From 7ee4bc5caed80e41fb4789330e5fc88ae22cb206 Mon Sep 17 00:00:00 2001
From: Holger Nahrstaedt <holgernahrstaedt@gmx.de>
Date: Mon, 7 Sep 2020 12:46:35 +0200
Subject: [PATCH] Fix broadcasting amounts that have a higher precision than
 allowed

* Use floor instead of round in beembase/Amount in order to handle floats which have a higher precision than allowed
* json_str parameter has been added to beembase.Amount, when True, a json dict is returned as string (needing when broadcasting with use_condenser=False)
---
 CHANGELOG.rst                  |   2 +
 beem/account.py                |   5 +
 beem/blockchaininstance.py     |  22 +++--
 beem/market.py                 |   2 +
 beem/witness.py                |   1 +
 beembase/objects.py            |  13 +--
 beembase/operations.py         |  68 ++++++++-----
 tests/beem/test_amount.py      |   2 +-
 tests/beem/test_hive.py        | 171 ++++++++++++++++++++++++---------
 tests/beem/test_steem.py       | 155 +++++++++++++++++++++---------
 tests/beembase/test_objects.py |  15 +++
 11 files changed, 326 insertions(+), 130 deletions(-)

diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 83458809..bd1f06d7 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -8,6 +8,8 @@ Changelog
 * import keyring only when needed
 * Add use_condenser to config (can be set wtih beempy set), when set to False, condenser calls are not used
 * Add set_expiration to Object Cache
+* Use floor instead of round in beembase/Amount in order to handle floats which have a higher precision than allowed
+* json_str parameter has been added to beembase.Amount, when True, a json dict is returned as string (needing when broadcasting with use_condenser=False)
 
 0.24.8
 ------
diff --git a/beem/account.py b/beem/account.py
index 5a6915a7..ec9a9985 100644
--- a/beem/account.py
+++ b/beem/account.py
@@ -2791,6 +2791,7 @@ class Account(BlockchainObject):
             "memo": memo,
             "from": account["name"],
             "prefix": self.blockchain.prefix,
+            "json_str": not bool(self.blockchain.config["use_condenser"]),
             "replace_hive_by_steem": replace_hive_by_steem,
         })
         return self.blockchain.finalizeOp(op, account, "active", **kwargs)
@@ -2820,6 +2821,7 @@ class Account(BlockchainObject):
             "to": to["name"],
             "amount": amount,
             "prefix": self.blockchain.prefix,
+            "json_str": not bool(self.blockchain.config["use_condenser"]),
             "replace_hive_by_steem": replace_hive_by_steem,
         })
         return self.blockchain.finalizeOp(op, account, "active", **kwargs)
@@ -2850,6 +2852,7 @@ class Account(BlockchainObject):
                 "requestid": request_id,
                 "amount": amount,
                 "prefix": self.blockchain.prefix,
+                "json_str": not bool(self.blockchain.config["use_condenser"]),
                 "replace_hive_by_steem": replace_hive_by_steem,
             })
 
@@ -2888,6 +2891,7 @@ class Account(BlockchainObject):
                 "amount": amount,
                 "memo": memo,
                 "prefix": self.blockchain.prefix,
+                "json_str": not bool(self.blockchain.config["use_condenser"]),
                 "replace_hive_by_steem": replace_hive_by_steem,
             })
         return self.blockchain.finalizeOp(op, account, "active", **kwargs)
@@ -2939,6 +2943,7 @@ class Account(BlockchainObject):
                 "amount": amount,
                 "memo": memo,
                 "prefix": self.blockchain.prefix,
+                "json_str": not bool(self.blockchain.config["use_condenser"]),
                 "replace_hive_by_steem": replace_hive_by_steem,
             })
         return self.blockchain.finalizeOp(op, account, "active", **kwargs)
diff --git a/beem/blockchaininstance.py b/beem/blockchaininstance.py
index 9750bef7..176edbdb 100644
--- a/beem/blockchaininstance.py
+++ b/beem/blockchaininstance.py
@@ -769,22 +769,24 @@ class BlockChainInstance(object):
 
     @property
     def is_hive(self):
-        config = self.get_config()
+        config = self.get_config(use_stored_data=True)
         if config is None:
             return False
-        return 'HIVE_CHAIN_ID' in self.get_config()
+        return 'HIVE_CHAIN_ID' in config
 
     @property
     def is_steem(self):
-        config = self.get_config()
+        config = self.get_config(use_stored_data=True)
         if config is None:
             return False
-        return 'STEEM_CHAIN_ID' in self.get_config()
+        return 'STEEM_CHAIN_ID' in config
 
     def get_replace_hive_by_steem(self):
-        hf_version = int(self.get_blockchain_version().split('.')[1])
+        if not self.is_hive:
+            return False
+        hf_version = int(self.get_blockchain_version(use_stored_data=True).split('.')[1])
         replace_hive_by_steem = True
-        if self.is_hive and hf_version >= 24:
+        if hf_version >= 24:
             replace_hive_by_steem = False
         return replace_hive_by_steem
 
@@ -1072,6 +1074,7 @@ class BlockChainInstance(object):
             "fee": Amount(fee, blockchain_instance=self),
             "creator": creator["name"],
             "prefix": self.prefix,
+            "json_str": not bool(self.config["use_condenser"]),
             "replace_hive_by_steem": replace_hive_by_steem,
         }
         op = operations.Claim_account(**op)
@@ -1252,6 +1255,7 @@ class BlockChainInstance(object):
                 "fee": Amount(fee, blockchain_instance=self),
                 "creator": creator["name"],
                 "prefix": self.prefix,
+                "json_str": not bool(self.config["use_condenser"]),
                 "replace_hive_by_steem": replace_hive_by_steem,
             }
             op = operations.Claim_account(**op)
@@ -1470,6 +1474,7 @@ class BlockChainInstance(object):
             'memo_key': memo,
             "json_metadata": json_meta or {},
             "prefix": self.prefix,
+            "json_str": not bool(self.config["use_condenser"]),
             "replace_hive_by_steem": replace_hive_by_steem,
         }
         op = operations.Account_create(**op)
@@ -1680,7 +1685,9 @@ class BlockChainInstance(object):
         for k in props:
             props_list.append([k, props[k]])
         replace_hive_by_steem = self.get_replace_hive_by_steem()
