From 1e50760d722f91b06e9ea61d73136a0cd71473ed Mon Sep 17 00:00:00 2001 From: Holger Nahrstaedt <holger@nahrstaedt.de> Date: Thu, 15 Feb 2018 15:36:20 +0100 Subject: [PATCH] Asset and Amount fixed for steem --- steem/account.py | 30 ++- steem/asset.py | 498 ++------------------------------------- steem/block.py | 12 +- steem/steem.py | 2 +- steem/wallet.py | 4 +- steemapi/steemnoderpc.py | 6 +- tests/test_amount.py | 14 +- tests/test_asset.py | 16 +- 8 files changed, 56 insertions(+), 526 deletions(-) diff --git a/steem/account.py b/steem/account.py index 6bf35d3d..a03c1155 100644 --- a/steem/account.py +++ b/steem/account.py @@ -2,6 +2,7 @@ from steem.instance import shared_steem_instance from .exceptions import AccountDoesNotExistsException from .blockchainobject import BlockchainObject +import json class Account(BlockchainObject): """ This class allows to easily access Account data @@ -24,7 +25,7 @@ class Account(BlockchainObject): .. code-block:: python from steem.account import Account - account = Account("init0") + account = Account("test") print(account) .. note:: This class comes with its own caching function to reduce the @@ -53,14 +54,10 @@ class Account(BlockchainObject): def refresh(self): """ Refresh/Obtain an account's data from the API server """ - import re - if re.match("^1\.2\.[0-9]*$", self.identifier): - account = self.steem.rpc.get_objects([self.identifier])[0] - else: - account = self.steem.rpc.lookup_account_names( - [self.identifier])[0] + account = self.steem.rpc.lookup_account_names( + [self.name])[0] if not account: - raise AccountDoesNotExistsException(self.identifier) + raise AccountDoesNotExistsException(self.name) self.identifier = account["id"] if self.full: @@ -73,15 +70,26 @@ class Account(BlockchainObject): else: super(Account, self).__init__(account) + def getSimilarAccountNames(self,limit=5): + """ Returns limit similar accounts with name as array + """ + return self.steem.rpc.lookup_accounts(self.name,limit) + @property def name(self): return self["name"] @property - def is_ltm(self): - """ Is the account a lifetime member (LTM)? + def profile(self): + """ Returns the account profile + """ + return json.loads(self["json_metadata"])["profile"] + + @property + def sp(self): + """ Returns the accounts Steem Power """ - return self["id"] == self["lifetime_referrer"] + vests = self["vesting_shares"] @property def balances(self): diff --git a/steem/asset.py b/steem/asset.py index 2c12ef9b..79b0ee41 100644 --- a/steem/asset.py +++ b/steem/asset.py @@ -42,39 +42,28 @@ class Asset(BlockchainObject): full=full, steem_instance=steem_instance ) + self.refresh() def refresh(self): """ Refresh the data from the API server """ - asset = self.steem.rpc.get_asset(self.identifier) - if not asset: + if self.identifier == "sbd_symbol" or self.identifier == self.steem.rpc.chain_params["sbd_symbol"] or self.identifier == 0: + self["asset"] = "sbd_symbol" + self["precision"] = 3 + self["id"] = 0 + self["symbol"] = self.steem.rpc.chain_params["sbd_symbol"] + elif self.identifier == "steem_symbol" or self.identifier == self.steem.rpc.chain_params["steem_symbol"] or self.identifier == 0: + self["asset"] = "steem_symbol" + self["precision"] = 3 + self["id"] = 1 + self["symbol"] = self.steem.rpc.chain_params["steem_symbol"] + elif self.identifier == "vests_symbol" or self.identifier == self.steem.rpc.chain_params["vests_symbol"] or self.identifier == 2: + self["asset"] = "vests_symbol" + self["precision"] = 6 + self["id"] = 2 + self["symbol"] = self.steem.rpc.chain_params["vests_symbol"] + else: raise AssetDoesNotExistsException(self.identifier) - super(Asset, self).__init__(asset, steem_instance=self.steem) - if self.full: - if "bitasset_data_id" in asset: - self["bitasset_data"] = self.steem.rpc.get_object( - asset["bitasset_data_id"]) - self["dynamic_asset_data"] = self.steem.rpc.get_object( - asset["dynamic_asset_data_id"]) - - # Permissions and flags - self["permissions"] = todict(asset["options"].get( - "issuer_permissions")) - self["flags"] = todict(asset["options"].get("flags")) - try: - self["description"] = json.loads(asset["options"]["description"]) - except: - self["description"] = asset["options"]["description"] - - @property - def is_fully_loaded(self): - """ Is this instance fully loaded / e.g. all data available? - """ - return ( - self.full and - "bitasset_data_id" in self and - "bitasset_data" in self - ) @property def symbol(self): @@ -83,456 +72,3 @@ class Asset(BlockchainObject): @property def precision(self): return self["precision"] - - @property - def is_bitasset(self): - """ Is the asset a :doc:`mpa`? - """ - return ("bitasset_data_id" in self) - - @property - def permissions(self): - """ List the permissions for this asset that the issuer can obtain - """ - return self["permissions"] - - @property - def flags(self): - """ List the permissions that are currently used (flags) - """ - return self["flags"] - - def ensure_full(self): - if not self.is_fully_loaded: - self.full = True - self.refresh() - - @property - def feeds(self): - from .price import PriceFeed - self.ensure_full() - if not self.is_bitasset: - return - r = [] - for feed in self["bitasset_data"]["feeds"]: - r.append(PriceFeed( - feed, - steem_instance=self.steem - )) - return r - - @property - def feed(self): - from .price import PriceFeed - assert self.is_bitasset - self.ensure_full() - return PriceFeed( - self["bitasset_data"]["current_feed"], - steem_instance=self.steem - ) - - @property - def calls(self): - return self.get_call_orders(10) - - def get_call_orders(self, limit=100): - from .price import Price - from .amount import Amount - assert limit <= 100 - assert self.is_bitasset - self.ensure_full() - r = list() - bitasset = self["bitasset_data"] - settlement_price = Price( - bitasset["current_feed"]["settlement_price"], - steem_instance=self.steem - ) - ret = self.steem.rpc.get_call_orders(self["id"], limit) - for call in ret[:limit]: - call_price = Price( - call["call_price"], - steem_instance=self.steem - ) - collateral_amount = Amount( - { - "amount": call["collateral"], - "asset_id": call["call_price"]["base"]["asset_id"] - }, - steem_instance=self.steem - ) - debt_amount = Amount( - { - "amount": call["debt"], - "asset_id": call["call_price"]["quote"]["asset_id"], - }, - steem_instance=self.steem - ) - r.append({ - "account": Account( - call["borrower"], - lazy=True, - steem_instance=self.steem - ), - "collateral": collateral_amount, - "debt": debt_amount, - "call_price": call_price, - "settlement_price": settlement_price, - "ratio": ( - float(collateral_amount) / - float(debt_amount) * - float(settlement_price) - ) - }) - return r - - @property - def settlements(self): - return self.get_settle_orders(10) - - def get_settle_orders(self, limit=100): - from .amount import Amount - from .utils import formatTimeString - assert limit <= 100 - assert self.is_bitasset - r = list() - ret = self.steem.rpc.get_settle_orders(self["id"], limit) - for settle in ret[:limit]: - r.append({ - "account": Account( - settle["owner"], - lazy=True, - steem_instance=self.steem - ), - "amount": Amount( - settle["balance"], - steem_instance=self.steem - ), - "date": formatTimeString(settle["settlement_date"]) - }) - return r - - def halt(self): - """ Halt this asset from being moved or traded - """ - nullaccount = Account( - "null-account", # We set the null-account - steem_instance=self.steem - ) - flags = {"white_list": True, - "transfer_restricted": True, - } - options = self["options"] - test_permissions(options["issuer_permissions"], flags) - flags_int = force_flag(options["flags"], flags) - options.update({ - "flags": flags_int, - "whitelist_authorities": [nullaccount["id"]], - "blacklist_authorities": [], - "whitelist_markets": [self["id"]], - "blacklist_markets": [], - }) - op = operations.Asset_update(**{ - "fee": {"amount": 0, - "asset_id": "1.3.0"}, - "issuer": self["issuer"], - "asset_to_update": self["id"], - "new_options": options, - "extensions": [] - }) - return self.steem.finalizeOp(op, self["issuer"], "active") - - def release( - self, - whitelist_authorities=[], - blacklist_authorities=[], - whitelist_markets=[], - blacklist_markets=[], - ): - """ Release this asset and allow unrestricted transfer, trading, - etc. - - :param list whitelist_authorities: List of accounts that - serve as whitelist authorities - :param list blacklist_authorities: List of accounts that - serve as blacklist authorities - :param list whitelist_markets: List of assets to allow - trading with - :param list blacklist_markets: List of assets to prevent - trading with - """ - flags = {"white_list": False, - "transfer_restricted": False, - } - options = self["options"] - test_permissions(options["issuer_permissions"], flags) - flags_int = force_flag(options["flags"], flags) - options.update({ - "flags": flags_int, - "whitelist_authorities": [ - Account(a)["id"] for a in whitelist_authorities - ], - "blacklist_authorities": [ - Account(a)["id"] for a in blacklist_authorities - ], - "whitelist_markets": [ - Asset(a)["id"] for a in whitelist_markets - ], - "blacklist_markets": [ - Asset(a)["id"] for a in blacklist_markets - ], - }) - op = operations.Asset_update(**{ - "fee": {"amount": 0, - "asset_id": "1.3.0"}, - "issuer": self["issuer"], - "asset_to_update": self["id"], - "new_options": options, - "extensions": [] - }) - return self.steem.finalizeOp(op, self["issuer"], "active") - - def setoptions(self, flags): - """ Enable a certain flag. - - Flags: - - * charge_market_fee - * white_list - * override_authority - * transfer_restricted - * disable_force_settle - * global_settle - * disable_confidential - * witness_fed_asset - * committee_fed_asset - - :param dict flag: dictionary of flags and boolean - """ - assert set(flags.keys()).issubset( - asset_permissions.keys()), "unknown flag" - - options = self["options"] - test_permissions(options["issuer_permissions"], flags) - flags_int = force_flag(options["flags"], flags) - options.update({"flags": flags_int}) - op = operations.Asset_update(**{ - "fee": {"amount": 0, "asset_id": "1.3.0"}, - "issuer": self["issuer"], - "asset_to_update": self["id"], - "new_options": options, - "extensions": [] - }) - return self.steem.finalizeOp(op, self["issuer"], "active") - - def enableflag(self, flag): - """ Enable a certain flag. - - :param str flag: Flag name - """ - return self.setoptions({flag: True}) - - def disableflag(self, flag): - """ Enable a certain flag. - - :param str flag: Flag name - """ - return self.setoptions({flag: False}) - - def seize(self, from_account, to_account, amount): - """ Seize amount from an account and send to another - - ... note:: This requires the ``override_authority`` to be - set for this asset! - - :param steem.account.Account from_account: From this account - :param steem.account.Account to_account: To this account - :param steem.amount.Amount amount: Amount to seize - """ - - options = self["options"] - if not (options["flags"] & asset_permissions["override_authority"]): - raise Exception("Insufficient Permissions/flags for seizure!") - - op = operations.Override_transfer(**{ - "fee": {"amount": 0, "asset_id": "1.3.0"}, - "issuer": self["issuer"], - "from": from_account["id"], - "to": to_account["id"], - "amount": amount.json(), - "extensions": [] - }) - return self.steem.finalizeOp(op, self["issuer"], "active") - - def add_authorities(self, type, authorities=[]): - """ Add authorities to an assets white/black list - - :param str type: ``blacklist`` or ``whitelist`` - :param list authorities: List of authorities (Accounts) - """ - assert type in ["blacklist", "whitelist"] - assert isinstance(authorities, (list, set)) - - options = self["options"] - if type == "whitelist": - options["whitelist_authorities"].extend([ - Account(a)["id"] for a in authorities - ]) - if type == "blacklist": - options["blacklist_authorities"].extend([ - Account(a)["id"] for a in authorities - ]) - op = operations.Asset_update(**{ - "fee": {"amount": 0, "asset_id": "1.3.0"}, - "issuer": self["issuer"], - "asset_to_update": self["id"], - "new_options": options, - "extensions": [] - }) - return self.steem.finalizeOp(op, self["issuer"], "active") - - def remove_authorities(self, type, authorities=[]): - """ Remove authorities from an assets white/black list - - :param str type: ``blacklist`` or ``whitelist`` - :param list authorities: List of authorities (Accounts) - """ - assert type in ["blacklist", "whitelist"] - assert isinstance(authorities, (list, set)) - - options = self["options"] - if type == "whitelist": - for a in authorities: - options["whitelist_authorities"].remove( - Account(a)["id"] - ) - if type == "blacklist": - for a in authorities: - options["blacklist_authorities"].remove( - Account(a)["id"] - ) - op = operations.Asset_update(**{ - "fee": {"amount": 0, "asset_id": "1.3.0"}, - "issuer": self["issuer"], - "asset_to_update": self["id"], - "new_options": options, - "extensions": [] - }) - return self.steem.finalizeOp(op, self["issuer"], "active") - - def add_markets(self, type, authorities=[], force_enable=True): - """ Add markets to an assets white/black list - - :param str type: ``blacklist`` or ``whitelist`` - :param list markets: List of markets (assets) - :param bool force_enable: Force enable ``white_list`` flag - """ - assert type in ["blacklist", "whitelist"] - assert isinstance(authorities, (list, set)) - - options = self["options"] - if force_enable: - test_permissions( - options["issuer_permissions"], - {"white_list": True} - ) - flags_int = force_flag( - options["flags"], - {"white_list": True} - ) - options.update({"flags": flags_int}) - else: - assert test_permissions( - options["flags"], - ["white_list"] - ), "whitelist feature not enabled" - - if type == "whitelist": - options["whitelist_markets"].extend([ - Asset(a)["id"] for a in authorities - ]) - if type == "blacklist": - options["blacklist_markets"].extend([ - Asset(a)["id"] for a in authorities - ]) - op = operations.Asset_update(**{ - "fee": {"amount": 0, "asset_id": "1.3.0"}, - "issuer": self["issuer"], - "asset_to_update": self["id"], - "new_options": options, - "extensions": [] - }) - return self.steem.finalizeOp(op, self["issuer"], "active") - - def remove_markets(self, type, authorities=[]): - """ Remove markets from an assets white/black list - - :param str type: ``blacklist`` or ``whitelist`` - :param list markets: List of markets (assets) - """ - assert type in ["blacklist", "whitelist"] - assert isinstance(authorities, (list, set)) - - options = self["options"] - if type == "whitelist": - for a in authorities: - options["whitelist_markets"].remove( - Asset(a)["id"] - ) - if type == "blacklist": - for a in authorities: - options["blacklist_markets"].remove( - Asset(a)["id"] - ) - op = operations.Asset_update(**{ - "fee": {"amount": 0, "asset_id": "1.3.0"}, - "issuer": self["issuer"], - "asset_to_update": self["id"], - "new_options": options, - "extensions": [] - }) - return self.steem.finalizeOp(op, self["issuer"], "active") - - def set_market_fee(self, percentage_fee, max_market_fee): - """ Set trading percentage fee - - :param float percentage_fee: Percentage of fee - :param steem.amount.Amount max_market_fee: Max Fee - - """ - assert percentage_fee <= 100 and percentage_fee > 0 - flags = {"charge_market_fee": percentage_fee > 0} - options = self["options"] - test_permissions(options["issuer_permissions"], flags) - flags_int = force_flag(options["flags"], flags) - options.update({ - "flags": flags_int, - "market_fee_percent": percentage_fee * 100, - "max_market_fee": int(max_market_fee), - }) - op = operations.Asset_update(**{ - "fee": {"amount": 0, "asset_id": "1.3.0"}, - "issuer": self["issuer"], - "asset_to_update": self["id"], - "new_options": options, - "extensions": [] - }) - return self.steem.finalizeOp(op, self["issuer"], "active") - - def update_feed_producers(self, producers): - """ Update bitasset feed producers - - :param list producers: List of accounts that are allowed to produce - a feed - """ - assert self.is_bitasset, \ - "Asset needs to be a bitasset/market pegged asset" - op = operations.Asset_update_feed_producers(**{ - "fee": {"amount": 0, "asset_id": "1.3.0"}, - "issuer": self["issuer"], - "asset_to_update": self["id"], - "new_feed_producers": [ - Account(a)["id"] for a in producers - ], - "extensions": [] - }) - return self.steem.finalizeOp(op, self["issuer"], "active") diff --git a/steem/block.py b/steem/block.py index 97c2b140..1be7bac3 100644 --- a/steem/block.py +++ b/steem/block.py @@ -7,7 +7,7 @@ class Block(BlockchainObject): """ Read a single block from the chain :param int block: block number - :param bitshares.bitshares.Steem bitshares_instance: Steem + :param steem.steem.Steem steem_instance: Steem instance :param bool lazy: Use lazy loading @@ -17,7 +17,7 @@ class Block(BlockchainObject): .. code-block:: python - from bitshares.block import Block + from steem.block import Block block = Block(1) print(block) @@ -30,10 +30,10 @@ class Block(BlockchainObject): """ Even though blocks never change, you freshly obtain its contents from an API with this method """ - block = self.bitshares.rpc.get_block(self.identifier) + block = self.steem.rpc.get_block(self.identifier) if not block: raise BlockDoesNotExistsException - super(Block, self).__init__(block, bitshares_instance=self.bitshares) + super(Block, self).__init__(block, steem_instance=self.steem) def time(self): """ Return a datatime instance for the timestamp of this block @@ -46,12 +46,12 @@ class BlockHeader(BlockchainObject): """ Even though blocks never change, you freshly obtain its contents from an API with this method """ - block = self.bitshares.rpc.get_block_header(self.identifier) + block = self.steem.rpc.get_block_header(self.identifier) if not block: raise BlockDoesNotExistsException super(BlockHeader, self).__init__( block, - bitshares_instance=self.bitshares + steem_instance=self.steem ) def time(self): diff --git a/steem/steem.py b/steem/steem.py index f82da5e3..a3cd601c 100644 --- a/steem/steem.py +++ b/steem/steem.py @@ -175,7 +175,7 @@ class Steem(object): @property def prefix(self): - return "STM"# self.rpc.chain_params["prefix"] + return self.rpc.chain_params["prefix"] def set_default_account(self, account): """ Set the default account to be used diff --git a/steem/wallet.py b/steem/wallet.py index b5f25623..ed2b731a 100644 --- a/steem/wallet.py +++ b/steem/wallet.py @@ -65,10 +65,10 @@ class Wallet(): # Prefix? if Wallet.rpc: - self.prefix = "STM"# Wallet.rpc.chain_params["prefix"] + self.prefix = Wallet.rpc.chain_params["prefix"] else: # If not connected, load prefix from config - self.prefix = "STM"# self.configStorage["prefix"] + self.prefix = self.configStorage["prefix"] # Compatibility after name change from wif->keys if "wif" in kwargs and "keys" not in kwargs: diff --git a/steemapi/steemnoderpc.py b/steemapi/steemnoderpc.py index cf815a8f..f8b1f768 100644 --- a/steemapi/steemnoderpc.py +++ b/steemapi/steemnoderpc.py @@ -21,7 +21,7 @@ class SteemNodeRPC(GrapheneWebsocketRPC): def __init__(self, *args, **kwargs): super(SteemNodeRPC, self).__init__(*args, **kwargs) - #self.chain_params = self.get_network() + self.chain_params = self.get_network() def register_apis(self): return @@ -85,8 +85,8 @@ class SteemNodeRPC(GrapheneWebsocketRPC): """ Identify the connected network. This call returns a dictionary with keys chain_id, core_symbol and prefix """ - props = self.get_chain_properties() - chain_id = props["chain_id"] + props = self.get_config() + chain_id = props["STEEMIT_CHAIN_ID"] for k, v in known_chains.items(): if v["chain_id"] == chain_id: return v diff --git a/tests/test_amount.py b/tests/test_amount.py index 597f7f44..f5029250 100644 --- a/tests/test_amount.py +++ b/tests/test_amount.py @@ -15,10 +15,10 @@ class Testcases(unittest.TestCase): nobroadcast=True, ) set_shared_steem_instance(self.bts) - self.asset = Asset("1.3.0") + self.asset = Asset("sbd_symbol") self.symbol = self.asset["symbol"] self.precision = self.asset["precision"] - self.asset2 = Asset("1.3.1") + self.asset2 = Asset("steem_symbol") def dotest(self, ret, amount, symbol): self.assertEqual(float(ret), float(amount)) @@ -50,7 +50,7 @@ class Testcases(unittest.TestCase): self.dotest(amount, 1.3, self.symbol) # Asset as symbol - amount = Amount(1.3, Asset("1.3.0")) + amount = Amount(1.3, Asset("sbd_symbol")) self.dotest(amount, 1.3, self.symbol) # Asset as symbol @@ -58,11 +58,11 @@ class Testcases(unittest.TestCase): self.dotest(amount, 1.3, self.symbol) # keyword inits - amount = Amount(amount=1.3, asset=Asset("1.3.0")) + amount = Amount(amount=1.3, asset=Asset("sbd_symbol")) self.dotest(amount, 1.3, self.symbol) # keyword inits - amount = Amount(amount=1.3, asset=dict(Asset("1.3.0"))) + amount = Amount(amount=1.3, asset=dict(Asset("sbd_symbol"))) self.dotest(amount, 1.3, self.symbol) # keyword inits @@ -98,12 +98,12 @@ class Testcases(unittest.TestCase): def test_string(self): self.assertEqual( str(Amount("1", self.symbol)), - "1.00000 {}".format(self.symbol)) + "1.000 {}".format(self.symbol)) def test_int(self): self.assertEqual( int(Amount("1", self.symbol)), - 100000) + 1000) def test_float(self): self.assertEqual( diff --git a/tests/test_asset.py b/tests/test_asset.py index 53224049..2328dc31 100644 --- a/tests/test_asset.py +++ b/tests/test_asset.py @@ -19,24 +19,10 @@ class Testcases(unittest.TestCase): with self.assertRaises(AssetDoesNotExistsException): Asset("FOObarNonExisting", full=False) - def test_refresh(self): - asset = Asset("1.3.0", full=False) - asset.ensure_full() - self.assertIn("dynamic_asset_data", asset) - self.assertIn("flags", asset) - self.assertIn("permissions", asset) - self.assertIsInstance(asset["flags"], dict) - self.assertIsInstance(asset["permissions"], dict) - def test_properties(self): - asset = Asset("1.3.0", full=False) + asset = Asset("sbd_symbol", full=False) self.assertIsInstance(asset.symbol, str) self.assertIsInstance(asset.precision, int) - self.assertIsInstance(asset.is_bitasset, bool) - self.assertIsInstance(asset.permissions, dict) - self.assertEqual(asset.permissions, asset["permissions"]) - self.assertIsInstance(asset.flags, dict) - self.assertEqual(asset.flags, asset["flags"]) """ # Mocker comes from pytest-mock, providing an easy way to have patched objects -- GitLab