def create(self, extra_entropy='', chain_id=MAINNET_CHAIN_ID): ''' Creates a new private key, and returns it as a :class:`~newchain_account.local.LocalAccount`. :param extra_entropy: Add extra randomness to whatever randomness your OS can provide :type extra_entropy: str or bytes or int :returns: an object with private key and convenience methods .. code-block:: python >>> from newchain_account import Account >>> acct = Account.create('KEYSMASH FJAFJKLDSKF7JKFDJ 1530') >>> acct.address '0x5ce9454909639D2D17A3F753ce7d93fa0b9aB12E' >>> acct.privateKey b"\\xb2\\}\\xb3\\x1f\\xee\\xd9\\x12''\\xbf\\t9\\xdcv\\x9a\\x96VK-\\xe4\\xc4rm\\x03[6\\xec\\xf1\\xe5\\xb3d" # These methods are also available: signHash(), signTransaction(), encrypt() # They correspond to the same-named methods in Account.* # but without the private key argument ''' self.chain_id = chain_id extra_key_bytes = text_if_str(to_bytes, extra_entropy) key_bytes = keccak(os.urandom(32) + extra_key_bytes) return self.privateKeyToAccount(key_bytes)
def signTransaction(self, transaction_dict, private_key): ''' Sign a transaction using a local private key. Produces signature details and the hex-encoded transaction suitable for broadcast using :meth:`w3.eth.sendRawTransaction() <web3.eth.Eth.sendRawTransaction>`. Create the transaction dict for a contract method with `my_contract.functions.my_function().buildTransaction() <http://web3py.readthedocs.io/en/latest/contracts.html#methods>`_ :param dict transaction_dict: the transaction with keys: nonce, chainId, to, data, value, gas, and gasPrice. :param private_key: the private key to sign the data with :type private_key: hex str, bytes or int :returns: Various details about the signature - most importantly the fields: v, r, and s :rtype: AttributeDict .. code-block:: python >>> transaction = { 'to': '0xF0109fC8DF283027b6285cc889F5aA624EaC1F55', 'value': 1000000000, 'gas': 2000000, 'gasPrice': 234567897654321, 'nonce': 0, 'chainId': 1 } >>> key = '0x4c0883a69102937d6231471b5dbb6204fe5129617082792ae468d01a3f362318' >>> signed = Account.signTransaction(transaction, key) {'hash': HexBytes('0x6893a6ee8df79b0f5d64a180cd1ef35d030f3e296a5361cf04d02ce720d32ec5'), 'r': 4487286261793418179817841024889747115779324305375823110249149479905075174044, 'rawTransaction': HexBytes('0xf86a8086d55698372431831e848094f0109fc8df283027b6285cc889f5aa624eac1f55843b9aca008025a009ebb6ca057a0535d6186462bc0b465b561c94a295bdb0621fc19208ab149a9ca0440ffd775ce91a833ab410777204d5341a6f9fa91216a6f3ee2c051fea6a0428'), # noqa: E501 's': 30785525769477805655994251009256770582792548537338581640010273753578382951464, 'v': 37} >>> w3.eth.sendRawTransaction(signed.rawTransaction) ''' if not isinstance(transaction_dict, Mapping): raise TypeError("transaction_dict must be dict-like, got %r" % transaction_dict) account = self.privateKeyToAccount(private_key) # sign transaction ( v, r, s, rlp_encoded, ) = sign_transaction_dict(account._key_obj, transaction_dict) transaction_hash = keccak(rlp_encoded) return AttributeDict({ 'rawTransaction': HexBytes(rlp_encoded), 'hash': HexBytes(transaction_hash), 'r': r, 's': s, 'v': v, })
def generate_account(self, web3, balance=0): extra_entropy = '' extra_key_bytes = text_if_str(to_bytes, extra_entropy) key_bytes = keccak(os.urandom(32) + extra_key_bytes) privatekey = keys.PrivateKey(key_bytes) address = privatekey.public_key.to_address() address = Web3.toChecksumAddress(address) prikey = privatekey.to_hex()[2:] if balance != 0: self.sendTransaction(web3, '', self.account_with_money['address'], address, web3.platon.gasPrice, 21000, balance) account = { "address": address, "nonce": 0, "balance": balance, "prikey": prikey, } self.accounts[address] = account # todo delete debug def debug(): from conf.settings import BASE_DIR from ruamel import yaml accounts = list(self.accounts.values()) with open(os.path.join(BASE_DIR, "deploy/tmp/accounts.yml"), mode="w", encoding="UTF-8") as f: yaml.dump(accounts, f, Dumper=yaml.RoundTripDumper) debug() return address, prikey
def sign_transaction(account, transaction_dict): if not isinstance(transaction_dict, Mapping): raise TypeError("transaction_dict must be dict-like, got %r" % transaction_dict) # allow from field, *only* if it matches the private key if 'from' in transaction_dict: if transaction_dict['from'] == account.address: sanitized_transaction = dissoc(transaction_dict, 'from') else: raise TypeError("from field must match key's %s, but it was %s" % ( account.address, transaction_dict['from'], )) else: sanitized_transaction = transaction_dict # sign transaction ( v, r, s, rlp_encoded, ) = sign_transaction_dict(account._key_obj, sanitized_transaction) transaction_hash = keccak(rlp_encoded) return AttributeDict({ 'rawTransaction': HexBytes(rlp_encoded), 'hash': HexBytes(transaction_hash), 'r': r, 's': s, 'v': v, })
def createKey(entropy): extra_key_bytes = text_if_str(to_bytes, entropy) key_bytes = keccak(os.urandom(32) + extra_key_bytes) key = parsePrivateKey(key_bytes) return { "private_key": key, "address": key.public_key.to_checksum_address() }
def rpc_balanceOf(address): func_hash = keccak(text='balanceOf(address)') selector = func_hash[:4] encoded_params = encode_abi(['address'], [address]) tx_data = to_hex(HexBytes(selector) + encoded_params) payload = {'to': addr, 'data': tx_data} ret = w3.eth.call(payload) return decode_single('uint256', ret)
def _hash_eip191_message(signable_message: SignableMessage) -> Hash32: version = signable_message.version if len(version) != 1: raise ValidationError( "The supplied message version is {version!r}. " "The EIP-191 signable message standard only supports one-byte versions." ) joined = b'\x19' + version + signable_message.header + signable_message.body return Hash32(keccak(joined))
def rpc_transfer(owner, to, value): func_hash = keccak(text='transfer(address,uint256)') selector = func_hash[:4] encoded_params = encode_abi(['address', 'uint256'], [to, value]) tx_data = to_hex(HexBytes(selector) + encoded_params) payload = {'from': owner, 'to': addr, 'data': tx_data} tx_hash = w3.eth.sendTransaction(payload) return w3.eth.waitForTransactionReceipt(tx_hash)
def generate_key(): """ generate node public private key :return: privateKey publicKey """ extra_entropy = '' extra_key_bytes = text_if_str(to_bytes, extra_entropy) key_bytes = keccak(os.urandom(32) + extra_key_bytes) privatekey = keys.PrivateKey(key_bytes) return privatekey.to_hex()[2:], keys.private_key_to_public_key(privatekey).to_hex()[2:]
def _hash_eip191_message(signable_message: SignableMessage) -> Hash32: """ Hash the given ``signable_message`` according to the EIP-191 Signed Data Standard. """ version = signable_message.version if len(version) != 1: raise ValidationError( "The supplied message version is {version!r}. " "The EIP-191 signable message standard only supports one-byte versions." ) joined = b"\x19" + version + signable_message.header + signable_message.body return Hash32(keccak(joined))
def sign(key, wallet, text): """Sign text using private key or wallet""" if (key is None and wallet is None): click.echo( 'Error: Please specify either a key or a wallet path (not both)') return if (key is not None and wallet is not None): click.echo( 'Error: Please specify either a key or a wallet path (not both)') return if (key is not None and text is None): click.echo('Error: Please specify a text to be signed') return private_key = None if (wallet is not None): if not os.path.isfile(wallet): click.echo('Error: Wallet file not found') return w = json.loads('{}') with open(wallet) as json_file: contents = json.load(json_file) w.update(contents) if not w['node_secret']: click.echo('Error: Private key not found in wallet file') return private_key = "0x{}".format(w['node_secret']) if (text is None): if not w['node_address']: click.echo('Error: Wallet address not found in wallet file') return text = "0x{}".format(w['node_address']) if (key is not None): private_key = key account = Account.from_key(private_key) sig = account.signHash(keccak(hexstr=text)) sig_hex = sig.signature.hex() click.echo(sig_hex)
def create(self, extra_entropy=''): r""" Creates a new private key, and returns it as a :class:`~eth_account.local.LocalAccount`. :param extra_entropy: Add extra randomness to whatever randomness your OS can provide :type extra_entropy: str or bytes or int :returns: an object with private key and convenience methods .. code-block:: python >>> from eth_account import Account >>> acct = Account.create('KEYSMASH FJAFJKLDSKF7JKFDJ 1530') >>> acct.address '0x5ce9454909639D2D17A3F753ce7d93fa0b9aB12E' >>> acct.key HexBytes('0x8676e9a8c86c8921e922e61e0bb6e9e9689aad4c99082620610b00140e5f21b8') # These methods are also available: sign_message(), sign_transaction(), encrypt() # They correspond to the same-named methods in Account.* # but without the private key argument """ extra_key_bytes = text_if_str(to_bytes, extra_entropy) key_bytes = keccak(os.urandom(32) + extra_key_bytes) return self.from_key(key_bytes)
def create(self, extra_entropy=''): r""" Creates a new private key, and returns it as a :class:`~eth_account.local.LocalAccount`. :param extra_entropy: Add extra randomness to whatever randomness your OS can provide :type extra_entropy: str or bytes or int :returns: an object with private key and convenience methods .. code-block:: python >>> from eth_account import Account >>> acct = Account.create('KEYSMASH FJAFJKLDSKF7JKFDJ 1530') >>> acct.address '0x5ce9454909639D2D17A3F753ce7d93fa0b9aB12E' >>> acct.key b"\xb2\}\xb3\x1f\xee\xd9\x12''\xbf\t9\xdcv\x9a\x96VK-\xe4\xc4rm\x03[6\xec\xf1\xe5\xb3d" # These methods are also available: sign_message(), sign_transaction(), encrypt() # They correspond to the same-named methods in Account.* # but without the private key argument """ extra_key_bytes = text_if_str(to_bytes, extra_entropy) key_bytes = keccak(os.urandom(32) + extra_key_bytes) return self.from_key(key_bytes)
def sign_transaction(self, transaction_dict, private_key): """ Sign a transaction using a local private key. It produces signature details and the hex-encoded transaction suitable for broadcast using :meth:`w3.eth.sendRawTransaction() <web3.eth.Eth.sendRawTransaction>`. To create the transaction dict that calls a contract, use contract object: `my_contract.functions.my_function().buildTransaction() <http://web3py.readthedocs.io/en/latest/contracts.html#methods>`_ Note: For non-legacy (typed) transactions, if the transaction type is not explicitly provided, it may be determined from the transaction parameters of a well-formed transaction. See below for examples on how to sign with different transaction types. :param dict transaction_dict: the transaction with available keys, depending on the type of transaction: nonce, chainId, to, data, value, gas, gasPrice, type, accessList, maxFeePerGas, and maxPriorityFeePerGas :param private_key: the private key to sign the data with :type private_key: hex str, bytes, int or :class:`eth_keys.datatypes.PrivateKey` :returns: Various details about the signature - most importantly the fields: v, r, and s :rtype: AttributeDict .. code-block:: python >>> # EIP-1559 dynamic fee transaction (more efficient and preferred over legacy txn) >>> dynamic_fee_transaction = { "type": 2, # optional - can be implicitly determined based on max fee params # noqa: E501 "gas": 100000, "maxFeePerGas": 2000000000, "maxPriorityFeePerGas": 2000000000, "data": "0x616263646566", "nonce": 34, "to": "0x09616C3d61b3331fc4109a9E41a8BDB7d9776609", "value": "0x5af3107a4000", "accessList": ( # optional { "address": "0x0000000000000000000000000000000000000001", "storageKeys": ( "0x0100000000000000000000000000000000000000000000000000000000000000", # noqa: E501 ) }, ), "chainId": 1900, } >>> key = '0x4c0883a69102937d6231471b5dbb6204fe5129617082792ae468d01a3f362318' >>> signed = Account.sign_transaction(dynamic_fee_transaction, key) {'hash': HexBytes('0x126431f2a7fda003aada7c2ce52b0ce3cbdbb1896230d3333b9eea24f42d15b0'), 'r': 110093478023675319011132687961420618950720745285952062287904334878381994888509, 'rawTransaction': HexBytes('0x02f8b282076c2284773594008477359400830186a09409616c3d61b3331fc4109a9e41a8bdb7d9776609865af3107a400086616263646566f838f7940000000000000000000000000000000000000001e1a0010000000000000000000000000000000000000000000000000000000000000080a0f366b34a5c206859b9778b4c909207e53443cca9e0b82e0b94bc4b47e6434d3da04a731eda413a944d4ea2d2236671e586e57388d0e9d40db53044ae4089f2aec8'), # noqa: E501 's': 33674551144139401179914073499472892825822542092106065756005379322302694600392, 'v': 0} >>> w3.eth.sendRawTransaction(signed.rawTransaction) .. code-block:: python >>> # legacy transaction (less efficient than EIP-1559 dynamic fee txn) >>> legacy_transaction = { # Note that the address must be in checksum format or native bytes: 'to': '0xF0109fC8DF283027b6285cc889F5aA624EaC1F55', 'value': 1000000000, 'gas': 2000000, 'gasPrice': 234567897654321, 'nonce': 0, 'chainId': 1 } >>> key = '0x4c0883a69102937d6231471b5dbb6204fe5129617082792ae468d01a3f362318' >>> signed = Account.sign_transaction(legacy_transaction, key) {'hash': HexBytes('0x6893a6ee8df79b0f5d64a180cd1ef35d030f3e296a5361cf04d02ce720d32ec5'), 'r': 4487286261793418179817841024889747115779324305375823110249149479905075174044, 'rawTransaction': HexBytes('0xf86a8086d55698372431831e848094f0109fc8df283027b6285cc889f5aa624eac1f55843b9aca008025a009ebb6ca057a0535d6186462bc0b465b561c94a295bdb0621fc19208ab149a9ca0440ffd775ce91a833ab410777204d5341a6f9fa91216a6f3ee2c051fea6a0428'), # noqa: E501 's': 30785525769477805655994251009256770582792548537338581640010273753578382951464, 'v': 37} >>> w3.eth.sendRawTransaction(signed.rawTransaction) .. code-block:: python >>> access_list_transaction = { "type": 1, # optional - can be implicitly determined based on 'accessList' and 'gasPrice' params # noqa: E501 "gas": 100000, "gasPrice": 1000000000, "data": "0x616263646566", "nonce": 34, "to": "0x09616C3d61b3331fc4109a9E41a8BDB7d9776609", "value": "0x5af3107a4000", "accessList": ( { "address": "0x0000000000000000000000000000000000000001", "storageKeys": ( "0x0100000000000000000000000000000000000000000000000000000000000000", # noqa: E501 ) }, ), "chainId": 1900, } >>> key = '0x4c0883a69102937d6231471b5dbb6204fe5129617082792ae468d01a3f362318' >>> signed = Account.sign_transaction(access_list_transaction, key) {'hash': HexBytes('0x2864ca20a74ca5e044067ad4139a22ff5a0853434f5f1dc00108f24ef5f1f783'), 'r': 105940705063391628472351883894091935317142890114440570831409400676736873197702, 'rawTransaction': HexBytes('0x01f8ad82076c22843b9aca00830186a09409616c3d61b3331fc4109a9e41a8bdb7d9776609865af3107a400086616263646566f838f7940000000000000000000000000000000000000001e1a0010000000000000000000000000000000000000000000000000000000000000080a0ea38506c4afe4bb402e030877fbe1011fa1da47aabcf215db8da8fee5d3af086a051e9af653b8eb98e74e894a766cf88904dbdb10b0bc1fbd12f18f661fa2797a4'), # noqa: E501 's': 37050226636175381535892585331727388340134760347943439553552848647212419749796, 'v': 0} >>> w3.eth.sendRawTransaction(signed.rawTransaction) """ if not isinstance(transaction_dict, Mapping): raise TypeError("transaction_dict must be dict-like, got %r" % transaction_dict) account = self.from_key(private_key) # allow from field, *only* if it matches the private key if 'from' in transaction_dict: if transaction_dict['from'] == account.address: sanitized_transaction = dissoc(transaction_dict, 'from') else: raise TypeError("from field must match key's %s, but it was %s" % ( account.address, transaction_dict['from'], )) else: sanitized_transaction = transaction_dict # sign transaction ( v, r, s, encoded_transaction, ) = sign_transaction_dict(account._key_obj, sanitized_transaction) transaction_hash = keccak(encoded_transaction) return SignedTransaction( rawTransaction=HexBytes(encoded_transaction), hash=HexBytes(transaction_hash), r=r, s=s, v=v, )
def sign_transaction(transaction_dict, private_key) -> SignedTransaction: """ Sign a (non-staking) transaction dictionary with the specified private key Parameters ---------- transaction_dict: :obj:`dict` with the following keys nonce: :obj:`int` Transaction nonce gasPrice: :obj:`int` Transaction gas price in Atto gas: :obj:`int` Gas limit in Atto to: :obj:`str` Destination address value: :obj:`int` Amount to be transferred in Atto data: :obj:`str` Transaction data, used for smart contracts from: :obj:`str` From address, optional (if passed, must match the public key address generated from private_key) chainId: :obj:`int` One of util.chainIds.keys(), optional If you want to replay your transaction across networks, do not pass it shardID: :obj:`int` Originating shard ID, optional (needed for cx shard transaction) toShardID: :obj:`int` Destination shard ID, optional (needed for cx shard transaction) r: :obj:`int` First 32 bytes of the signature, optional s: :obj:`int` Next 32 bytes of the signature, optional v: :obj:`int` Recovery value, optional private_key: :obj:`str` The private key Returns ------- A SignedTransaction object, which is a named tuple rawTransaction: :obj:`str` Hex bytes of the raw transaction hash: :obj:`str` Hex bytes of the transaction hash r: :obj:`int` First 32 bytes of the signature s: :obj:`int` Next 32 bytes of the signature v: :obj:`int` Recovery value Raises ------ TypeError, if the from address specified is not the same one as derived from the the private key AssertionError, if the fields for the transaction are missing, or if the chainId supplied is not a string, or if the chainId is not a key in util.py API Reference ------------- https://readthedocs.org/projects/eth-account/downloads/pdf/stable/ """ account, sanitized_transaction = sanitize_transaction( transaction_dict, private_key) if 'to' in sanitized_transaction and sanitized_transaction[ 'to'] is not None: sanitized_transaction['to'] = convert_one_to_hex( sanitized_transaction['to']) filled_transaction = pipe( # https://github.com/ethereum/eth-account/blob/00e7b10005c5fa7090086fcef37a76296c524e17/eth_account/_utils/transactions.py#L39 sanitized_transaction, dict, partial(merge, TRANSACTION_DEFAULTS), chain_id_to_v, apply_formatters_to_dict(HARMONY_FORMATTERS)) unsigned_transaction = serialize_transaction(filled_transaction) transaction_hash = unsigned_transaction.hash() if isinstance(unsigned_transaction, (UnsignedEthereumTxData, UnsignedHarmonyTxData)): chain_id = None # https://github.com/ethereum/eth-account/blob/00e7b10005c5fa7090086fcef37a76296c524e17/eth_account/_utils/signing.py#L26 else: chain_id = unsigned_transaction.v (v, r, s) = sign_transaction_hash(account._key_obj, transaction_hash, chain_id) encoded_transaction = encode_transaction(unsigned_transaction, vrs=(v, r, s)) signed_transaction_hash = keccak(encoded_transaction) return SignedTransaction( rawTransaction=HexBytes(encoded_transaction), hash=HexBytes(signed_transaction_hash), r=r, s=s, v=v, )
def _sign_transaction_generic(account, sanitized_transaction, parent_serializer): """ Sign a generic staking transaction, given the serializer base class and account Paramters --------- account: :obj:`eth_account.Account`, the account to use for signing sanitized_transaction: :obj:`dict`, The sanitized transaction (chainId checks and no from key) parent_serializer: :obj: The serializer class from staking_structures Returns ------- SignedTransaction object, which can be posted to the chain by using blockchain.send_raw_transaction Raises ------ Assertion / KeyError, if certain keys are missing from the dict rlp.exceptions.ObjectSerializationError, if data types are not as expected """ # obtain the serializers if sanitized_transaction.get('chainId', 0) == 0: unsigned_serializer, signed_serializer = parent_serializer.Unsigned(), parent_serializer.Signed() # unsigned, signed else: unsigned_serializer, signed_serializer = parent_serializer.SignedChainId(), parent_serializer.SignedChainId() # since chain_id_to_v adds v/r/s, unsigned is not used here # fill the transaction filled_transaction = pipe( # https://github.com/ethereum/eth-account/blob/00e7b10005c5fa7090086fcef37a76296c524e17/eth_account/_utils/transactions.py#L39 sanitized_transaction, dict, partial(merge, {'chainId': None}), chain_id_to_v, # will move chain id to v and add v/r/s apply_formatters_to_dict(FORMATTERS) ) # get the unsigned transaction for f, _ in unsigned_serializer._meta.fields: assert f in filled_transaction, f'Could not find {f} in transaction' unsigned_transaction = unsigned_serializer.from_dict(\ {f: filled_transaction[f] for f, _ in unsigned_serializer._meta.fields}) # drop extras silently # sign the unsigned transaction if 'v' in unsigned_transaction.as_dict(): chain_id = unsigned_transaction.v else: chain_id = None transaction_hash = unsigned_transaction.hash() (v, r, s) = sign_transaction_hash( account._key_obj, transaction_hash, chain_id) chain_naive_transaction = dissoc( unsigned_transaction.as_dict(), 'v', 'r', 's') # remove extra v/r/s added by chain_id_to_v # serialize it signed_transaction = signed_serializer( v=v + (8 if chain_id is None else 0), # copied from https://github.com/harmony-one/sdk/blob/99a827782fabcd5f91f025af0d8de228956d42b4/packages/harmony-staking/src/stakingTransaction.ts#L207 r=r, s=s, # in the below statement, remove everything not expected by signed_serializer **{f: chain_naive_transaction[f] for f, _ in signed_serializer._meta.fields if f not in 'vrs'}) # encode it encoded_transaction = rlp.encode(signed_transaction) # hash it signed_transaction_hash = keccak(encoded_transaction) # return is return SignedTransaction( rawTransaction=HexBytes(encoded_transaction), hash=HexBytes(signed_transaction_hash), r=r, s=s, v=v, )
from eth_keys import keys from eth_utils.curried import keccak import os, codecs def to_hex(raw): return '0x' + codecs.decode(codecs.encode(raw, 'hex'), 'ascii') key_bytes = keccak(os.urandom(32) + b'some entropy you want') print('{0:>18} => {1}'.format('raw key', to_hex(key_bytes))) privateKey = keys.PrivateKey(key_bytes) print('{0:>18} => {1}'.format('private key', str(privateKey))) publicKey = privateKey.public_key print('{0:>18} => {1}'.format('public key', str(publicKey))) address = publicKey.to_checksum_address() print('{0:>18} => {1}'.format('checksum address', address))
def get_topic(text): return to_hex(keccak(text=text))