-        op = operations.Witness_set_properties({"owner": owner["name"], "props": props_list, "prefix": self.prefix, "replace_hive_by_steem": replace_hive_by_steem})
+        op = operations.Witness_set_properties({"owner": owner["name"], "props": props_list, "prefix": self.prefix,
+                                                "json_str": not bool(self.config["use_condenser"]),
+                                                "replace_hive_by_steem": replace_hive_by_steem})
         tb = TransactionBuilder(blockchain_instance=self)
         tb.appendOps([op])
         tb.appendWif(wif)
@@ -1726,6 +1733,7 @@ class BlockChainInstance(object):
                 "props": props,
                 "fee": Amount(0, self.token_symbol, blockchain_instance=self),
                 "prefix": self.prefix,
+                "json_str": not bool(self.config["use_condenser"]),
                 "replace_hive_by_steem": replace_hive_by_steem,
             })
         return self.finalizeOp(op, account, "active", **kwargs)
diff --git a/beem/market.py b/beem/market.py
index 94635b7e..281ef6f6 100644
--- a/beem/market.py
+++ b/beem/market.py
@@ -607,6 +607,7 @@ class Market(dict):
             "expiration": formatTimeFromNow(expiration),
             "fill_or_kill": killfill,
             "prefix": self.blockchain.prefix,
+            "json_str": not bool(self.blockchain.config["use_condenser"]),
             "replace_hive_by_steem": replace_hive_by_steem,
         })
 
@@ -692,6 +693,7 @@ class Market(dict):
             "expiration": formatTimeFromNow(expiration),
             "fill_or_kill": killfill,
             "prefix": self.blockchain.prefix,
+            "json_str": not bool(self.blockchain.config["use_condenser"]),
             "replace_hive_by_steem": replace_hive_by_steem,
         })
         if returnOrderId:
diff --git a/beem/witness.py b/beem/witness.py
index f78ea981..5c25f883 100644
--- a/beem/witness.py
+++ b/beem/witness.py
@@ -167,6 +167,7 @@ class Witness(BlockchainObject):
                     "quote": quote,
                 },
                 "prefix": self.blockchain.prefix,
+                "json_str": not bool(self.blockchain.config["use_condenser"]),
                 "replace_hive_by_steem": replace_hive_by_steem,
             })
         return self.blockchain.finalizeOp(op, account, "active")
diff --git a/beembase/objects.py b/beembase/objects.py
index 7e4cbd4a..8dd1416c 100644
--- a/beembase/objects.py
+++ b/beembase/objects.py
@@ -6,6 +6,7 @@ from builtins import bytes, int, str
 from builtins import object
 from future.utils import python_2_unicode_compatible
 import json
+from math import floor
 from beemgraphenebase.py23 import py23_bytes, bytes_types, integer_types, string_types, text_type
 from collections import OrderedDict
 from beemgraphenebase.types import (
@@ -26,8 +27,9 @@ default_prefix = "STM"
 
 
 class Amount(object):
-    def __init__(self, d, prefix=default_prefix, replace_hive_by_steem=True):
+    def __init__(self, d, prefix=default_prefix, replace_hive_by_steem=True, json_str=False):
         self.replace_hive_by_steem = replace_hive_by_steem
+        self.json_str = json_str
         if isinstance(d, string_types):
             self.amount, self.symbol = d.strip().split(" ")
             self.precision = None
@@ -47,7 +49,7 @@ class Amount(object):
                         self.asset = asset["asset"]
             if self.precision is None:
                 raise Exception("Asset unknown")
-            self.amount = round(float(self.amount) * 10 ** self.precision)
+            self.amount = floor(float(self.amount) * 10 ** self.precision)
             # Workaround to allow transfers in HIVE
 
             if self.symbol == "HBD" and replace_hive_by_steem:
@@ -94,7 +96,7 @@ class Amount(object):
                 self.symbol = "STEEM"              
             self.asset = d.asset["asset"]
             self.precision = d.asset["precision"]
-            self.amount = round(float(self.amount) * 10 ** self.precision)
+            self.amount = floor(float(self.amount) * 10 ** self.precision)
             self.str_repr = str(d)
             # self.str_repr = json.dumps((d.json()))
             # self.str_repr = '{:.{}f} {}'.format((float(self.amount) / 10 ** self.precision), self.precision, self.asset)
@@ -111,7 +113,8 @@ class Amount(object):
                 py23_bytes(symbol, "ascii"))
 
     def __str__(self):
-        # return json.dumps({"amount": self.amount, "precision": self.precision, "nai": self.asset})
+        if self.json_str:
+            return json.dumps({"amount": str(self.amount), "precision": self.precision, "nai": self.asset})
         return self.str_repr
 
 
@@ -127,8 +130,6 @@ class Operation(GPHOperation):
         return class_
 
     def operations(self):
-        if self.prefix == "WLS":
-            return operations_wls
         return operations
 
     def getOperationNameForId(self, i):
diff --git a/beembase/operations.py b/beembase/operations.py
index a14b7b23..c83d1965 100644
--- a/beembase/operations.py
+++ b/beembase/operations.py
@@ -52,6 +52,7 @@ class Transfer(GrapheneObject):
             kwargs = args[0]
         prefix = kwargs.get("prefix", default_prefix)
         replace_hive_by_steem = kwargs.get("replace_hive_by_steem", True)
+        json_str = kwargs.get("json_str", False)
         if "memo" not in kwargs:
             kwargs["memo"] = ""
         if isinstance(kwargs["memo"], dict):
@@ -65,7 +66,7 @@ class Transfer(GrapheneObject):
         super(Transfer, self).__init__(OrderedDict([
             ('from', String(kwargs["from"])),
             ('to', String(kwargs["to"])),
-            ('amount', Amount(kwargs["amount"], prefix=prefix, replace_hive_by_steem=replace_hive_by_steem)),
+            ('amount', Amount(kwargs["amount"], prefix=prefix, replace_hive_by_steem=replace_hive_by_steem, json_str=json_str)),
             ('memo', memo),
         ]))
 
@@ -92,10 +93,11 @@ class Transfer_to_vesting(GrapheneObject):
             kwargs = args[0]
         prefix = kwargs.get("prefix", default_prefix)
         replace_hive_by_steem = kwargs.get("replace_hive_by_steem", True)
