diff --git a/.gitignore b/.gitignore index 41fdc26bd8069dfd2202ed579a0a82ca7ed4bfcb..a1a561f9ffe9595438d628c454aba357562045fb 100644 --- a/.gitignore +++ b/.gitignore @@ -65,3 +65,6 @@ target/ *.swp .ropeproject/ */.ropeproject/ + +# IDEs +.vscode diff --git a/CHANGELOG.rst b/CHANGELOG.rst index e591fbac93fc53c315d05fe434f4cd1da3d8f0be..13fac615622438adf702ab0752ddefe908324927 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,5 +1,27 @@ Changelog ======== +0.24.27 +------- +* Adapt changes of HF25 to operationids + +0.24.26 +------- +* reverting change to operationsid + +0.24.25 +------- +* More robust HIVE_CHAIN_ID detection + +0.24.24 +------- +* Prioritize HIVE_CHAIN_ID property for the chain selection (@emre) + +0.24.23 +------- +* Fixed some small code issues +* Added reccurring_transfer op in preparation for HF25 (@sicarius) +* Added collateralized_convert op in preparation for HF25 (@sicarius) + 0.24.22 ------- * Fix to parameter in transfer_to_vesting diff --git a/beem/account.py b/beem/account.py index fe30b5d34ce139fbe052535e2f765322a1729160..2e5451ceca6f80e36ea6031a1361f72785824af8 100644 --- a/beem/account.py +++ b/beem/account.py @@ -2914,6 +2914,69 @@ class Account(BlockchainObject): }) return self.blockchain.finalizeOp(op, account, "active", **kwargs) + #------------------------------------------------------------------------------- + # Recurring Transfer added in hf25 + #------------------------------------------------------------------------------- + def recurring_transfer(self, to, amount, asset, recurrence, executions, memo="", skip_account_check=False, account=None, **kwargs): + """ Transfer an asset to another account. + + :param str to: Recipient + :param float amount: Amount to transfer in each occurence, must have 3 decimal points + :param str asset: Asset to transfer + :param int recurrence: How often in hours to execute transfer + :param int executions: Number of times to recur before stopping execution + :param str memo: (optional) Memo, may begin with `#` for encrypted + messaging + :param bool skip_account_check: (optional) When True, the receiver + account name is not checked to speed up sending multiple transfers in a row + :param str account: (optional) the source account for the transfer + if not ``default_account`` + + + Transfer example: + + .. code-block:: python + + from beem.account import Account + from beem import Hive + active_wif = "5xxxx" + stm = Hive(keys=[active_wif]) + acc = Account("test", blockchain_instance=stm) + acc.transfer("test1", 1, "HIVE", 48, 5, "test") + + """ + + if account is None: + account = self + elif not skip_account_check: + account = Account(account, blockchain_instance=self.blockchain) + amount = Amount(amount, asset, blockchain_instance=self.blockchain) + if not skip_account_check: + to = Account(to, blockchain_instance=self.blockchain) + + to_name = extract_account_name(to) + account_name = extract_account_name(account) + if memo and memo[0] == "#": + from .memo import Memo + memoObj = Memo( + from_account=account, + to_account=to, + blockchain_instance=self.blockchain + ) + memo = memoObj.encrypt(memo[1:])["message"] + + op = operations.Recurring_transfer(**{ + "amount": amount, + "to": to_name, + "memo": memo, + "from": account_name, + "recurrence": recurrence, + "executions": executions, + "prefix": self.blockchain.prefix, + "json_str": not bool(self.blockchain.config["use_condenser"]), + }) + return self.blockchain.finalizeOp(op, account, "active", **kwargs) + def transfer_to_vesting(self, amount, to=None, account=None, skip_account_check=False, **kwargs): """ Vest STEEM @@ -2977,6 +3040,38 @@ class Account(BlockchainObject): return self.blockchain.finalizeOp(op, account, "active") + #Added to differentiate and match the addition of the HF25 convert operation + def collateralized_convert(self, amount, account=None, request_id=None, **kwargs): + """ Convert Hive dollars to Hive (this method is meant to be more instant) + and reflect the method added in HF25 + + :param float amount: amount of SBD to convert + :param str account: (optional) the source account for the transfer + if not ``default_account`` + :param str request_id: (optional) identifier for tracking the + conversion` + + """ + if account is None: + account = self + else: + account = Account(account, blockchain_instance=self.blockchain) + amount = self._check_amount(amount, self.blockchain.backed_token_symbol) + if request_id: + request_id = int(request_id) + else: + request_id = random.getrandbits(32) + op = operations.Collateralized_convert( + **{ + "owner": account["name"], + "requestid": request_id, + "amount": amount, + "prefix": self.blockchain.prefix, + "json_str": not bool(self.blockchain.config["use_condenser"]), + }) + + return self.blockchain.finalizeOp(op, account, "active", **kwargs) + def transfer_to_savings(self, amount, asset, memo, to=None, account=None, **kwargs): """ Transfer SBD or STEEM into a 'savings' account. diff --git a/beem/cli.py b/beem/cli.py index cf81d07578df2bfb9590dbf32734ed5bb9a79357..3bf57a8a9ffa7aadf60c40971978e0e36576b427 100644 --- a/beem/cli.py +++ b/beem/cli.py @@ -9,7 +9,7 @@ import calendar import pytz import time import hashlib -import math +#import math currently unused module import random import logging import click diff --git a/beem/transactionbuilder.py b/beem/transactionbuilder.py index ca76a1b31b8a9dbb7ae724d389eb81f6ef2d5c39..b6ceb846c723fb1b506e472f1252f24ea616164b 100644 --- a/beem/transactionbuilder.py +++ b/beem/transactionbuilder.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- import logging import struct -import time +#import time (not currently used) from datetime import timedelta from binascii import unhexlify from beemgraphenebase.py23 import bytes_types, integer_types, string_types, text_type @@ -11,7 +11,7 @@ from beembase.objects import Operation from beemgraphenebase.account import PrivateKey, PublicKey from beembase.signedtransactions import Signed_Transaction from beembase.ledgertransactions import Ledger_Transaction -from beembase import transactions, operations +from beembase import operations #removed deprecated transactions module from .exceptions import ( InsufficientAuthorityError, MissingKeyError, diff --git a/beem/version.py b/beem/version.py index 38ac4019e947d66e5d7d00661f135ef1bb5a66fe..373ee2c4703ecdbf3e4488835a358ce257d7463a 100644 --- a/beem/version.py +++ b/beem/version.py @@ -1,2 +1,2 @@ """THIS FILE IS GENERATED FROM beem SETUP.PY.""" -version = '0.24.22' +version = '0.24.27' diff --git a/beemapi/graphenerpc.py b/beemapi/graphenerpc.py index 48f1f56f4d8bbbe83b897732b8298a86d00d3a0d..96d69cd069201967db23cb87056addbcf1b716ab 100644 --- a/beemapi/graphenerpc.py +++ b/beemapi/graphenerpc.py @@ -304,13 +304,35 @@ class GrapheneRPC(object): prefix = None symbols = [] chain_assets = [] + + prefix_count = {} + for key in props: + if key.split("_")[0] in prefix_count: + prefix_count[key.split("_")[0]] += 1 + else: + prefix_count[key.split("_")[0]] = 1 + if len(prefix_count) > 0: + sorted_prefix_count = sorted(prefix_count.items(), key=lambda x: x[1], reverse=True) + if sorted_prefix_count[0][1] > 1: + blockchain_name = sorted_prefix_count[0][0] + if blockchain_name is None and 'HIVE_CHAIN_ID' in props and 'STEEM_CHAIN_ID' in props: + del props['STEEM_CHAIN_ID'] + + for key in props: - if key[-8:] == "CHAIN_ID": + + if key[-8:] == "CHAIN_ID" and blockchain_name is None: chain_id = props[key] blockchain_name = key.split("_")[0] - elif key[-13:] == "CHAIN_VERSION": + elif key[-8:] == "CHAIN_ID" and key.split("_")[0] == blockchain_name: + chain_id = props[key] + elif key[-13:] == "CHAIN_VERSION" and blockchain_name is None: network_version = props[key] - elif key[-14:] == "ADDRESS_PREFIX": + elif key[-13:] == "CHAIN_VERSION" and key.split("_")[0] == blockchain_name: + network_version = props[key] + elif key[-14:] == "ADDRESS_PREFIX" and blockchain_name is None: + prefix = props[key] + elif key[-14:] == "ADDRESS_PREFIX" and key.split("_")[0] == blockchain_name: prefix = props[key] elif key[-6:] == "SYMBOL": value = {} diff --git a/beemapi/version.py b/beemapi/version.py index 38ac4019e947d66e5d7d00661f135ef1bb5a66fe..373ee2c4703ecdbf3e4488835a358ce257d7463a 100644 --- a/beemapi/version.py +++ b/beemapi/version.py @@ -1,2 +1,2 @@ """THIS FILE IS GENERATED FROM beem SETUP.PY.""" -version = '0.24.22' +version = '0.24.27' diff --git a/beembase/operationids.py b/beembase/operationids.py index 6b3d023c21c385aafb1d41030f6a495548c425d2..6ac8106b6d20cd7f6839b29cde9dabbbebe7c506 100644 --- a/beembase/operationids.py +++ b/beembase/operationids.py @@ -1,81 +1,96 @@ # -*- coding: utf-8 -*- #: Operation ids + +# https://gitlab.syncad.com/hive/hive/-/blob/master/libraries/protocol/include/hive/protocol/operations.hpp ops = [ - 'vote', - 'comment', - 'transfer', - 'transfer_to_vesting', - 'withdraw_vesting', - 'limit_order_create', - 'limit_order_cancel', - 'feed_publish', - 'convert', - 'account_create', - 'account_update', - 'witness_update', - 'account_witness_vote', - 'account_witness_proxy', - 'pow', - 'custom', - 'report_over_production', - 'delete_comment', - 'custom_json', - 'comment_options', - 'set_withdraw_vesting_route', - 'limit_order_create2', - 'claim_account', - 'create_claimed_account', - 'request_account_recovery', - 'recover_account', - 'change_recovery_account', - 'escrow_transfer', - 'escrow_dispute', - 'escrow_release', - 'pow2', - 'escrow_approve', - 'transfer_to_savings', - 'transfer_from_savings', - 'cancel_transfer_from_savings', - 'custom_binary', - 'decline_voting_rights', - 'reset_account', - 'set_reset_account', - 'claim_reward_balance', - 'delegate_vesting_shares', - 'account_create_with_delegation', - 'witness_set_properties', - 'account_update2', - 'create_proposal', - 'update_proposal_votes', - 'remove_proposal', - 'update_proposal', - 'fill_convert_request', - 'author_reward', - 'curation_reward', - 'comment_reward', - 'liquidity_reward', - 'producer_reward', - 'interest', - 'fill_vesting_withdraw', - 'fill_order', - 'shutdown_witness', - 'fill_transfer_from_savings', - 'hardfork', - 'comment_payout_update', - 'return_vesting_delegation', - 'comment_benefactor_reward', - 'producer_reward', - 'clear_null_account_balance', - 'proposal_pay', - 'sps_fund', - 'hardfork_hive', - 'hardfork_hive_restore', - 'delayed_voting', - 'consolidate_treasury_balance', - 'effective_comment_vote', - 'ineffective_delete_comment', - 'sps_convert' + 'vote', #0 + 'comment', #1 + 'transfer', #2 + 'transfer_to_vesting', #3 + 'withdraw_vesting', #4 + 'limit_order_create', #5 + 'limit_order_cancel', #6 + 'feed_publish', #7 + 'convert', #8 + 'account_create', #9 + 'account_update', #10 + 'witness_update', #11 + 'account_witness_vote', #12 + 'account_witness_proxy', #13 + 'pow', #14 + 'custom', #15 + 'report_over_production', #16 + 'delete_comment', #17 + 'custom_json', #18 + 'comment_options', #19 + 'set_withdraw_vesting_route', #20 + 'limit_order_create2', #21 + 'claim_account', #22 + 'create_claimed_account', #23 + 'request_account_recovery', #24 + 'recover_account', #25 + 'change_recovery_account', #26 + 'escrow_transfer', #27 + 'escrow_dispute', #28 + 'escrow_release', #29 + 'pow2', #30 + 'escrow_approve', #31 + 'transfer_to_savings', #32 + 'transfer_from_savings', #33 + 'cancel_transfer_from_savings', #34 + 'custom_binary', #35 + 'decline_voting_rights', #36 + 'reset_account', #37 + 'set_reset_account', #38 + 'claim_reward_balance', #39 + 'delegate_vesting_shares', #40 + 'account_create_with_delegation', #41 + 'witness_set_properties', #42 + 'account_update2', #43 + 'create_proposal', #44 + 'update_proposal_votes', #45 + 'remove_proposal', #46 + 'update_proposal', #47 + 'collateralized_convert', #48 + 'recurrent_transfer', #49 + # virtual operations below this point + 'fill_convert_request', #last_regular + 1 + 'author_reward', #last_regular + 2 + 'curation_reward', #last_regular + 3 + 'comment_reward', #last_regular + 4 + 'liquidity_reward', #last_regular + 5 + 'interest', #last_regular + 6 + 'fill_vesting_withdraw', #last_regular + 7 + 'fill_order', #last_regular + 8 + 'shutdown_witness', #last_regular + 9 + 'fill_transfer_from_savings', #last_regular + 10 + 'hardfork', #last_regular + 11 + 'comment_payout_update', #last_regular + 12 + 'return_vesting_delegation', #last_regular + 13 + 'comment_benefactor_reward', #last_regular + 14 + 'producer_reward', #last_regular + 15 + 'clear_null_account_balance', #last_regular + 16 + 'proposal_pay', #last_regular + 17 + 'sps_fund', #last_regular + 18 + 'hardfork_hive', #last_regular + 19 + 'hardfork_hive_restore', #last_regular + 20 + 'delayed_voting', #last_regular + 21 + 'consolidate_treasury_balance', #last_regular + 22 + 'effective_comment_vote', #last_regular + 23 + 'ineffective_delete_comment', #last_regular + 24 + 'sps_convert', #last_regular + 25 + 'expired_account_notification', #last_regular + 26 + 'changed_recovery_account', #last_regular + 27 + 'transfer_to_vesting_completed', #last_regular + 28 + 'pow_reward', #last_regular + 29 + 'vesting_shares_split', #last_regular + 30 + 'account_created', #last_regular + 31 + 'fill_collateralized_convert_request', #last_regular + 32 + 'system_warning', #last_regular + 33, + 'fill_recurrent_transfer', #last_regular + 34 + 'failed_recurrent_transfer' # last_regular + 35 ] + operations = {o: ops.index(o) for o in ops} diff --git a/beembase/operations.py b/beembase/operations.py index 126024a93a997c8a6507d02ad81e2284d1dec18c..25c1fca45d91211045f520773ab813faacd8d768 100644 --- a/beembase/operations.py +++ b/beembase/operations.py @@ -66,6 +66,35 @@ class Transfer(GrapheneObject): ('memo', memo), ])) +#Added recurring transfer support for HF25 +class Recurring_transfer(GrapheneObject): + def __init__(self, *args, **kwargs): + # Allow for overwrite of prefix + if check_for_class(self, args): + return + if len(args) == 1 and len(kwargs) == 0: + kwargs = args[0] + prefix = kwargs.get("prefix", default_prefix) + json_str = kwargs.get("json_str", False) + if "memo" not in kwargs: + kwargs["memo"] = "" + if isinstance(kwargs["memo"], dict): + kwargs["memo"]["prefix"] = prefix + memo = Optional(Memo(**kwargs["memo"])) + elif isinstance(kwargs["memo"], string_types): + memo = (String(kwargs["memo"])) + else: + memo = Optional(Memo(kwargs["memo"])) + + super(Recurring_transfer, self).__init__(OrderedDict([ + ('from', String(kwargs["from"])), + ('to', String(kwargs["to"])), + ('amount', Amount(kwargs["amount"], prefix=prefix, json_str=json_str)), + ('memo', memo), + ('recurrence', Int16(kwargs["recurrence"])), + ('executions', Int16(kwargs["executions"])), + ])) + class Vote(GrapheneObject): def __init__(self, *args, **kwargs): @@ -642,6 +671,24 @@ class Convert(GrapheneObject): ('amount', Amount(kwargs["amount"], prefix=prefix, json_str=json_str)), ])) +#Operation added for HF25 for the new HBD/Hive conversion operation +class Collateralized_convert(GrapheneObject): + def __init__(self, *args, **kwargs): + if check_for_class(self, args): + return + if len(args) == 1 and len(kwargs) == 0: + kwargs = args[0] + prefix = kwargs.get("prefix", default_prefix) + json_str = kwargs.get("json_str", False) + super(Collateralized_convert, self).__init__( + OrderedDict([ + ('owner', String(kwargs["owner"])), + ('requestid', Uint32(kwargs["requestid"])), + ('amount', Amount(kwargs["amount"], prefix=prefix, json_str=json_str)), + + ])) + + class Set_withdraw_vesting_route(GrapheneObject): def __init__(self, *args, **kwargs): diff --git a/beembase/version.py b/beembase/version.py index 38ac4019e947d66e5d7d00661f135ef1bb5a66fe..373ee2c4703ecdbf3e4488835a358ce257d7463a 100644 --- a/beembase/version.py +++ b/beembase/version.py @@ -1,2 +1,2 @@ """THIS FILE IS GENERATED FROM beem SETUP.PY.""" -version = '0.24.22' +version = '0.24.27' diff --git a/beemgraphenebase/version.py b/beemgraphenebase/version.py index 38ac4019e947d66e5d7d00661f135ef1bb5a66fe..373ee2c4703ecdbf3e4488835a358ce257d7463a 100644 --- a/beemgraphenebase/version.py +++ b/beemgraphenebase/version.py @@ -1,2 +1,2 @@ """THIS FILE IS GENERATED FROM beem SETUP.PY.""" -version = '0.24.22' +version = '0.24.27'