def convert(self, amount, account=None, request_id=None): """ Convert SteemDollars to Steem (takes one week to settle) :param float amount: number of VESTS to withdraw :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 not account: account = configStorage.get("default_account") if not account: raise ValueError("You need to provide an account") if request_id: request_id = int(request_id) else: request_id = random.getrandbits(32) op = operations.Convert( **{ "owner": account, "requestid": request_id, "amount": '{:.{prec}f} {asset}'.format( float(amount), prec=3, asset='SBD') }) return self.finalizeOp(op, account, "active")
def set_withdraw_vesting_route(self, to, percentage=100, account=None, auto_vest=False): """ Set up a vesting withdraw route. When vesting shares are withdrawn, they will be routed to these accounts based on the specified weights. :param str to: Recipient of the vesting withdrawal :param float percentage: The percent of the withdraw to go to the 'to' account. :param str account: (optional) the vesting account :param bool auto_vest: Set to true if the from account should receive the VESTS as VESTS, or false if it should receive them as STEEM. (defaults to ``False``) """ if not account: account = configStorage.get("default_account") if not account: raise ValueError("You need to provide an account") op = operations.SetWithdrawVestingRoute( **{ "from_account": account, "to_account": to, "percent": int(percentage * STEEMIT_1_PERCENT), "auto_vest": auto_vest }) return self.finalizeOp(op, account, "active")
def transfer_to_vesting(self, amount, to=None, account=None): """ Vest STEEM :param float amount: number of STEEM to vest :param str to: (optional) the source account for the transfer if not ``default_account`` :param str account: (optional) the source account for the transfer if not ``default_account`` """ if not account: account = configStorage.get("default_account") if not account: raise ValueError("You need to provide an account") if not to: to = account # powerup on the same account op = operations.TransferToVesting( **{ "from": account, "to": to, "amount": '{:.{prec}f} {asset}'.format( float(amount), prec=3, asset='STEEM') }) return self.finalizeOp(op, account, "active")
def withdraw_vesting(self, amount, account=None): """ Withdraw VESTS from the vesting account. :param float amount: number of VESTS to withdraw over a period of 104 weeks :param str account: (optional) the source account for the transfer if not ``default_account`` """ if not account: account = configStorage.get("default_account") if not account: raise ValueError("You need to provide an account") op = operations.WithdrawVesting( **{ "account": account, "vesting_shares": '{:.{prec}f} {asset}'.format( float(amount), prec=6, asset="VESTS"), }) return self.finalizeOp(op, account, "active")
def vote(self, identifier, weight, account=None): """ Vote for a post :param str identifier: Identifier for the post to upvote Takes the form ``author/permlink`` :param float weight: Voting weight. Range: -100.0 - +100.0. May not be 0.0 :param str account: Voter to use for voting. (Optional) If ``voter`` is not defines, the ``default_account`` will be taken or a ValueError will be raised .. code-block:: python steempy set default_account <account> """ if not account: account = configStorage.get("default_account") if not account: raise ValueError("You need to provide a voter account") post_author, post_permlink = resolve_identifier(identifier) op = operations.Vote( **{ "voter": account, "author": post_author, "permlink": post_permlink, "weight": int(weight * STEEMIT_1_PERCENT) }) return self.finalizeOp(op, account, "posting")
def transfer(self, to, amount, asset, memo="", account=None): """ Transfer SBD or STEEM to another account. :param str to: Recipient :param float amount: Amount to transfer :param str asset: Asset to transfer (``SBD`` or ``STEEM``) :param str memo: (optional) Memo, may begin with `#` for encrypted messaging :param str account: (optional) the source account for the transfer if not ``default_account`` """ if not account: account = configStorage.get("default_account") if not account: raise ValueError("You need to provide an account") assert asset in ['STEEM', 'SBD'] if memo and memo[0] == "#": from smokebase import memo as Memo memo_wif = self.wallet.getMemoKeyForAccount(account) if not memo_wif: raise MissingKeyError("Memo key for %s missing!" % account) to_account = Account(to, steemd_instance=self.steemd) nonce = random.getrandbits(64) memo = Memo.encode_memo( PrivateKey(memo_wif), PublicKey(to_account["memo_key"], prefix=self.steemd.chain_params["prefix"]), nonce, memo, prefix=self.steemd.chain_params["prefix"]) op = operations.Transfer( **{ "from": account, "to": to, "amount": '{:.{prec}f} {asset}'.format( float(amount), prec=3, asset=asset), "memo": memo }) return self.finalizeOp(op, account, "active")
def transfer_from_savings_cancel(self, request_id, account=None): """ Cancel a withdrawal from 'savings' account. :param str request_id: Identifier for tracking or cancelling the withdrawal :param str account: (optional) the source account for the transfer if not ``default_account`` """ if not account: account = configStorage.get("default_account") if not account: raise ValueError("You need to provide an account") op = operations.CancelTransferFromSavings(**{ "from": account, "request_id": request_id, }) return self.finalizeOp(op, account, "active")
def comment_options(self, identifier, options, account=None): """ Set the comment options :param str identifier: Post identifier :param dict options: The options to define. :param str account: (optional) the account to allow access to (defaults to ``default_account``) For the options, you have these defaults::: { "author": "", "permlink": "", "max_accepted_payout": "1000000.000 SMOKE", "percent_steem_dollars": 10000, "allow_votes": True, "allow_curation_rewards": True, } """ if not account: account = configStorage.get("default_account") if not account: raise ValueError("You need to provide an account") account = Account(account, steemd_instance=self.steemd) author, permlink = resolve_identifier(identifier) default_max_payout = "1000000.000 SBD" op = operations.CommentOptions( **{ "author": author, "permlink": permlink, "max_accepted_payout": options.get("max_accepted_payout", default_max_payout), "percent_steem_dollars": options.get("percent_steem_dollars", 100) * STEEMIT_1_PERCENT, "allow_votes": options.get("allow_votes", True), "allow_curation_rewards": options.get("allow_curation_rewards", True), }) return self.finalizeOp(op, account["name"], "posting")
def approve_witness(self, witness, account=None, approve=True): """ Vote **for** a witness. This method adds a witness to your set of approved witnesses. To remove witnesses see ``disapprove_witness``. :param str witness: witness to approve :param str account: (optional) the account to allow access to (defaults to ``default_account``) """ if not account: account = configStorage.get("default_account") if not account: raise ValueError("You need to provide an account") account = Account(account, steemd_instance=self.steemd) op = operations.AccountWitnessVote(**{ "account": account["name"], "witness": witness, "approve": approve, }) return self.finalizeOp(op, account["name"], "active")
def update_account_profile(self, profile, account=None): """ Update an account's meta data (json_meta) :param dict json: The meta data to use (i.e. use Profile() from account.py) :param str account: (optional) the account to allow access to (defaults to ``default_account``) """ if not account: account = configStorage.get("default_account") if not account: raise ValueError("You need to provide an account") account = Account(account, steemd_instance=self.steemd) op = operations.AccountUpdate( **{ "account": account["name"], "memo_key": account["memo_key"], "json_metadata": profile }) return self.finalizeOp(op, account["name"], "active")
def claim_reward_balance(self, reward_steem='0 STEEM', reward_sbd='0 SBD', reward_vests='0 VESTS', account=None): """ Claim reward balances. By default, this will claim ``all`` outstanding balances. To bypass this behaviour, set desired claim amount by setting any of `reward_steem`, `reward_sbd` or `reward_vests`. Args: reward_steem (string): Amount of STEEM you would like to claim. reward_sbd (string): Amount of SBD you would like to claim. reward_vests (string): Amount of VESTS you would like to claim. account (string): The source account for the claim if not ``default_account`` is used. """ if not account: account = configStorage.get("default_account") if not account: raise ValueError("You need to provide an account") # if no values were set by user, claim all outstanding balances on # account if none( float(first(x.split(' '))) for x in [reward_sbd, reward_steem, reward_vests]): a = Account(account) reward_steem = a['reward_steem_balance'] reward_sbd = a['reward_sbd_balance'] reward_vests = a['reward_vesting_balance'] op = operations.ClaimRewardBalance( **{ "account": account, "reward_steem": reward_steem, "reward_sbd": reward_sbd, "reward_vests": reward_vests, }) return self.finalizeOp(op, account, "posting")
def resteem(self, identifier, account=None): """ Resteem a post :param str identifier: post identifier (<account>/<permlink>) :param str account: (optional) the account to allow access to (defaults to ``default_account``) """ if not account: account = configStorage.get("default_account") if not account: raise ValueError("You need to provide an account") author, permlink = resolve_identifier(identifier) json_body = [ "reblog", { "account": account, "author": author, "permlink": permlink } ] return self.custom_json(id="follow", json=json_body, required_posting_auths=[account])
def follow(self, follow, what=["blog"], account=None): """ Follow another account's blog :param str follow: Follow this account :param list what: List of states to follow (defaults to ``['blog']``) :param str account: (optional) the account to allow access to (defaults to ``default_account``) """ if not account: account = configStorage.get("default_account") if not account: raise ValueError("You need to provide an account") json_body = [ 'follow', { 'follower': account, 'following': follow, 'what': what } ] return self.custom_json(id="follow", json=json_body, required_posting_auths=[account])
def witness_update(self, signing_key, url, props, account=None): """ Update witness :param pubkey signing_key: Signing key :param str url: URL :param dict props: Properties :param str account: (optional) witness account name Properties::: { "account_creation_fee": x, "maximum_block_size": x, } """ if not account: account = configStorage.get("default_account") if not account: raise ValueError("You need to provide an account") try: PublicKey(signing_key) except Exception as e: raise e op = operations.WitnessUpdate( **{ "owner": account, "url": url, "block_signing_key": signing_key, "props": props, "fee": "0.000 STEEM", "prefix": self.steemd.chain_params["prefix"] }) return self.finalizeOp(op, account, "active")
def update_memo_key(self, key, account=None): """ Update an account's memo public key This method does **not** add any private keys to your wallet but merely changes the memo public key. :param str key: New memo public key :param str account: (optional) the account to allow access to (defaults to ``default_account``) """ if not account: account = configStorage.get("default_account") if not account: raise ValueError("You need to provide an account") PublicKey(key) # raises exception if invalid account = Account(account, steemd_instance=self.steemd) op = operations.AccountUpdate( **{ "account": account["name"], "memo_key": key, "json_metadata": account["json_metadata"] }) return self.finalizeOp(op, account["name"], "active")
def get_config_node_list(): from smokebase.storage import configStorage nodes = configStorage.get('nodes', None) if nodes: return nodes.split(',')
def allow(self, foreign, weight=None, permission="posting", account=None, threshold=None): """ Give additional access to an account by some other public key or account. :param str foreign: The foreign account that will obtain access :param int weight: (optional) The weight to use. If not define, the threshold will be used. If the weight is smaller than the threshold, additional signatures will be required. (defaults to threshold) :param str permission: (optional) The actual permission to modify (defaults to ``posting``) :param str account: (optional) the account to allow access to (defaults to ``default_account``) :param int threshold: The threshold that needs to be reached by signatures to be able to interact """ if not account: account = configStorage.get("default_account") if not account: raise ValueError("You need to provide an account") if permission not in ["owner", "posting", "active"]: raise ValueError( "Permission needs to be either 'owner', 'posting', or 'active") account = Account(account, steemd_instance=self.steemd) if not weight: weight = account[permission]["weight_threshold"] authority = account[permission] try: pubkey = PublicKey(foreign) authority["key_auths"].append([str(pubkey), weight]) except: # noqa FIXME(sneak) try: foreign_account = Account(foreign, steemd_instance=self.steemd) authority["account_auths"].append( [foreign_account["name"], weight]) except: # noqa FIXME(sneak) raise ValueError( "Unknown foreign account or unvalid public key") if threshold: authority["weight_threshold"] = threshold self._test_weights_treshold(authority) op = operations.AccountUpdate( **{ "account": account["name"], permission: authority, "memo_key": account["memo_key"], "json_metadata": account["json_metadata"], 'prefix': self.steemd.chain_params["prefix"] }) if permission == "owner": return self.finalizeOp(op, account["name"], "owner") else: return self.finalizeOp(op, account["name"], "active")
def disallow(self, foreign, permission="posting", account=None, threshold=None): """ Remove additional access to an account by some other public key or account. :param str foreign: The foreign account that will obtain access :param str permission: (optional) The actual permission to modify (defaults to ``posting``) :param str account: (optional) the account to allow access to (defaults to ``default_account``) :param int threshold: The threshold that needs to be reached by signatures to be able to interact """ if not account: account = configStorage.get("default_account") if not account: raise ValueError("You need to provide an account") if permission not in ["owner", "posting", "active"]: raise ValueError( "Permission needs to be either 'owner', 'posting', or 'active") account = Account(account, steemd_instance=self.steemd) authority = account[permission] try: pubkey = PublicKey(foreign, prefix=self.steemd.chain_params["prefix"]) affected_items = list( filter(lambda x: x[0] == str(pubkey), authority["key_auths"])) authority["key_auths"] = list( filter(lambda x: x[0] != str(pubkey), authority["key_auths"])) except: # noqa FIXME(sneak) try: foreign_account = Account(foreign, steemd_instance=self.steemd) affected_items = list( filter(lambda x: x[0] == foreign_account["name"], authority["account_auths"])) authority["account_auths"] = list( filter(lambda x: x[0] != foreign_account["name"], authority["account_auths"])) except: # noqa FIXME(sneak) raise ValueError( "Unknown foreign account or unvalid public key") removed_weight = affected_items[0][1] # Define threshold if threshold: authority["weight_threshold"] = threshold # Correct threshold (at most by the amount removed from the # authority) try: self._test_weights_treshold(authority) except: # noqa FIXME(sneak) log.critical("The account's threshold will be reduced by %d" % removed_weight) authority["weight_threshold"] -= removed_weight self._test_weights_treshold(authority) op = operations.AccountUpdate( **{ "account": account["name"], permission: authority, "memo_key": account["memo_key"], "json_metadata": account["json_metadata"] }) if permission == "owner": return self.finalizeOp(op, account["name"], "owner") else: return self.finalizeOp(op, account["name"], "active")
def create_account( self, account_name, json_meta=None, password=None, owner_key=None, active_key=None, posting_key=None, memo_key=None, additional_owner_keys=[], additional_active_keys=[], additional_posting_keys=[], additional_owner_accounts=[], additional_active_accounts=[], additional_posting_accounts=[], store_keys=True, store_owner_key=False, delegation_fee_steem='0 STEEM', creator=None, ): """ Create new account in Steem The brainkey/password can be used to recover all generated keys (see `steembase.account` for more details. By default, this call will use ``default_account`` to register a new name ``account_name`` with all keys being derived from a new brain key that will be returned. The corresponding keys will automatically be installed in the wallet. .. note:: Account creations cost a fee that is defined by the network. If you create an account, you will need to pay for that fee! **You can partially pay that fee by delegating VESTS.** To pay the fee in full in STEEM, leave ``delegation_fee_steem`` set to ``0 STEEM`` (Default). To pay the fee partially in STEEM, partially with delegated VESTS, set ``delegation_fee_steem`` to a value greater than ``1 STEEM``. `Required VESTS will be calculated automatically.` To pay the fee with maximum amount of delegation, set ``delegation_fee_steem`` to ``1 STEEM``. `Required VESTS will be calculated automatically.` .. warning:: Don't call this method unless you know what you are doing! Be sure to understand what this method does and where to find the private keys for your account. .. note:: Please note that this imports private keys (if password is present) into the wallet by default. However, it **does not import the owner key** unless `store_owner_key` is set to True (default False). Do NOT expect to be able to recover it from the wallet if you lose your password! :param str account_name: (**required**) new account name :param str json_meta: Optional meta data for the account :param str owner_key: Main owner key :param str active_key: Main active key :param str posting_key: Main posting key :param str memo_key: Main memo_key :param str password: Alternatively to providing keys, one can provide a password from which the keys will be derived :param list additional_owner_keys: Additional owner public keys :param list additional_active_keys: Additional active public keys :param list additional_posting_keys: Additional posting public keys :param list additional_owner_accounts: Additional owner account names :param list additional_active_accounts: Additional active account names :param list additional_posting_accounts: Additional posting account names :param bool store_keys: Store new keys in the wallet (default: ``True``) :param bool store_owner_key: Store owner key in the wallet (default: ``False``) :param str delegation_fee_steem: (Optional) If set, `creator` pay a fee of this amount, and delegate the rest with VESTS (calculated automatically). Minimum: 1 STEEM. If left to 0 (Default), full fee is paid without VESTS delegation. :param str creator: which account should pay the registration fee (defaults to ``default_account``) :raises AccountExistsException: if the account already exists on the blockchain """ assert len( account_name) <= 16, "Account name must be at most 16 chars long" if not creator: creator = configStorage.get("default_account") if not creator: raise ValueError( "Not creator account given. Define it with " + "creator=x, or set the default_account using steempy") if password and (owner_key or posting_key or active_key or memo_key): raise ValueError("You cannot use 'password' AND provide keys!") # check if account already exists try: Account(account_name, steemd_instance=self.steemd) except: # noqa FIXME(sneak) pass else: raise AccountExistsException " Generate new keys from password" from smokebase.account import PasswordKey, PublicKey if password: posting_key = PasswordKey(account_name, password, role="posting") active_key = PasswordKey(account_name, password, role="active") owner_key = PasswordKey(account_name, password, role="owner") memo_key = PasswordKey(account_name, password, role="memo") posting_pubkey = posting_key.get_public_key() active_pubkey = active_key.get_public_key() owner_pubkey = owner_key.get_public_key() memo_pubkey = memo_key.get_public_key() posting_privkey = posting_key.get_private_key() active_privkey = active_key.get_private_key() owner_privkey = owner_key.get_private_key() memo_privkey = memo_key.get_private_key() # store private keys if store_keys: if store_owner_key: self.wallet.addPrivateKey(owner_privkey) self.wallet.addPrivateKey(active_privkey) self.wallet.addPrivateKey(posting_privkey) self.wallet.addPrivateKey(memo_privkey) elif owner_key and posting_key and active_key and memo_key: posting_pubkey = PublicKey( posting_key, prefix=self.steemd.chain_params["prefix"]) active_pubkey = PublicKey( active_key, prefix=self.steemd.chain_params["prefix"]) owner_pubkey = PublicKey(owner_key, prefix=self.steemd.chain_params["prefix"]) memo_pubkey = PublicKey(memo_key, prefix=self.steemd.chain_params["prefix"]) else: raise ValueError( "Call incomplete! Provide either a password or public keys!") owner = format(owner_pubkey, self.steemd.chain_params["prefix"]) active = format(active_pubkey, self.steemd.chain_params["prefix"]) posting = format(posting_pubkey, self.steemd.chain_params["prefix"]) memo = format(memo_pubkey, self.steemd.chain_params["prefix"]) owner_key_authority = [[owner, 1]] active_key_authority = [[active, 1]] posting_key_authority = [[posting, 1]] owner_accounts_authority = [] active_accounts_authority = [] posting_accounts_authority = [] # additional authorities for k in additional_owner_keys: owner_key_authority.append([k, 1]) for k in additional_active_keys: active_key_authority.append([k, 1]) for k in additional_posting_keys: posting_key_authority.append([k, 1]) for k in additional_owner_accounts: owner_accounts_authority.append([k, 1]) for k in additional_active_accounts: active_accounts_authority.append([k, 1]) for k in additional_posting_accounts: posting_accounts_authority.append([k, 1]) props = self.steemd.get_chain_properties() required_fee_steem = Amount(props["account_creation_fee"]).amount * 30 required_fee_vests = 0 delegation_fee_steem = Amount(delegation_fee_steem).amount if delegation_fee_steem: # creating accounts without delegation requires 30x # account_creation_fee creating account with delegation allows one # to use VESTS to pay the fee where the ratio must satisfy 1 STEEM # in fee == 5 STEEM in delegated VESTS delegated_sp_fee_mult = 5 if delegation_fee_steem < 1: raise ValueError( "When creating account with delegation, at least " + "1 STEEM in fee must be paid.") # calculate required remaining fee in vests remaining_fee = required_fee_steem - delegation_fee_steem if remaining_fee > 0: required_sp = remaining_fee * delegated_sp_fee_mult required_fee_vests = Converter().sp_to_vests(required_sp) + 1 s = { 'creator': creator, 'fee': '%s STEEM' % (delegation_fee_steem or required_fee_steem), 'delegation': '%s VESTS' % required_fee_vests, 'json_metadata': json_meta or {}, 'memo_key': memo, 'new_account_name': account_name, 'owner': { 'account_auths': owner_accounts_authority, 'key_auths': owner_key_authority, 'weight_threshold': 1 }, 'active': { 'account_auths': active_accounts_authority, 'key_auths': active_key_authority, 'weight_threshold': 1 }, 'posting': { 'account_auths': posting_accounts_authority, 'key_auths': posting_key_authority, 'weight_threshold': 1 }, 'prefix': self.steemd.chain_params["prefix"] } op = operations.AccountCreateWithDelegation(**s) return self.finalizeOp(op, creator, "active")