+        json_str = kwargs.get("json_str", False)
         super(Transfer_to_vesting, self).__init__(OrderedDict([
             ('from', String(kwargs["from"])),
             ('to', String(kwargs["to"])),
-            ('amount', Amount(kwargs["amount"], prefix=prefix, replace_hive_by_steem=replace_hive_by_steem)),
+            ('amount', Amount(kwargs["amount"], prefix=prefix, replace_hive_by_steem=replace_hive_by_steem, json_str=json_str)),
         ]))
 
 
@@ -184,6 +186,7 @@ class Account_create(GrapheneObject):
             kwargs = args[0]
         prefix = kwargs.get("prefix", default_prefix)
         replace_hive_by_steem = kwargs.get("replace_hive_by_steem", True)
+        json_str = kwargs.get("json_str", False)
         if not len(kwargs["new_account_name"]) <= 16:
             raise AssertionError("Account name must be at most 16 chars long")
 
@@ -195,7 +198,7 @@ class Account_create(GrapheneObject):
                 meta = kwargs["json_metadata"]
 
         super(Account_create, self).__init__(OrderedDict([
-            ('fee', Amount(kwargs["fee"], prefix=prefix, replace_hive_by_steem=replace_hive_by_steem)),
+            ('fee', Amount(kwargs["fee"], prefix=prefix, replace_hive_by_steem=replace_hive_by_steem, json_str=json_str)),
             ('creator', String(kwargs["creator"])),
             ('new_account_name', String(kwargs["new_account_name"])),
             ('owner', Permission(kwargs["owner"], prefix=prefix)),
@@ -215,6 +218,7 @@ class Account_create_with_delegation(GrapheneObject):
             kwargs = args[0]
         prefix = kwargs.get("prefix", default_prefix)
         replace_hive_by_steem = kwargs.get("replace_hive_by_steem", True)
+        json_str = kwargs.get("json_str", False)
         if not len(kwargs["new_account_name"]) <= 16:
             raise AssertionError("Account name must be at most 16 chars long")
 
@@ -226,8 +230,8 @@ class Account_create_with_delegation(GrapheneObject):
                 meta = kwargs["json_metadata"]
 
         super(Account_create_with_delegation, self).__init__(OrderedDict([
-            ('fee', Amount(kwargs["fee"], prefix=prefix, replace_hive_by_steem=replace_hive_by_steem)),
-            ('delegation', Amount(kwargs["delegation"], prefix=prefix, replace_hive_by_steem=replace_hive_by_steem)),
+            ('fee', Amount(kwargs["fee"], prefix=prefix, replace_hive_by_steem=replace_hive_by_steem, json_str=json_str)),
+            ('delegation', Amount(kwargs["delegation"], prefix=prefix, replace_hive_by_steem=replace_hive_by_steem, json_str=json_str)),
             ('creator', String(kwargs["creator"])),
             ('new_account_name', String(kwargs["new_account_name"])),
             ('owner', Permission(kwargs["owner"], prefix=prefix)),
@@ -342,6 +346,7 @@ class Create_proposal(GrapheneObject):
             kwargs = args[0]
         prefix = kwargs.get("prefix", default_prefix)
         replace_hive_by_steem = kwargs.get("replace_hive_by_steem", True)
+        json_str = kwargs.get("json_str", False)
         extensions = Array([])
 
         super(Create_proposal, self).__init__(
@@ -350,7 +355,7 @@ class Create_proposal(GrapheneObject):
                 ('receiver', String(kwargs["receiver"])),
                 ('start_date', PointInTime(kwargs["start_date"])),
                 ('end_date', PointInTime(kwargs["end_date"])),
-                ('daily_pay', Amount(kwargs["daily_pay"], prefix=prefix, replace_hive_by_steem=replace_hive_by_steem)),
+                ('daily_pay', Amount(kwargs["daily_pay"], prefix=prefix, replace_hive_by_steem=replace_hive_by_steem, json_str=json_str)),
                 ('subject', String(kwargs["subject"])),
                 ('permlink', String(kwargs["permlink"])),
                 ('extensions', extensions)
@@ -424,6 +429,7 @@ class Witness_set_properties(GrapheneObject):
             kwargs = args[0]
         prefix = kwargs.pop("prefix", default_prefix)
         replace_hive_by_steem = kwargs.get("replace_hive_by_steem", True)
+        json_str = kwargs.get("json_str", False)
         extensions = Array([])
         props = {}
         for k in kwargs["props"]:
@@ -449,9 +455,9 @@ class Witness_set_properties(GrapheneObject):
             elif isinstance(k[1], int) and k[0] in ["hbd_interest_rate"]:
                 props[k[0]] = (hexlify(Uint16(k[1]).__bytes__())).decode()            
             elif not isinstance(k[1], str) and k[0] in ["account_creation_fee"]:
-                props[k[0]] = (hexlify(Amount(k[1], prefix=prefix, replace_hive_by_steem=replace_hive_by_steem).__bytes__())).decode()
+                props[k[0]] = (hexlify(Amount(k[1], prefix=prefix, replace_hive_by_steem=replace_hive_by_steem, json_str=json_str).__bytes__())).decode()
             elif not is_hex and isinstance(k[1], str) and k[0] in ["account_creation_fee"]:
-                props[k[0]] = (hexlify(Amount(k[1], prefix=prefix, replace_hive_by_steem=replace_hive_by_steem).__bytes__())).decode()
+                props[k[0]] = (hexlify(Amount(k[1], prefix=prefix, replace_hive_by_steem=replace_hive_by_steem, json_str=json_str).__bytes__())).decode()
             elif not isinstance(k[1], str) and k[0] in ["sbd_exchange_rate"]:
                 if 'prefix' not in k[1]:
                     k[1]['prefix'] = prefix
@@ -493,6 +499,7 @@ class Witness_update(GrapheneObject):
             kwargs = args[0]
         prefix = kwargs.pop("prefix", default_prefix)
         replace_hive_by_steem = kwargs.pop("replace_hive_by_steem", True)
+        json_str = kwargs.get("json_str", False)
         if "block_signing_key" in kwargs and kwargs["block_signing_key"]:
             block_signing_key = (PublicKey(kwargs["block_signing_key"], prefix=prefix))
         else:
@@ -508,7 +515,7 @@ class Witness_update(GrapheneObject):
             ('url', String(kwargs["url"])),
             ('block_signing_key', block_signing_key),
             ('props', WitnessProps(kwargs["props"])),
-            ('fee', Amount(kwargs["fee"], prefix=prefix, replace_hive_by_steem=replace_hive_by_steem)),
+            ('fee', Amount(kwargs["fee"], prefix=prefix, replace_hive_by_steem=replace_hive_by_steem, json_str=json_str)),
         ]))
 
 
@@ -573,6 +580,7 @@ class Comment_options(GrapheneObject):
             kwargs = args[0]
         prefix = kwargs.get("prefix", default_prefix)
         replace_hive_by_steem = kwargs.get("replace_hive_by_steem", True)
+        json_str = kwargs.get("json_str", False)
         # handle beneficiaries
         if "beneficiaries" in kwargs and kwargs['beneficiaries']:
             kwargs['extensions'] = [[0, {'beneficiaries': kwargs['beneficiaries']}]]
@@ -585,7 +593,7 @@ class Comment_options(GrapheneObject):
                     ('author', String(kwargs["author"])),
                     ('permlink', String(kwargs["permlink"])),
                     ('max_accepted_payout',
-                     Amount(kwargs["max_accepted_payout"], prefix=prefix, replace_hive_by_steem=replace_hive_by_steem)),
+                     Amount(kwargs["max_accepted_payout"], prefix=prefix, replace_hive_by_steem=replace_hive_by_steem, json_str=json_str)),
                     ('percent_steem_dollars',
                      Uint16(int(kwargs["percent_steem_dollars"]))),
                     ('allow_votes', Bool(bool(kwargs["allow_votes"]))),
@@ -630,6 +638,7 @@ class Feed_publish(GrapheneObject):
             kwargs = args[0]
         prefix = kwargs.get("prefix", default_prefix)
         replace_hive_by_steem = kwargs.get("replace_hive_by_steem", True)
+        json_str = kwargs.get("json_str", False)
         if 'prefix' not in kwargs['exchange_rate']:
             kwargs['exchange_rate']['prefix'] = prefix
         if 'replace_hive_by_steem' not in kwargs['exchange_rate']:
@@ -649,11 +658,12 @@ class Convert(GrapheneObject):
             kwargs = args[0]
         prefix = kwargs.get("prefix", default_prefix)
         replace_hive_by_steem = kwargs.get("replace_hive_by_steem", True)
+        json_str = kwargs.get("json_str", False)
         super(Convert, self).__init__(
             OrderedDict([
                 ('owner', String(kwargs["owner"])),
                 ('requestid', Uint32(kwargs["requestid"])),
-                ('amount', Amount(kwargs["amount"], prefix=prefix, replace_hive_by_steem=replace_hive_by_steem)),
+                ('amount', Amount(kwargs["amount"], prefix=prefix, replace_hive_by_steem=replace_hive_by_steem, json_str=json_str)),
             ]))
 
 
@@ -693,10 +703,11 @@ class Claim_account(GrapheneObject):
             kwargs = args[0]
         prefix = kwargs.get("prefix", default_prefix)
         replace_hive_by_steem = kwargs.get("replace_hive_by_steem", True)
+        json_str = kwargs.get("json_str", False)
         super(Claim_account, self).__init__(
             OrderedDict([
                 ('creator', String(kwargs["creator"])),
-                ('fee', Amount(kwargs["fee"], prefix=prefix, replace_hive_by_steem=replace_hive_by_steem)),
+                ('fee', Amount(kwargs["fee"], prefix=prefix, replace_hive_by_steem=replace_hive_by_steem, json_str=json_str)),
                 ('extensions', Array([])),
             ]))
 
@@ -755,12 +766,13 @@ class Limit_order_create(GrapheneObject):
             kwargs = args[0]
         prefix = kwargs.get("prefix", default_prefix)
         replace_hive_by_steem = kwargs.get("replace_hive_by_steem", True)
+        json_str = kwargs.get("json_str", False)
         super(Limit_order_create, self).__init__(
             OrderedDict([
                 ('owner', String(kwargs["owner"])),
                 ('orderid', Uint32(kwargs["orderid"])),
-                ('amount_to_sell', Amount(kwargs["amount_to_sell"], prefix=prefix, replace_hive_by_steem=replace_hive_by_steem)),
-                ('min_to_receive', Amount(kwargs["min_to_receive"], prefix=prefix, replace_hive_by_steem=replace_hive_by_steem)),
+                ('amount_to_sell', Amount(kwargs["amount_to_sell"], prefix=prefix, replace_hive_by_steem=replace_hive_by_steem, json_str=json_str)),
+                ('min_to_receive', Amount(kwargs["min_to_receive"], prefix=prefix, replace_hive_by_steem=replace_hive_by_steem, json_str=json_str)),
                 ('fill_or_kill', Bool(kwargs["fill_or_kill"])),
                 ('expiration', PointInTime(kwargs["expiration"])),
             ]))
@@ -774,6 +786,7 @@ class Limit_order_create2(GrapheneObject):
             kwargs = args[0]
         prefix = kwargs.get("prefix", default_prefix)
         replace_hive_by_steem = kwargs.get("replace_hive_by_steem", True)
+        json_str = kwargs.get("json_str", False)
         if 'prefix' not in kwargs['exchange_rate']:
             kwargs['exchange_rate']['prefix'] = prefix
         if 'replace_hive_by_steem' not in kwargs['exchange_rate']:
@@ -782,7 +795,7 @@ class Limit_order_create2(GrapheneObject):
             OrderedDict([
                 ('owner', String(kwargs["owner"])),
                 ('orderid', Uint32(kwargs["orderid"])),
-                ('amount_to_sell', Amount(kwargs["amount_to_sell"], prefix=prefix, replace_hive_by_steem=replace_hive_by_steem)),
+                ('amount_to_sell', Amount(kwargs["amount_to_sell"], prefix=prefix, replace_hive_by_steem=replace_hive_by_steem, json_str=json_str)),
                 ('fill_or_kill', Bool(kwargs["fill_or_kill"])),
                 ('exchange_rate', ExchangeRate(kwargs["exchange_rate"])),
                 ('expiration', PointInTime(kwargs["expiration"])),
@@ -811,6 +824,7 @@ class Transfer_from_savings(GrapheneObject):
             kwargs = args[0]
         prefix = kwargs.get("prefix", default_prefix)
         replace_hive_by_steem = kwargs.get("replace_hive_by_steem", True)
+        json_str = kwargs.get("json_str", False)
         if "memo" not in kwargs:
             kwargs["memo"] = ""
 
@@ -819,7 +833,7 @@ class Transfer_from_savings(GrapheneObject):
                 ('from', String(kwargs["from"])),
                 ('request_id', Uint32(kwargs["request_id"])),
                 ('to', String(kwargs["to"])),
-                ('amount', Amount(kwargs["amount"], prefix=prefix, replace_hive_by_steem=replace_hive_by_steem)),
+                ('amount', Amount(kwargs["amount"], prefix=prefix, replace_hive_by_steem=replace_hive_by_steem, json_str=json_str)),
                 ('memo', String(kwargs["memo"])),
             ]))
 
@@ -845,12 +859,13 @@ class Claim_reward_balance(GrapheneObject):
             kwargs = args[0]
         prefix = kwargs.get("prefix", default_prefix)
         replace_hive_by_steem = kwargs.get("replace_hive_by_steem", True)
+        json_str = kwargs.get("json_str", False)
         if "reward_sbd" in kwargs and "reward_steem" in kwargs:
             super(Claim_reward_balance, self).__init__(
                 OrderedDict([
                     ('account', String(kwargs["account"])),
-                    ('reward_steem', Amount(kwargs["reward_steem"], prefix=prefix, replace_hive_by_steem=replace_hive_by_steem)),
-                    ('reward_sbd', Amount(kwargs["reward_sbd"], prefix=prefix, replace_hive_by_steem=replace_hive_by_steem)),
+                    ('reward_steem', Amount(kwargs["reward_steem"], prefix=prefix, replace_hive_by_steem=replace_hive_by_steem, json_str=json_str)),
+                    ('reward_sbd', Amount(kwargs["reward_sbd"], prefix=prefix, replace_hive_by_steem=replace_hive_by_steem, json_str=json_str)),
                     ('reward_vests', Amount(kwargs["reward_vests"], prefix=prefix)),
                 ]))
         elif "reward_hbd" in kwargs and "reward_hive" in kwargs:
@@ -865,7 +880,7 @@ class Claim_reward_balance(GrapheneObject):
             super(Claim_reward_balance, self).__init__(
                 OrderedDict([
                     ('account', String(kwargs["account"])),
-                    ('reward_steem', Amount(kwargs["reward_steem"], prefix=prefix, replace_hive_by_steem=replace_hive_by_steem)),
+                    ('reward_steem', Amount(kwargs["reward_steem"], prefix=prefix, replace_hive_by_steem=replace_hive_by_steem, json_str=json_str)),
                     ('reward_vests', Amount(kwargs["reward_vests"], prefix=prefix)),
                 ]))
         else:
@@ -885,13 +900,14 @@ class Transfer_to_savings(GrapheneObject):
             kwargs = args[0]
         prefix = kwargs.get("prefix", default_prefix)
         replace_hive_by_steem = kwargs.get("replace_hive_by_steem", True)
+        json_str = kwargs.get("json_str", False)
         if "memo" not in kwargs:
             kwargs["memo"] = ""
         super(Transfer_to_savings, self).__init__(
             OrderedDict([
                 ('from', String(kwargs["from"])),
                 ('to', String(kwargs["to"])),
-                ('amount', Amount(kwargs["amount"], prefix=prefix, replace_hive_by_steem=replace_hive_by_steem)),
+                ('amount', Amount(kwargs["amount"], prefix=prefix, replace_hive_by_steem=replace_hive_by_steem, json_str=json_str)),
                 ('memo', String(kwargs["memo"])),
             ]))
 
@@ -939,6 +955,7 @@ class Escrow_transfer(GrapheneObject):
             kwargs = args[0]
         prefix = kwargs.get("prefix", default_prefix)
         replace_hive_by_steem = kwargs.get("replace_hive_by_steem", True)
+        json_str = kwargs.get("json_str", False)
         meta = ""
         if "json_meta" in kwargs and kwargs["json_meta"]:
             if (isinstance(kwargs["json_meta"], dict) or isinstance(kwargs["json_meta"], list)):
@@ -952,9 +969,9 @@ class Escrow_transfer(GrapheneObject):
                     ('to', String(kwargs["to"])),
                     ('agent', String(kwargs["agent"])),
                     ('escrow_id', Uint32(kwargs["escrow_id"])),
-                    ('sbd_amount', Amount(kwargs["sbd_amount"], prefix=prefix, replace_hive_by_steem=replace_hive_by_steem)),
-                    ('steem_amount', Amount(kwargs["steem_amount"], prefix=prefix, replace_hive_by_steem=replace_hive_by_steem)),
-                    ('fee', Amount(kwargs["fee"], prefix=prefix, replace_hive_by_steem=replace_hive_by_steem)),
+                    ('sbd_amount', Amount(kwargs["sbd_amount"], prefix=prefix, replace_hive_by_steem=replace_hive_by_steem, json_str=json_str)),
+                    ('steem_amount', Amount(kwargs["steem_amount"], prefix=prefix, replace_hive_by_steem=replace_hive_by_steem, json_str=json_str)),
+                    ('fee', Amount(kwargs["fee"], prefix=prefix, replace_hive_by_steem=replace_hive_by_steem, json_str=json_str)),
                     ('ratification_deadline', PointInTime(kwargs["ratification_deadline"])),
                     ('escrow_expiration', PointInTime(kwargs["escrow_expiration"])),
                     ('json_meta', String(meta)),
@@ -998,6 +1015,7 @@ class Escrow_release(GrapheneObject):
             kwargs = args[0]
         prefix = kwargs.get("prefix", default_prefix)
         replace_hive_by_steem = kwargs.get("replace_hive_by_steem", True)
+        json_str = kwargs.get("json_str", False)
         if "steem_amount" in kwargs and "sbd_amount" in kwargs:
             super(Escrow_release, self).__init__(
                 OrderedDict([
@@ -1005,8 +1023,8 @@ class Escrow_release(GrapheneObject):
                     ('to', String(kwargs["to"])),
                     ('who', String(kwargs["who"])),
                     ('escrow_id', Uint32(kwargs["escrow_id"])),
-                    ('sbd_amount', Amount(kwargs["sbd_amount"], prefix=prefix, replace_hive_by_steem=replace_hive_by_steem)),
-                    ('steem_amount', Amount(kwargs["steem_amount"], prefix=prefix, replace_hive_by_steem=replace_hive_by_steem)),
+                    ('sbd_amount', Amount(kwargs["sbd_amount"], prefix=prefix, replace_hive_by_steem=replace_hive_by_steem, json_str=json_str)),
+                    ('steem_amount', Amount(kwargs["steem_amount"], prefix=prefix, replace_hive_by_steem=replace_hive_by_steem, json_str=json_str)),
                 ]))
         else:
             super(Escrow_release, self).__init__(
diff --git a/tests/beem/test_amount.py b/tests/beem/test_amount.py
index 233d0814..a64d8687 100644
--- a/tests/beem/test_amount.py
+++ b/tests/beem/test_amount.py
@@ -78,7 +78,7 @@ class Testcases(unittest.TestCase):
         self.dotest(amount, 1.3001, symbol)        
 
         amount = Amount(amount=1.3001, asset=Asset("SBD", steem_instance=stm), fixed_point_arithmetic=True, steem_instance=stm)
-        self.dotest(amount, 1.3, symbol)   
+        self.dotest(amount, 1.3, symbol)
 
         # keyword inits
         amount = Amount(amount=1.3, asset=dict(Asset("SBD", steem_instance=stm)), steem_instance=stm)
diff --git a/tests/beem/test_hive.py b/tests/beem/test_hive.py
index 35922886..79521d86 100644
--- a/tests/beem/test_hive.py
+++ b/tests/beem/test_hive.py
@@ -10,7 +10,7 @@ from parameterized import parameterized
 import random
 import json
 from pprint import pprint
-from beem import Hive, exceptions
+from beem import Hive, exceptions, Steem
 from beem.amount import Amount
 from beem.version import version as beem_version
 from beem.account import Account
@@ -45,12 +45,20 @@ class Testcases(unittest.TestCase):
         acc.blockchain.txbuffer.clear()
         tx = acc.transfer(
             "test", 1.33, acc.blockchain.backed_token_symbol, memo="Foobar", account="test1")
-        self.assertEqual(
-            tx["operations"][0][0],
-            "transfer"
-        )
         self.assertEqual(len(tx["operations"]), 1)
-        op = tx["operations"][0][1]
+        if isinstance(tx["operations"][0], list):
+            self.assertEqual(
+                tx["operations"][0][0],
+                "transfer"
+            )
+            op = tx["operations"][0][1]
+        else:
+            self.assertEqual(
+                tx["operations"][0]["type"],
+                "transfer_operation"
+            )
+            
+            op = tx["operations"][0]["value"]
         self.assertIn("memo", op)
         self.assertEqual(op["memo"], "Foobar")
         self.assertEqual(op["from"], "test1")
@@ -88,11 +96,18 @@ class Testcases(unittest.TestCase):
             additional_posting_accounts=["test3"],
             storekeys=False,
         )
-        self.assertEqual(
-            tx["operations"][0][0],
-            "account_create"
-        )
-        op = tx["operations"][0][1]
+        if isinstance(tx["operations"][0], list):
+            self.assertEqual(
+                tx["operations"][0][0],
+                "account_create"
+            )
+            op = tx["operations"][0][1]
+        else:
+            self.assertEqual(
+                tx["operations"][0]["type"],
+                "account_create_operation"
+            )
+            op = tx["operations"][0]["value"]         
         role = "active"
         self.assertIn(
             format(key5.pubkey, core_unit),
@@ -149,11 +164,18 @@ class Testcases(unittest.TestCase):
             additional_active_accounts=["test1"],
             storekeys=False,
         )
-        self.assertEqual(
-            tx["operations"][0][0],
-            "account_create"
-        )
-        op = tx["operations"][0][1]
+        if isinstance(tx["operations"][0], list):
+            self.assertEqual(
+                tx["operations"][0][0],
+                "account_create"
+            )
+            op = tx["operations"][0][1]
+        else:
+            self.assertEqual(
+                tx["operations"][0]["type"],
+                "account_create_operation"
+            )
+            op = tx["operations"][0]["value"]        
         role = "active"
         self.assertIn(
             format(key5.pubkey, core_unit),
@@ -247,11 +269,19 @@ class Testcases(unittest.TestCase):
             threshold=1,
             permission="owner",
         )
-        self.assertEqual(
-            (tx["operations"][0][0]),
-            "account_update"
-        )
-        op = tx["operations"][0][1]
+        if isinstance(tx["operations"][0], list):
+            
+            self.assertEqual(
+                (tx["operations"][0][0]),
+                "account_update"
+            )
+            op = tx["operations"][0][1]
+        else:
+            self.assertEqual(
+                (tx["operations"][0]["type"]),
+                "account_update_operation"
+            )
+            op = tx["operations"][0]["value"]            
         self.assertIn("owner", op)
         self.assertIn(
             [wif, '1'],
@@ -288,11 +318,19 @@ class Testcases(unittest.TestCase):
         self.assertEqual(acc.blockchain.prefix, prefix)
         acc.blockchain.txbuffer.clear()
         tx = acc.update_memo_key(pkey)
-        self.assertEqual(
-            (tx["operations"][0][0]),
-            "account_update"
-        )
-        op = tx["operations"][0][1]
+        if isinstance(tx["operations"][0], list):
+            self.assertEqual(
+                (tx["operations"][0][0]),
+                "account_update"
+            )
+            op = tx["operations"][0][1]
+        else:
+            self.assertEqual(
+                (tx["operations"][0]["type"]),
+                "account_update_operation"
+            )
+            op = tx["operations"][0]["value"]
+            
         self.assertEqual(
             op["memo_key"],
             pkey)
@@ -301,11 +339,18 @@ class Testcases(unittest.TestCase):
         w = self.account
         w.blockchain.txbuffer.clear()
         tx = w.approvewitness("test1")
-        self.assertEqual(
-            (tx["operations"][0][0]),
-            "account_witness_vote"
-        )
-        op = tx["operations"][0][1]
+        if isinstance(tx["operations"][0], list):
+            self.assertEqual(
+                (tx["operations"][0][0]),
+                "account_witness_vote"
+            )
+            op = tx["operations"][0][1]
+        else:
+            self.assertEqual(
+                (tx["operations"][0]["type"]),
+                "account_witness_vote_operation"
+            )
+            op = tx["operations"][0]["value"]            
         self.assertIn(
             "test1",
             op["witness"])
@@ -316,11 +361,18 @@ class Testcases(unittest.TestCase):
         tx = bts.post("title", "body", author="test", permlink=None, reply_identifier=None,
                       json_metadata=None, comment_options=None, community="test", tags=["a", "b", "c", "d", "e"],
                       beneficiaries=[{'account': 'test1', 'weight': 5000}, {'account': 'test2', 'weight': 5000}], self_vote=True)
-        self.assertEqual(
-            (tx["operations"][0][0]),
-            "comment"
-        )
-        op = tx["operations"][0][1]
+        if isinstance(tx["operations"][0], list):
+            self.assertEqual(
+                (tx["operations"][0][0]),
+                "comment"
+            )
+            op = tx["operations"][0][1]
+        else:
+            self.assertEqual(
+                (tx["operations"][0]["type"]),
+                "comment_operation"
+            )
+            op = tx["operations"][0]["value"]            
         self.assertEqual(op["body"], "body")
         self.assertEqual(op["title"], "title")
         self.assertTrue(op["permlink"].startswith("title"))
@@ -329,22 +381,38 @@ class Testcases(unittest.TestCase):
         json_metadata = json.loads(op["json_metadata"])
         self.assertEqual(json_metadata["tags"], ["a", "b", "c", "d", "e"])
         self.assertEqual(json_metadata["app"], "beem/%s" % (beem_version))
-        self.assertEqual(
-            (tx["operations"][1][0]),
-            "comment_options"
-        )
-        op = tx["operations"][1][1]
+        if isinstance(tx["operations"][1], list):
+            self.assertEqual(
+                (tx["operations"][1][0]),
+                "comment_options"
+            )
+            op = tx["operations"][1][1]
+        else:
+                
+            self.assertEqual(
+                (tx["operations"][1]["type"]),
+                "comment_options_operation"
+            )
+            op = tx["operations"][1]["value"]
         self.assertEqual(len(op['extensions'][0][1]['beneficiaries']), 2)
 
     def test_comment_option(self):
         bts = self.bts
         bts.txbuffer.clear()
         tx = bts.comment_options({}, "@gtg/witness-gtg-log", account="test")
-        self.assertEqual(
-            (tx["operations"][0][0]),
-            "comment_options"
-        )
-        op = tx["operations"][0][1]
+        if isinstance(tx["operations"][0], list):
+            self.assertEqual(
+                (tx["operations"][0][0]),
+                "comment_options"
+            )
+            op = tx["operations"][0][1]
+        else:
+            self.assertEqual(
+                (tx["operations"][0]["type"]),
+                "comment_options_operation"
+            )
+            op = tx["operations"][0]["value"]
+            
         self.assertIn(
             "gtg",
             op["author"])
@@ -466,3 +534,14 @@ class Testcases(unittest.TestCase):
         assert not bts.is_hive
         bts.switch_blockchain("hive", update_nodes=True)
         assert bts.is_hive        
+
+    def test_switch_blockchain(self):
+        bts = self.bts
+        nodes_hive = self.nodelist.get_hive_nodes()
+        nodes_steem = self.nodelist.get_steem_nodes()
+        rpc = Steem(nodes_steem)
+        assert rpc.is_steem
+        assert not rpc.get_replace_hive_by_steem()
+        rpc = Hive(nodes_hive)
+        assert rpc.is_hive
+        assert rpc.get_replace_hive_by_steem()
diff --git a/tests/beem/test_steem.py b/tests/beem/test_steem.py
index 8a730260..b563ea59 100644
--- a/tests/beem/test_steem.py
+++ b/tests/beem/test_steem.py
@@ -44,12 +44,21 @@ class Testcases(unittest.TestCase):
         acc.blockchain.txbuffer.clear()
         tx = acc.transfer(
             "test", 1.33, acc.blockchain.sbd_symbol, memo="Foobar", account="test1")
-        self.assertEqual(
-            tx["operations"][0][0],
-            "transfer"
-        )
         self.assertEqual(len(tx["operations"]), 1)
-        op = tx["operations"][0][1]
+        if isinstance(tx["operations"][0], list):
+            self.assertEqual(
+                tx["operations"][0][0],
+                "transfer"
+            )
+            
+            op = tx["operations"][0][1]
+        else:
+            self.assertEqual(
+                tx["operations"][0]["type"],
+                "transfer_operation"
+            )
+            
+            op = tx["operations"][0]["value"]          
         self.assertIn("memo", op)
         self.assertEqual(op["memo"], "Foobar")
         self.assertEqual(op["from"], "test1")
@@ -87,11 +96,18 @@ class Testcases(unittest.TestCase):
             additional_posting_accounts=["test3"],
             storekeys=False,
         )
-        self.assertEqual(
-            tx["operations"][0][0],
-            "account_create"
-        )
-        op = tx["operations"][0][1]
+        if isinstance(tx["operations"][0], list):
+            self.assertEqual(
+                tx["operations"][0][0],
+                "account_create"
+            )
+            op = tx["operations"][0][1]
+        else:
+            self.assertEqual(
+                tx["operations"][0]["type"],
+                "account_create_operation"
+            )
+            op = tx["operations"][0]["value"]            
         role = "active"
         self.assertIn(
             format(key5.pubkey, core_unit),
@@ -148,11 +164,18 @@ class Testcases(unittest.TestCase):
             additional_active_accounts=["test1"],
             storekeys=False,
         )
-        self.assertEqual(
-            tx["operations"][0][0],
-            "account_create"
-        )
-        op = tx["operations"][0][1]
+        if isinstance(tx["operations"][0], list):
+            self.assertEqual(
+                tx["operations"][0][0],
+                "account_create"
+            )
+            op = tx["operations"][0][1]
+        else:
+            self.assertEqual(
+                tx["operations"][0]["type"],
+                "account_create_operation"
+            )
+            op = tx["operations"][0]["value"]            
         role = "active"
         self.assertIn(
             format(key5.pubkey, core_unit),
@@ -246,11 +269,18 @@ class Testcases(unittest.TestCase):
             threshold=1,
             permission="owner",
         )
-        self.assertEqual(
-            (tx["operations"][0][0]),
-            "account_update"
-        )
-        op = tx["operations"][0][1]
+        if isinstance(tx["operations"][0], list):
+            self.assertEqual(
+                (tx["operations"][0][0]),
+                "account_update"
+            )
+            op = tx["operations"][0][1]
+        else:
+            self.assertEqual(
+                (tx["operations"][0]["type"]),
+                "account_update_operation"
+            )
+            op = tx["operations"][0]["value"]            
         self.assertIn("owner", op)
         self.assertIn(
             [wif, '1'],
@@ -287,11 +317,18 @@ class Testcases(unittest.TestCase):
         self.assertEqual(acc.blockchain.prefix, prefix)
         acc.blockchain.txbuffer.clear()
         tx = acc.update_memo_key(pkey)
-        self.assertEqual(
-            (tx["operations"][0][0]),
-            "account_update"
-        )
-        op = tx["operations"][0][1]
+        if isinstance(tx["operations"][0], list):
+            self.assertEqual(
+                (tx["operations"][0][0]),
+                "account_update"
+            )
+            op = tx["operations"][0][1]
+        else:
+            self.assertEqual(
+                (tx["operations"][0]["type"]),
+                "account_update_operation"
+            )
+            op = tx["operations"][0]["value"]            
         self.assertEqual(
             op["memo_key"],
             pkey)
@@ -300,11 +337,18 @@ class Testcases(unittest.TestCase):
         w = self.account
         w.blockchain.txbuffer.clear()
         tx = w.approvewitness("test1")
-        self.assertEqual(
-            (tx["operations"][0][0]),
-            "account_witness_vote"
-        )
-        op = tx["operations"][0][1]
+        if isinstance(tx["operations"][0], list):
+            self.assertEqual(
+                (tx["operations"][0][0]),
+                "account_witness_vote"
+            )
+            op = tx["operations"][0][1]
+        else:
+            self.assertEqual(
+                (tx["operations"][0]["type"]),
+                "account_witness_vote_operation"
+            )
+            op = tx["operations"][0]["value"]            
         self.assertIn(
             "test1",
             op["witness"])
@@ -315,11 +359,18 @@ class Testcases(unittest.TestCase):
         tx = bts.post("title", "body", author="test", permlink=None, reply_identifier=None,
                       json_metadata=None, comment_options=None, community="test", tags=["a", "b", "c", "d", "e"],
                       beneficiaries=[{'account': 'test1', 'weight': 5000}, {'account': 'test2', 'weight': 5000}], self_vote=True)
-        self.assertEqual(
-            (tx["operations"][0][0]),
-            "comment"
-        )
-        op = tx["operations"][0][1]
+        if isinstance(tx["operations"][0], list):
+            self.assertEqual(
+                (tx["operations"][0][0]),
+                "comment"
+            )
+            op = tx["operations"][0][1]
+        else:
+            self.assertEqual(
+                (tx["operations"][0]["type"]),
+                "comment_operation"
+            )
+            op = tx["operations"][0]["value"]            
         self.assertEqual(op["body"], "body")
         self.assertEqual(op["title"], "title")
         self.assertTrue(op["permlink"].startswith("title"))
@@ -328,22 +379,36 @@ class Testcases(unittest.TestCase):
         json_metadata = json.loads(op["json_metadata"])
         self.assertEqual(json_metadata["tags"], ["a", "b", "c", "d", "e"])
         self.assertEqual(json_metadata["app"], "beem/%s" % (beem_version))
-        self.assertEqual(
-            (tx["operations"][1][0]),
-            "comment_options"
-        )
-        op = tx["operations"][1][1]
+        if isinstance(tx["operations"][1], list):
+            self.assertEqual(
+                (tx["operations"][1][0]),
+                "comment_options"
+            )
+            op = tx["operations"][1][1]
+        else:
+            self.assertEqual(
+                (tx["operations"][1]["type"]),
+                "comment_options_operation"
+            )
+            op = tx["operations"][1]["value"]            
         self.assertEqual(len(op['extensions'][0][1]['beneficiaries']), 2)
 
     def test_comment_option(self):
         bts = self.bts
         bts.txbuffer.clear()
         tx = bts.comment_options({}, "@gtg/witness-gtg-log", account="test")
-        self.assertEqual(
-            (tx["operations"][0][0]),
-            "comment_options"
-        )
-        op = tx["operations"][0][1]
+        if isinstance(tx["operations"][0], list):
+            self.assertEqual(
+                (tx["operations"][0][0]),
+                "comment_options"
+            )
+            op = tx["operations"][0][1]
+        else:
+            self.assertEqual(
+                (tx["operations"][0]["type"]),
+                "comment_options_operation"
+            )
+            op = tx["operations"][0]["value"]            
         self.assertIn(
             "gtg",
             op["author"])
diff --git a/tests/beembase/test_objects.py b/tests/beembase/test_objects.py
index 30776289..de11091a 100644
--- a/tests/beembase/test_objects.py
+++ b/tests/beembase/test_objects.py
@@ -25,11 +25,26 @@ class Testcases(unittest.TestCase):
         self.assertEqual(a, t.__str__())
         self.assertEqual(a, str(t))
 
+        t = Amount(a, json_str=True, prefix="STM")
+        self.assertEqual({"amount": "1000", "precision": 3, "nai": "@@000000021"}, json.loads(str(t)))        
+
         a = {"amount": "3000", "precision": 3, "nai": "@@000000037"}
         t = Amount(a, prefix="STM")
         # self.assertEqual(str(a), t.__str__())
         self.assertEqual(a, json.loads(str(t)))
 
+
+
+    def test_Amount_overflow(self):
+        a = "0.9999 STEEM"
+        t = Amount(a)
+        self.assertEqual("0.999 STEEM", t.__str__())
+        self.assertEqual("0.999 STEEM", str(t))
+        a = "0.9991 STEEM"
+        t = Amount(a)
+        self.assertEqual("0.999 STEEM", t.__str__())
+        self.assertEqual("0.999 STEEM", str(t))
+
     def test_Operation(self):
         a = {"amount": '1000', "precision": 3, "nai": '@@000000013'}
         j = ["transfer", {'from': 'a', 'to': 'b', 'amount': a, 'memo': 'c'}]
-- 
GitLab