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)
Ejemplo n.º 2
0
    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,
        })
Ejemplo n.º 3
0
    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
Ejemplo n.º 4
0
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,
    })
Ejemplo n.º 5
0
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)
Ejemplo n.º 7
0
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)
Ejemplo n.º 9
0
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:]
Ejemplo n.º 10
0
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))
Ejemplo n.º 11
0
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)
Ejemplo n.º 12
0
    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)
Ejemplo n.º 13
0
    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)
Ejemplo n.º 14
0
    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,
        )
Ejemplo n.º 15
0
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,
    )
Ejemplo n.º 16
0
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))