def test_safe_multisig_tx_serializer(self):
        safe = get_eth_address_with_key()[0]
        to = None
        value = int(10e18)
        tx_data = None
        operation = 0
        safe_tx_gas = 1
        data_gas = 1
        gas_price = 1
        gas_token = None
        refund_receiver = None
        nonce = 0

        data = {
            "safe": safe,
            "to": to,
            "value": value,  # 1 ether
            "data": tx_data,
            "operation": operation,
            "safe_tx_gas": safe_tx_gas,
            "data_gas": data_gas,
            "gas_price": gas_price,
            "gas_token": gas_token,
            "nonce": nonce,
            "signatures": [{
                'r': 5,
                's': 7,
                'v': 27
            }, {
                'r': 17,
                's': 29,
                'v': 28
            }]
        }
        serializer = SafeRelayMultisigTxSerializer(data=data)
        self.assertFalse(
            serializer.is_valid())  # Less signatures than threshold

        # Signatures must be sorted!
        accounts = [Account.create() for _ in range(2)]
        accounts.sort(key=lambda x: x.address.lower())

        safe = get_eth_address_with_key()[0]
        data['safe'] = safe

        serializer = SafeRelayMultisigTxSerializer(data=data)
        self.assertFalse(
            serializer.is_valid())  # To and data cannot both be null

        tx_data = HexBytes('0xabcd')
        data['data'] = tx_data.hex()
        serializer = SafeRelayMultisigTxSerializer(data=data)
        self.assertFalse(serializer.is_valid()
                         )  # Operation is not create, but no to provided

        # Now we fix the signatures
        to = accounts[-1].address
        data['to'] = to
        multisig_tx_hash = SafeTx(None,
                                  safe,
                                  to,
                                  value,
                                  tx_data,
                                  operation,
                                  safe_tx_gas,
                                  data_gas,
                                  gas_price,
                                  gas_token,
                                  refund_receiver,
                                  safe_nonce=nonce).safe_tx_hash

        signatures = [
            account.signHash(multisig_tx_hash) for account in accounts
        ]
        data['signatures'] = signatures
        serializer = SafeRelayMultisigTxSerializer(data=data)
        self.assertTrue(serializer.is_valid())

        data = {
            "safe": safe,
            "to": to,
            "value": value,  # 1 ether
            "data": tx_data,
            "operation": operation,
            "safe_tx_gas": safe_tx_gas,
            "data_gas": data_gas,
            "gas_price": gas_price,
            "gas_token": gas_token,
            "nonce": nonce,
            "refund_receiver":
            accounts[0].address,  # Refund must be empty or NULL_ADDRESS
            "signatures": [{
                'r': 5,
                's': 7,
                'v': 27
            }]
        }
        serializer = SafeRelayMultisigTxSerializer(data=data)
        self.assertFalse(serializer.is_valid())

        data['refund_receiver'] = NULL_ADDRESS
        serializer = SafeRelayMultisigTxSerializer(data=data)
        self.assertTrue(serializer.is_valid())
示例#2
0
 def to_python(self, value):
     return value if value is None else HexBytes(value).hex()
    def get_total_transfer_history(
            self,
            addresses: List[str],
            from_block: int = 0,
            to_block: Optional[int] = None,
            token_address: Optional[str] = None) -> List[Dict[str, Any]]:
        """
        Get events for erc20 and erc721 transfers from and to an `address`. We decode it manually
        An example of an erc20 event:
        {'logIndex': 0,
         'transactionIndex': 0,
         'transactionHash': HexBytes('0x4d0f25313603e554e3b040667f7f391982babbd195c7ae57a8c84048189f7794'),
         'blockHash': HexBytes('0x90fa67d848a0eaf3be625235dae28815389f5292d4465c48d1139f0c207f8d42'),
         'blockNumber': 791,
         'address': '0xf7d0Bd47BF3214494E7F5B40E392A25cb4788620',
         'data': '0x000000000000000000000000000000000000000000000000002001f716742000',
         'topics': [HexBytes('0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'),
          HexBytes('0x000000000000000000000000f5984365fca2e3bc7d2e020abb2c701df9070eb7'),
          HexBytes('0x0000000000000000000000001df62f291b2e969fb0849d99d9ce41e2f137006e')],
         'type': 'mined'
         'args': {'from': '0xf5984365FcA2e3bc7D2E020AbB2c701DF9070eB7',
                  'to': '0x1dF62f291b2E969fB0849d99D9Ce41e2F137006e',
                  'value': 9009360000000000
                 }
        }
        An example of an erc721 event
        {'address': '0x6631FcbB50677DfC6c02CCDcc03a8f68Db427a64',
         'blockHash': HexBytes('0x95c71c6c9373e9a8ca2c767dda1cd5083eb6addcce36fc216c9e1f458d6970f9'),
         'blockNumber': 5341681,
         'data': '0x',
         'logIndex': 0,
         'removed': False,
         'topics': [HexBytes('0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'),
          HexBytes('0x0000000000000000000000000000000000000000000000000000000000000000'),
          HexBytes('0x000000000000000000000000b5239c032ab9fb5abfc3903e770a4b6a9095542c'),
          HexBytes('0x0000000000000000000000000000000000000000000000000000000000000063')],
         'transactionHash': HexBytes('0xce8c8af0503e6f8a421345c10cdf92834c95186916a3f5b1437d2bba63d2db9e'),
         'transactionIndex': 0,
         'transactionLogIndex': '0x0',
         'type': 'mined',
         'args': {'from': '0x0000000000000000000000000000000000000000',
                  'to': '0xb5239C032AB9fB5aBFc3903e770A4B6a9095542C',
                  'tokenId': 99
                 }
         }
        :param addresses: Search events `from` and `to` these `addresses`
        :param from_block: Block to start querying from
        :param to_block: Block to stop querying from
        :param token_address: Address of the token
        :return: List of events sorted by blockNumber
        """
        topic_0 = self.TRANSFER_TOPIC.hex()
        addresses_encoded = [
            HexBytes(eth_abi.encode_single('address', address)).hex()
            for address in addresses
        ]
        # Topics for transfer `to` and `from` an address
        topics_from = [topic_0, addresses_encoded]
        topics_to = [topic_0, None, addresses_encoded]
        parameters: Dict[str, Any] = {'fromBlock': from_block}
        if to_block:
            parameters['toBlock'] = to_block
        if token_address:
            parameters['address'] = token_address

        all_events: List[Dict] = []
        # Do the request to `eth_getLogs`
        for topics in (topics_to, topics_from):
            parameters['topics'] = topics
            all_events.extend(self.slow_w3.eth.getLogs(parameters))

        # Decode events. Just pick valid ERC20 Transfer events (ERC721 `Transfer` has the same signature)
        erc20_events = []
        for event in all_events:
            event['args'] = self._decode_erc20_or_erc721_log(
                event['data'], event['topics'])
            if event['args']:
                erc20_events.append(event)
        erc20_events.sort(key=lambda x: x['blockNumber'])
        return erc20_events
示例#4
0
def increase(file, address, template, config, offline, style):
    """
    this is staking submodule increase command.
    """
    if template:
        show_params()
        return
    if not os.path.isfile(file):
        cust_print('file {} not exits! please check!'.format(file), fg='r')
        sys.exit(1)
    params = read_json_file(file)
    wallet_dir = g_dict_dir_config["wallet_dir"]
    wallet_file_path, private_key, hrp, _ = verify_password(
        address, wallet_dir)

    ppos = get_eth_obj(config, 'ppos')
    _params = {}
    try:
        _params['typ'] = params['typ']
        _params['node_id'] = params['node_id'] or ppos.admin.nodeInfo.id
        _params['amount'] = ppos.w3.toWei(str(params['amount']), "ether")
        _params['pri_key'] = private_key[2:]
        if isinstance(params['transaction_cfg'], dict):
            _params['transaction_cfg'] = params['transaction_cfg']
    except KeyError as e:
        cust_print('Key {} does not exist in file {},please check!'.format(
            e, file),
                   fg='r')
        sys.exit(1)
    try:
        if offline:
            data = HexBytes(
                rlp.encode([
                    rlp.encode(int(1002)),
                    rlp.encode(bytes.fromhex(_params['node_id'])),
                    rlp.encode(_params['typ']),
                    rlp.encode(_params['amount'])
                ])).hex()
            params['to_type'] = 'staking'
            transaction_dict = un_sign_data(data, params, ppos,
                                            _params['pri_key'])
            unsigned_tx_dir = g_dict_dir_config["unsigned_tx_dir"]
            check_dir_exits(unsigned_tx_dir)
            unsigned_file_csv_name = "unsigned_staking_increase_{}.csv".format(
                get_time_stamp())
            unsigned_file_path = os.path.join(unsigned_tx_dir,
                                              unsigned_file_csv_name)
            if style == '':
                write_csv(unsigned_file_path, [transaction_dict])
            else:
                unsigned_file_path = unsigned_file_path.replace('csv', 'jpg')
                write_QRCode(transaction_dict, unsigned_file_path)
            cust_print('unsigned_file save to:{}'.format(unsigned_file_path),
                       fg='g')
        else:
            tx_hash = ppos.increaseStaking(*_params.values())
            cust_print(
                'increase staking send transfer transaction successful, tx hash:{}.'
                .format(tx_hash),
                fg='g')
    except ValueError as e:
        cust_print(
            'increase staking send transfer transaction fail,error info:{}'.
            format(e),
            fg='r')
        sys.exit(1)
示例#5
0
        "signed":
        "f87f8085e8d4a510008227108080af6025515b525b600a37f260003556601b596020356000355760015b525b54602052f260255860005b525b54602052f21ba05afed0244d0da90b67cf8979b0f246432a5112c0d31e8d5eedd2bc17b171c694a0bb1035c834677c2e1185b8dc90ca6d1fa585ab3d7ef23707e1a497a98e752d1b"  # noqa: 501
    },
    {
        "chainId":
        None,
        "key":
        "c85ef7d79691fe79573b1a7064c19c1a9819ebdbd1faaab1a8ec92344438aaf4",
        "nonce":
        0,
        "gasPrice":
        1000000000000,
        "gas":
        10000,
        "to":
        HexBytes("0x13978aee95f38490e9769C39B2773Ed763d9cd5F"),
        "value":
        10000000000000000,
        "data":
        "",
        "unsigned":
        "eb8085e8d4a510008227109413978aee95f38490e9769c39b2773ed763d9cd5f872386f26fc1000080808080",  # noqa: 501
        "signed":
        "f86b8085e8d4a510008227109413978aee95f38490e9769c39b2773ed763d9cd5f872386f26fc10000801ba0eab47c1a49bf2fe5d40e01d313900e19ca485867d462fe06e139e3a536c6d4f4a014a569d327dcda4b29f74f93c0e9729d2f49ad726e703f9cd90dbb0fbf6649f1"  # noqa: 501
    },
]

PRIVATE_KEY_AS_BYTES = b'unicorns' * 4
PRIVATE_KEY_AS_HEXSTR = '0x756e69636f726e73756e69636f726e73756e69636f726e73756e69636f726e73'
PRIVATE_KEY_AS_INT = 0x756e69636f726e73756e69636f726e73756e69636f726e73756e69636f726e73
PRIVATE_KEY_AS_OBJ = keys.PrivateKey(PRIVATE_KEY_AS_BYTES)
示例#6
0
    def encrypt(cls, private_key, password, kdf=None, iterations=None):
        """
        Creates a dictionary with an encrypted version of your private key.
        To import this keyfile into Ethereum clients like geth and parity:
        encode this dictionary with :func:`json.dumps` and save it to disk where your
        client keeps key files.

        :param private_key: The raw private key
        :type private_key: hex str, bytes, int or :class:`eth_keys.datatypes.PrivateKey`
        :param str password: The password which you will need to unlock the account in your client
        :param str kdf: The key derivation function to use when encrypting your private key
        :param int iterations: The work factor for the key derivation function
        :returns: The data to use in your encrypted file
        :rtype: dict

        If kdf is not set, the default key derivation function falls back to the
        environment variable :envvar:`ETH_ACCOUNT_KDF`. If that is not set, then
        'scrypt' will be used as the default.

        .. code-block:: python

            >>> import getpass
            >>> encrypted = Account.encrypt(
                0xb25c7db31feed9122727bf0939dc769a96564b2de4c4726d035b36ecf1e5b364,
                getpass.getpass()
            )

            {
                'address': '5ce9454909639d2d17a3f753ce7d93fa0b9ab12e',
                'crypto': {
                    'cipher': 'aes-128-ctr',
                    'cipherparams': {
                        'iv': '0b7845a5c3597d3d378bde9b7c7319b7'
                    },
                    'ciphertext': 'a494f1feb3c854e99c1ff01e6aaa17d43c0752009073503b908457dc8de5d2a5',  # noqa: E501
                    'kdf': 'scrypt',
                    'kdfparams': {
                        'dklen': 32,
                        'n': 262144,
                        'p': 8,
                        'r': 1,
                        'salt': '13c4a48123affaa29189e9097726c698'
                    },
                    'mac': 'f4cfb027eb0af9bd7a320b4374a3fa7bef02cfbafe0ec5d1fd7ad129401de0b1'
                },
                'id': 'a60e0578-0e5b-4a75-b991-d55ec6451a6f',
                'version': 3
            }

             >>> with open('my-keyfile', 'w') as f:
                 f.write(json.dumps(encrypted))
        """
        if isinstance(private_key, keys.PrivateKey):
            key_bytes = private_key.to_bytes()
        else:
            key_bytes = HexBytes(private_key)

        if kdf is None:
            kdf = cls._default_kdf

        password_bytes = text_if_str(to_bytes, password)
        assert len(key_bytes) == 32

        return create_keyfile_json(key_bytes,
                                   password_bytes,
                                   kdf=kdf,
                                   iterations=iterations)
示例#7
0
    def test_produce_mpe_events_from_blockchain(self,
                                                mock_get_current_block_no,
                                                mock_last_block_number,
                                                mock_get_contract_instance):
        mpe_event_producer = MPEEventProducer("wss://ropsten.infura.io/ws",
                                              Repository(NETWORKS))
        event_repository = EventRepository(Repository(NETWORKS))

        deposit_fund_Event_object = Mock()
        deposit_fund_Event_object.createFilter = Mock(return_value=Mock(
            get_all_entries=Mock(return_value=[
                AttributeDict({
                    'args':
                    AttributeDict({
                        'sender': '0xabd2cCb3828b4428bBde6C2031A865b0fb272a5A',
                        'amount': 30000000
                    }),
                    'event':
                    'DepositFunds',
                    'logIndex':
                    1,
                    'transactionIndex':
                    18,
                    'transactionHash':
                    HexBytes(
                        '0x562cc2fa59d9c7a4aa56106a19ad9c8078a95ae68416619fc191d86c50c91f12'
                    ),
                    'address':
                    '0x8FB1dC8df86b388C7e00689d1eCb533A160B4D0C',
                    'blockHash':
                    HexBytes(
                        '0xe06042a4d471351c0ee9e50056bd4fb6a0e158b2489ba70775d3c06bd29da19b'
                    ),
                    'blockNumber':
                    6286405
                })
            ])))

        mock_get_contract_instance.return_value = Mock(
            events=Mock(DepositFunds=deposit_fund_Event_object,
                        abi=[{
                            "type": "event",
                            "name": "DepositFunds"
                        }]))

        mock_last_block_number.return_value = 50

        mock_get_current_block_no.return_value = 50
        blockchain_events = mpe_event_producer.produce_event(3)
        assert blockchain_events == [
            AttributeDict({
                'args':
                AttributeDict({
                    'sender': '0xabd2cCb3828b4428bBde6C2031A865b0fb272a5A',
                    'amount': 30000000
                }),
                'event':
                'DepositFunds',
                'logIndex':
                1,
                'transactionIndex':
                18,
                'transactionHash':
                HexBytes(
                    '0x562cc2fa59d9c7a4aa56106a19ad9c8078a95ae68416619fc191d86c50c91f12'
                ),
                'address':
                '0x8FB1dC8df86b388C7e00689d1eCb533A160B4D0C',
                'blockHash':
                HexBytes(
                    '0xe06042a4d471351c0ee9e50056bd4fb6a0e158b2489ba70775d3c06bd29da19b'
                ),
                'blockNumber':
                6286405
            })
        ]
示例#8
0
class EthModuleTest:
    def test_eth_protocolVersion(self, web3: "Web3") -> None:
        protocol_version = web3.eth.protocolVersion

        assert is_string(protocol_version)
        assert protocol_version.isdigit()

    def test_eth_syncing(self, web3: "Web3") -> None:
        syncing = web3.eth.syncing

        assert is_boolean(syncing) or is_dict(syncing)

        if is_boolean(syncing):
            assert syncing is False
        elif is_dict(syncing):
            sync_dict = cast(SyncStatus, syncing)
            assert 'startingBlock' in sync_dict
            assert 'currentBlock' in sync_dict
            assert 'highestBlock' in sync_dict

            assert is_integer(sync_dict['startingBlock'])
            assert is_integer(sync_dict['currentBlock'])
            assert is_integer(sync_dict['highestBlock'])

    def test_eth_coinbase(self, web3: "Web3") -> None:
        coinbase = web3.eth.coinbase
        assert is_checksum_address(coinbase)

    def test_eth_mining(self, web3: "Web3") -> None:
        mining = web3.eth.mining
        assert is_boolean(mining)

    def test_eth_hashrate(self, web3: "Web3") -> None:
        hashrate = web3.eth.hashrate
        assert is_integer(hashrate)
        assert hashrate >= 0

    def test_eth_chainId(self, web3: "Web3") -> None:
        chain_id = web3.eth.chainId
        # chain id value from geth fixture genesis file
        assert chain_id == 131277322940537

    def test_eth_gasPrice(self, web3: "Web3") -> None:
        gas_price = web3.eth.gasPrice
        assert is_integer(gas_price)
        assert gas_price > 0

    def test_eth_accounts(self, web3: "Web3") -> None:
        accounts = web3.eth.accounts
        assert is_list_like(accounts)
        assert len(accounts) != 0
        assert all((is_checksum_address(account) for account in accounts))
        assert web3.eth.coinbase in accounts

    def test_eth_blockNumber(self, web3: "Web3") -> None:
        block_number = web3.eth.blockNumber
        assert is_integer(block_number)
        assert block_number >= 0

    def test_eth_getBalance(self, web3: "Web3") -> None:
        coinbase = web3.eth.coinbase

        with pytest.raises(InvalidAddress):
            web3.eth.getBalance(
                ChecksumAddress(HexAddress(HexStr(coinbase.lower()))))

        balance = web3.eth.getBalance(coinbase)

        assert is_integer(balance)
        assert balance >= 0

    def test_eth_getBalance_with_block_identifier(self, web3: "Web3") -> None:
        miner_address = web3.eth.getBlock(1)['miner']
        genesis_balance = web3.eth.getBalance(miner_address, 0)
        later_balance = web3.eth.getBalance(miner_address, 1)

        assert is_integer(genesis_balance)
        assert is_integer(later_balance)
        assert later_balance > genesis_balance

    def test_eth_getStorageAt(
            self, web3: "Web3",
            emitter_contract_address: ChecksumAddress) -> None:
        storage = web3.eth.getStorageAt(emitter_contract_address, 0)
        assert isinstance(storage, HexBytes)

    def test_eth_getStorageAt_invalid_address(self, web3: "Web3") -> None:
        coinbase = web3.eth.coinbase
        with pytest.raises(InvalidAddress):
            web3.eth.getStorageAt(
                ChecksumAddress(HexAddress(HexStr(coinbase.lower()))), 0)

    def test_eth_getTransactionCount(
            self, web3: "Web3",
            unlocked_account_dual_type: ChecksumAddress) -> None:
        transaction_count = web3.eth.getTransactionCount(
            unlocked_account_dual_type)
        assert is_integer(transaction_count)
        assert transaction_count >= 0

    def test_eth_getTransactionCount_invalid_address(self,
                                                     web3: "Web3") -> None:
        coinbase = web3.eth.coinbase
        with pytest.raises(InvalidAddress):
            web3.eth.getTransactionCount(
                ChecksumAddress(HexAddress(HexStr(coinbase.lower()))))

    def test_eth_getBlockTransactionCountByHash_empty_block(
            self, web3: "Web3", empty_block: BlockData) -> None:
        transaction_count = web3.eth.getBlockTransactionCount(
            empty_block['hash'])

        assert is_integer(transaction_count)
        assert transaction_count == 0

    def test_eth_getBlockTransactionCountByNumber_empty_block(
            self, web3: "Web3", empty_block: BlockData) -> None:
        transaction_count = web3.eth.getBlockTransactionCount(
            empty_block['number'])

        assert is_integer(transaction_count)
        assert transaction_count == 0

    def test_eth_getBlockTransactionCountByHash_block_with_txn(
            self, web3: "Web3", block_with_txn: BlockData) -> None:
        transaction_count = web3.eth.getBlockTransactionCount(
            block_with_txn['hash'])

        assert is_integer(transaction_count)
        assert transaction_count >= 1

    def test_eth_getBlockTransactionCountByNumber_block_with_txn(
            self, web3: "Web3", block_with_txn: BlockData) -> None:
        transaction_count = web3.eth.getBlockTransactionCount(
            block_with_txn['number'])

        assert is_integer(transaction_count)
        assert transaction_count >= 1

    def test_eth_getUncleCountByBlockHash(self, web3: "Web3",
                                          empty_block: BlockData) -> None:
        uncle_count = web3.eth.getUncleCount(empty_block['hash'])

        assert is_integer(uncle_count)
        assert uncle_count == 0

    def test_eth_getUncleCountByBlockNumber(self, web3: "Web3",
                                            empty_block: BlockData) -> None:
        uncle_count = web3.eth.getUncleCount(empty_block['number'])

        assert is_integer(uncle_count)
        assert uncle_count == 0

    def test_eth_getCode(self, web3: "Web3",
                         math_contract_address: ChecksumAddress) -> None:
        code = web3.eth.getCode(math_contract_address)
        assert isinstance(code, HexBytes)
        assert len(code) > 0

    def test_eth_getCode_invalid_address(self, web3: "Web3",
                                         math_contract: "Contract") -> None:
        with pytest.raises(InvalidAddress):
            web3.eth.getCode(
                ChecksumAddress(
                    HexAddress(HexStr(math_contract.address.lower()))))

    def test_eth_getCode_with_block_identifier(
            self, web3: "Web3", emitter_contract: "Contract") -> None:
        code = web3.eth.getCode(emitter_contract.address,
                                block_identifier=web3.eth.blockNumber)
        assert isinstance(code, HexBytes)
        assert len(code) > 0

    def test_eth_sign(self, web3: "Web3",
                      unlocked_account_dual_type: ChecksumAddress) -> None:
        signature = web3.eth.sign(unlocked_account_dual_type,
                                  text='Message tö sign. Longer than hash!')
        assert is_bytes(signature)
        assert len(signature) == 32 + 32 + 1

        # test other formats
        hexsign = web3.eth.sign(
            unlocked_account_dual_type,
            hexstr=HexStr(
                '0x4d6573736167652074c3b6207369676e2e204c6f6e676572207468616e206861736821'
            ))
        assert hexsign == signature

        intsign = web3.eth.sign(
            unlocked_account_dual_type,
            0x4d6573736167652074c3b6207369676e2e204c6f6e676572207468616e206861736821
        )
        assert intsign == signature

        bytessign = web3.eth.sign(
            unlocked_account_dual_type,
            b'Message t\xc3\xb6 sign. Longer than hash!')
        assert bytessign == signature

        new_signature = web3.eth.sign(unlocked_account_dual_type,
                                      text='different message is different')
        assert new_signature != signature

    def test_eth_signTypedData(
        self,
        web3: "Web3",
        unlocked_account_dual_type: ChecksumAddress,
        skip_if_testrpc: Callable[["Web3"], None],
    ) -> None:
        validJSONMessage = '''
            {
                "types": {
                    "EIP712Domain": [
                        {"name": "name", "type": "string"},
                        {"name": "version", "type": "string"},
                        {"name": "chainId", "type": "uint256"},
                        {"name": "verifyingContract", "type": "address"}
                    ],
                    "Person": [
                        {"name": "name", "type": "string"},
                        {"name": "wallet", "type": "address"}
                    ],
                    "Mail": [
                        {"name": "from", "type": "Person"},
                        {"name": "to", "type": "Person"},
                        {"name": "contents", "type": "string"}
                    ]
                },
                "primaryType": "Mail",
                "domain": {
                    "name": "Ether Mail",
                    "version": "1",
                    "chainId": "0x01",
                    "verifyingContract": "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC"
                },
                "message": {
                    "from": {
                        "name": "Cow",
                        "wallet": "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826"
                    },
                    "to": {
                        "name": "Bob",
                        "wallet": "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB"
                    },
                    "contents": "Hello, Bob!"
                }
            }
        '''
        skip_if_testrpc(web3)
        signature = HexBytes(
            web3.eth.signTypedData(unlocked_account_dual_type,
                                   json.loads(validJSONMessage)))
        assert len(signature) == 32 + 32 + 1

    def test_invalid_eth_signTypedData(
            self, web3: "Web3", unlocked_account_dual_type: ChecksumAddress,
            skip_if_testrpc: Callable[["Web3"], None]) -> None:
        skip_if_testrpc(web3)
        invalid_typed_message = '''
            {
                "types": {
                    "EIP712Domain": [
                        {"name": "name", "type": "string"},
                        {"name": "version", "type": "string"},
                        {"name": "chainId", "type": "uint256"},
                        {"name": "verifyingContract", "type": "address"}
                    ],
                    "Person": [
                        {"name": "name", "type": "string"},
                        {"name": "wallet", "type": "address"}
                    ],
                    "Mail": [
                        {"name": "from", "type": "Person"},
                        {"name": "to", "type": "Person[2]"},
                        {"name": "contents", "type": "string"}
                    ]
                },
                "primaryType": "Mail",
                "domain": {
                    "name": "Ether Mail",
                    "version": "1",
                    "chainId": "0x01",
                    "verifyingContract": "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC"
                },
                "message": {
                    "from": {
                        "name": "Cow",
                        "wallet": "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826"
                    },
                    "to": [{
                        "name": "Bob",
                        "wallet": "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB"
                    }],
                    "contents": "Hello, Bob!"
                }
            }
        '''
        with pytest.raises(
                ValueError,
                match=
                r".*Expected 2 items for array type Person\[2\], got 1 items.*"
        ):
            web3.eth.signTypedData(unlocked_account_dual_type,
                                   json.loads(invalid_typed_message))

    def test_eth_signTransaction(self, web3: "Web3",
                                 unlocked_account: ChecksumAddress) -> None:
        txn_params: TxParams = {
            'from': unlocked_account,
            'to': unlocked_account,
            'value': Wei(1),
            'gas': Wei(21000),
            'gasPrice': web3.eth.gasPrice,
            'nonce': Nonce(0),
        }
        result = web3.eth.signTransaction(txn_params)
        signatory_account = web3.eth.account.recover_transaction(result['raw'])
        assert unlocked_account == signatory_account
        assert result['tx']['to'] == txn_params['to']
        assert result['tx']['value'] == txn_params['value']
        assert result['tx']['gas'] == txn_params['gas']
        assert result['tx']['gasPrice'] == txn_params['gasPrice']
        assert result['tx']['nonce'] == txn_params['nonce']

    def test_eth_sendTransaction_addr_checksum_required(
            self, web3: "Web3", unlocked_account: ChecksumAddress) -> None:
        non_checksum_addr = unlocked_account.lower()
        txn_params: TxParams = {
            'from': unlocked_account,
            'to': unlocked_account,
            'value': Wei(1),
            'gas': Wei(21000),
            'gasPrice': web3.eth.gasPrice,
        }

        with pytest.raises(InvalidAddress):
            invalid_params = cast(
                TxParams, dict(txn_params, **{'from': non_checksum_addr}))
            web3.eth.sendTransaction(invalid_params)

        with pytest.raises(InvalidAddress):
            invalid_params = cast(
                TxParams, dict(txn_params, **{'to': non_checksum_addr}))
            web3.eth.sendTransaction(invalid_params)

    def test_eth_sendTransaction(
            self, web3: "Web3",
            unlocked_account_dual_type: ChecksumAddress) -> None:
        txn_params: TxParams = {
            'from': unlocked_account_dual_type,
            'to': unlocked_account_dual_type,
            'value': Wei(1),
            'gas': Wei(21000),
            'gasPrice': web3.eth.gasPrice,
        }
        txn_hash = web3.eth.sendTransaction(txn_params)
        txn = web3.eth.getTransaction(txn_hash)

        assert is_same_address(txn['from'],
                               cast(ChecksumAddress, txn_params['from']))
        assert is_same_address(txn['to'],
                               cast(ChecksumAddress, txn_params['to']))
        assert txn['value'] == 1
        assert txn['gas'] == 21000
        assert txn['gasPrice'] == txn_params['gasPrice']

    def test_eth_sendTransaction_with_nonce(
            self, web3: "Web3", unlocked_account: ChecksumAddress) -> None:
        txn_params: TxParams = {
            'from': unlocked_account,
            'to': unlocked_account,
            'value': Wei(1),
            'gas': Wei(21000),
            # Increased gas price to ensure transaction hash different from other tests
            'gasPrice': Wei(web3.eth.gasPrice * 3),
            'nonce': web3.eth.getTransactionCount(unlocked_account),
        }
        txn_hash = web3.eth.sendTransaction(txn_params)
        txn = web3.eth.getTransaction(txn_hash)

        assert is_same_address(txn['from'],
                               cast(ChecksumAddress, txn_params['from']))
        assert is_same_address(txn['to'],
                               cast(ChecksumAddress, txn_params['to']))
        assert txn['value'] == 1
        assert txn['gas'] == 21000
        assert txn['gasPrice'] == txn_params['gasPrice']
        assert txn['nonce'] == txn_params['nonce']

    def test_eth_replaceTransaction(
            self, web3: "Web3",
            unlocked_account_dual_type: ChecksumAddress) -> None:
        txn_params: TxParams = {
            'from': unlocked_account_dual_type,
            'to': unlocked_account_dual_type,
            'value': Wei(1),
            'gas': Wei(21000),
            'gasPrice': web3.eth.gasPrice,
        }
        txn_hash = web3.eth.sendTransaction(txn_params)

        txn_params['gasPrice'] = Wei(web3.eth.gasPrice * 2)
        replace_txn_hash = web3.eth.replaceTransaction(txn_hash, txn_params)
        replace_txn = web3.eth.getTransaction(replace_txn_hash)

        assert is_same_address(replace_txn['from'],
                               cast(ChecksumAddress, txn_params['from']))
        assert is_same_address(replace_txn['to'],
                               cast(ChecksumAddress, txn_params['to']))
        assert replace_txn['value'] == 1
        assert replace_txn['gas'] == 21000
        assert replace_txn['gasPrice'] == txn_params['gasPrice']

    def test_eth_replaceTransaction_non_existing_transaction(
            self, web3: "Web3",
            unlocked_account_dual_type: ChecksumAddress) -> None:
        txn_params: TxParams = {
            'from': unlocked_account_dual_type,
            'to': unlocked_account_dual_type,
            'value': Wei(1),
            'gas': Wei(21000),
            'gasPrice': web3.eth.gasPrice,
        }
        with pytest.raises(TransactionNotFound):
            web3.eth.replaceTransaction(
                HexStr(
                    '0x98e8cc09b311583c5079fa600f6c2a3bea8611af168c52e4b60b5b243a441997'
                ), txn_params)

    def test_eth_replaceTransaction_already_mined(
            self, web3: "Web3",
            unlocked_account_dual_type: ChecksumAddress) -> None:
        txn_params: TxParams = {
            'from': unlocked_account_dual_type,
            'to': unlocked_account_dual_type,
            'value': Wei(1),
            'gas': Wei(21000),
            'gasPrice': web3.eth.gasPrice,
        }
        txn_hash = web3.eth.sendTransaction(txn_params)
        web3.eth.waitForTransactionReceipt(txn_hash)

        txn_params['gasPrice'] = Wei(web3.eth.gasPrice * 2)
        with pytest.raises(ValueError, match="Supplied transaction with hash"):
            web3.eth.replaceTransaction(txn_hash, txn_params)

    def test_eth_replaceTransaction_incorrect_nonce(
            self, web3: "Web3", unlocked_account: ChecksumAddress) -> None:
        txn_params: TxParams = {
            'from': unlocked_account,
            'to': unlocked_account,
            'value': Wei(1),
            'gas': Wei(21000),
            'gasPrice': web3.eth.gasPrice,
        }
        txn_hash = web3.eth.sendTransaction(txn_params)
        txn = web3.eth.getTransaction(txn_hash)

        txn_params['gasPrice'] = Wei(web3.eth.gasPrice * 2)
        txn_params['nonce'] = Nonce(txn['nonce'] + 1)
        with pytest.raises(ValueError):
            web3.eth.replaceTransaction(txn_hash, txn_params)

    def test_eth_replaceTransaction_gas_price_too_low(
            self, web3: "Web3",
            unlocked_account_dual_type: ChecksumAddress) -> None:
        txn_params: TxParams = {
            'from': unlocked_account_dual_type,
            'to': unlocked_account_dual_type,
            'value': Wei(1),
            'gas': Wei(21000),
            'gasPrice': Wei(10),
        }
        txn_hash = web3.eth.sendTransaction(txn_params)

        txn_params['gasPrice'] = Wei(9)
        with pytest.raises(ValueError):
            web3.eth.replaceTransaction(txn_hash, txn_params)

    def test_eth_replaceTransaction_gas_price_defaulting_minimum(
            self, web3: "Web3", unlocked_account: ChecksumAddress) -> None:
        txn_params: TxParams = {
            'from': unlocked_account,
            'to': unlocked_account,
            'value': Wei(1),
            'gas': Wei(21000),
            'gasPrice': Wei(10),
        }
        txn_hash = web3.eth.sendTransaction(txn_params)

        txn_params.pop('gasPrice')
        replace_txn_hash = web3.eth.replaceTransaction(txn_hash, txn_params)
        replace_txn = web3.eth.getTransaction(replace_txn_hash)

        assert replace_txn['gasPrice'] == 12  # minimum gas price

    def test_eth_replaceTransaction_gas_price_defaulting_strategy_higher(
            self, web3: "Web3", unlocked_account: ChecksumAddress) -> None:
        txn_params: TxParams = {
            'from': unlocked_account,
            'to': unlocked_account,
            'value': Wei(1),
            'gas': Wei(21000),
            'gasPrice': Wei(10),
        }
        txn_hash = web3.eth.sendTransaction(txn_params)

        def higher_gas_price_strategy(web3: "Web3", txn: TxParams) -> Wei:
            return Wei(20)

        web3.eth.setGasPriceStrategy(higher_gas_price_strategy)

        txn_params.pop('gasPrice')
        replace_txn_hash = web3.eth.replaceTransaction(txn_hash, txn_params)
        replace_txn = web3.eth.getTransaction(replace_txn_hash)
        assert replace_txn[
            'gasPrice'] == 20  # Strategy provides higher gas price

    def test_eth_replaceTransaction_gas_price_defaulting_strategy_lower(
            self, web3: "Web3", unlocked_account: ChecksumAddress) -> None:
        txn_params: TxParams = {
            'from': unlocked_account,
            'to': unlocked_account,
            'value': Wei(1),
            'gas': Wei(21000),
            'gasPrice': Wei(10),
        }
        txn_hash = web3.eth.sendTransaction(txn_params)

        def lower_gas_price_strategy(web3: "Web3", txn: TxParams) -> Wei:
            return Wei(5)

        web3.eth.setGasPriceStrategy(lower_gas_price_strategy)

        txn_params.pop('gasPrice')
        replace_txn_hash = web3.eth.replaceTransaction(txn_hash, txn_params)
        replace_txn = web3.eth.getTransaction(replace_txn_hash)
        # Strategy provices lower gas price - minimum preferred
        assert replace_txn['gasPrice'] == 12

    def test_eth_modifyTransaction(self, web3: "Web3",
                                   unlocked_account: ChecksumAddress) -> None:
        txn_params: TxParams = {
            'from': unlocked_account,
            'to': unlocked_account,
            'value': Wei(1),
            'gas': Wei(21000),
            'gasPrice': web3.eth.gasPrice,
        }
        txn_hash = web3.eth.sendTransaction(txn_params)

        modified_txn_hash = web3.eth.modifyTransaction(
            txn_hash,
            gasPrice=(cast(int, txn_params['gasPrice']) * 2),
            value=2)
        modified_txn = web3.eth.getTransaction(modified_txn_hash)

        assert is_same_address(modified_txn['from'],
                               cast(ChecksumAddress, txn_params['from']))
        assert is_same_address(modified_txn['to'],
                               cast(ChecksumAddress, txn_params['to']))
        assert modified_txn['value'] == 2
        assert modified_txn['gas'] == 21000
        assert modified_txn['gasPrice'] == cast(int,
                                                txn_params['gasPrice']) * 2

    @pytest.mark.parametrize(
        'raw_transaction, expected_hash',
        [
            (
                # address 0x39EEed73fb1D3855E90Cbd42f348b3D7b340aAA6
                '0xf8648085174876e8008252089439eeed73fb1d3855e90cbd42f348b3d7b340aaa601801ba0ec1295f00936acd0c2cb90ab2cdaacb8bf5e11b3d9957833595aca9ceedb7aada05dfc8937baec0e26029057abd3a1ef8c505dca2cdc07ffacb046d090d2bea06a',  # noqa: E501
                '0x1f80f8ab5f12a45be218f76404bda64d37270a6f4f86ededd0eb599f80548c13',
            ),
            (
                # private key 0x3c2ab4e8f17a7dea191b8c991522660126d681039509dc3bb31af7c9bdb63518
                # This is an unfunded account, but the transaction has a 0 gas price, so is valid.
                # It never needs to be mined, we just want the transaction hash back to confirm.
                HexBytes(
                    '0xf85f808082c35094d898d5e829717c72e7438bad593076686d7d164a80801ba005c2e99ecee98a12fbf28ab9577423f42e9e88f2291b3acc8228de743884c874a077d6bc77a47ad41ec85c96aac2ad27f05a039c4787fca8a1e5ee2d8c7ec1bb6a'
                ),  # noqa: E501
                '0x98eeadb99454427f6aad7b558bac13e9d225512a6f5e5c11cf48e8d4067e51b5',
            ),
        ])
    def test_eth_sendRawTransaction(
        self,
        web3: "Web3",
        raw_transaction: Union[HexStr, bytes],
        funded_account_for_raw_txn: ChecksumAddress,
        expected_hash: HexStr,
    ) -> None:
        txn_hash = web3.eth.sendRawTransaction(raw_transaction)
        assert txn_hash == web3.toBytes(hexstr=expected_hash)

    def test_eth_call(self, web3: "Web3", math_contract: "Contract") -> None:
        coinbase = web3.eth.coinbase
        txn_params = math_contract._prepare_transaction(
            fn_name='add',
            fn_args=(7, 11),
            transaction={
                'from': coinbase,
                'to': math_contract.address
            },
        )
        call_result = web3.eth.call(txn_params)
        assert is_string(call_result)
        result = web3.codec.decode_single('uint256', call_result)
        assert result == 18

    def test_eth_call_with_0_result(self, web3: "Web3",
                                    math_contract: "Contract") -> None:
        coinbase = web3.eth.coinbase
        txn_params = math_contract._prepare_transaction(
            fn_name='add',
            fn_args=(0, 0),
            transaction={
                'from': coinbase,
                'to': math_contract.address
            },
        )
        call_result = web3.eth.call(txn_params)
        assert is_string(call_result)
        result = web3.codec.decode_single('uint256', call_result)
        assert result == 0

    def test_eth_estimateGas(
            self, web3: "Web3",
            unlocked_account_dual_type: ChecksumAddress) -> None:
        gas_estimate = web3.eth.estimateGas({
            'from': unlocked_account_dual_type,
            'to': unlocked_account_dual_type,
            'value': Wei(1),
        })
        assert is_integer(gas_estimate)
        assert gas_estimate > 0

    def test_eth_estimateGas_with_block(
            self, web3: "Web3",
            unlocked_account_dual_type: ChecksumAddress) -> None:
        gas_estimate = web3.eth.estimateGas(
            {
                'from': unlocked_account_dual_type,
                'to': unlocked_account_dual_type,
                'value': Wei(1),
            }, 'latest')
        assert is_integer(gas_estimate)
        assert gas_estimate > 0

    def test_eth_getBlockByHash(self, web3: "Web3",
                                empty_block: BlockData) -> None:
        block = web3.eth.getBlock(empty_block['hash'])
        assert block['hash'] == empty_block['hash']

    def test_eth_getBlockByHash_not_found(self, web3: "Web3",
                                          empty_block: BlockData) -> None:
        with pytest.raises(BlockNotFound):
            web3.eth.getBlock(UNKNOWN_HASH)

    def test_eth_getBlockByNumber_with_integer(self, web3: "Web3",
                                               empty_block: BlockData) -> None:
        block = web3.eth.getBlock(empty_block['number'])
        assert block['number'] == empty_block['number']

    def test_eth_getBlockByNumber_latest(self, web3: "Web3",
                                         empty_block: BlockData) -> None:
        current_block_number = web3.eth.blockNumber
        block = web3.eth.getBlock('latest')
        assert block['number'] == current_block_number

    def test_eth_getBlockByNumber_not_found(self, web3: "Web3",
                                            empty_block: BlockData) -> None:
        with pytest.raises(BlockNotFound):
            web3.eth.getBlock(BlockNumber(12345))

    def test_eth_getBlockByNumber_pending(self, web3: "Web3",
                                          empty_block: BlockData) -> None:
        current_block_number = web3.eth.blockNumber
        block = web3.eth.getBlock('pending')
        assert block['number'] == current_block_number + 1

    def test_eth_getBlockByNumber_earliest(self, web3: "Web3",
                                           empty_block: BlockData) -> None:
        genesis_block = web3.eth.getBlock(BlockNumber(0))
        block = web3.eth.getBlock('earliest')
        assert block['number'] == 0
        assert block['hash'] == genesis_block['hash']

    def test_eth_getBlockByNumber_full_transactions(
            self, web3: "Web3", block_with_txn: BlockData) -> None:
        block = web3.eth.getBlock(block_with_txn['number'], True)
        transaction = block['transactions'][0]
        assert transaction['hash'] == block_with_txn['transactions'][
            0]  # type: ignore

    def test_eth_getTransactionByHash(self, web3: "Web3",
                                      mined_txn_hash: HexStr) -> None:
        transaction = web3.eth.getTransaction(mined_txn_hash)
        assert is_dict(transaction)
        assert transaction['hash'] == HexBytes(mined_txn_hash)

    def test_eth_getTransactionByHash_contract_creation(
            self, web3: "Web3", math_contract_deploy_txn_hash: HexStr) -> None:
        transaction = web3.eth.getTransaction(math_contract_deploy_txn_hash)
        assert is_dict(transaction)
        assert transaction['to'] is None, "to field is %r" % transaction['to']

    def test_eth_getTransactionByBlockHashAndIndex(
            self, web3: "Web3", block_with_txn: BlockData,
            mined_txn_hash: HexStr) -> None:
        transaction = web3.eth.getTransactionByBlock(block_with_txn['hash'], 0)
        assert is_dict(transaction)
        assert transaction['hash'] == HexBytes(mined_txn_hash)

    def test_eth_getTransactionByBlockNumberAndIndex(
            self, web3: "Web3", block_with_txn: BlockData,
            mined_txn_hash: HexStr) -> None:
        transaction = web3.eth.getTransactionByBlock(block_with_txn['number'],
                                                     0)
        assert is_dict(transaction)
        assert transaction['hash'] == HexBytes(mined_txn_hash)

    def test_eth_getTransactionReceipt_mined(self, web3: "Web3",
                                             block_with_txn: BlockData,
                                             mined_txn_hash: HexStr) -> None:
        receipt = web3.eth.getTransactionReceipt(mined_txn_hash)
        assert is_dict(receipt)
        assert receipt['blockNumber'] == block_with_txn['number']
        assert receipt['blockHash'] == block_with_txn['hash']
        assert receipt['transactionIndex'] == 0
        assert receipt['transactionHash'] == HexBytes(mined_txn_hash)
        assert is_checksum_address(receipt['to'])
        assert receipt['from'] is not None
        assert is_checksum_address(receipt['from'])

    def test_eth_getTransactionReceipt_unmined(
            self, web3: "Web3",
            unlocked_account_dual_type: ChecksumAddress) -> None:
        txn_hash = web3.eth.sendTransaction({
            'from': unlocked_account_dual_type,
            'to': unlocked_account_dual_type,
            'value': Wei(1),
            'gas': Wei(21000),
            'gasPrice': web3.eth.gasPrice,
        })
        with pytest.raises(TransactionNotFound):
            web3.eth.getTransactionReceipt(txn_hash)

    def test_eth_getTransactionReceipt_with_log_entry(
        self,
        web3: "Web3",
        block_with_txn_with_log: BlockData,
        emitter_contract: "Contract",
        txn_hash_with_log: HexStr,
    ) -> None:
        receipt = web3.eth.getTransactionReceipt(txn_hash_with_log)
        assert is_dict(receipt)
        assert receipt['blockNumber'] == block_with_txn_with_log['number']
        assert receipt['blockHash'] == block_with_txn_with_log['hash']
        assert receipt['transactionIndex'] == 0
        assert receipt['transactionHash'] == HexBytes(txn_hash_with_log)

        assert len(receipt['logs']) == 1
        log_entry = receipt['logs'][0]

        assert log_entry['blockNumber'] == block_with_txn_with_log['number']
        assert log_entry['blockHash'] == block_with_txn_with_log['hash']
        assert log_entry['logIndex'] == 0
        assert is_same_address(log_entry['address'], emitter_contract.address)
        assert log_entry['transactionIndex'] == 0
        assert log_entry['transactionHash'] == HexBytes(txn_hash_with_log)

    def test_eth_getUncleByBlockHashAndIndex(self, web3: "Web3") -> None:
        # TODO: how do we make uncles....
        pass

    def test_eth_getUncleByBlockNumberAndIndex(self, web3: "Web3") -> None:
        # TODO: how do we make uncles....
        pass

    def test_eth_newFilter(self, web3: "Web3") -> None:
        filter = web3.eth.filter({})

        changes = web3.eth.getFilterChanges(filter.filter_id)
        assert is_list_like(changes)
        assert not changes

        logs = web3.eth.getFilterLogs(filter.filter_id)
        assert is_list_like(logs)
        assert not logs

        result = web3.eth.uninstallFilter(filter.filter_id)
        assert result is True

    def test_eth_newBlockFilter(self, web3: "Web3") -> None:
        filter = web3.eth.filter('latest')
        assert is_string(filter.filter_id)

        changes = web3.eth.getFilterChanges(filter.filter_id)
        assert is_list_like(changes)
        assert not changes

        # TODO: figure out why this fails in go-ethereum
        # logs = web3.eth.getFilterLogs(filter.filter_id)
        # assert is_list_like(logs)
        # assert not logs

        result = web3.eth.uninstallFilter(filter.filter_id)
        assert result is True

    def test_eth_newPendingTransactionFilter(self, web3: "Web3") -> None:
        filter = web3.eth.filter('pending')
        assert is_string(filter.filter_id)

        changes = web3.eth.getFilterChanges(filter.filter_id)
        assert is_list_like(changes)
        assert not changes

        # TODO: figure out why this fails in go-ethereum
        # logs = web3.eth.getFilterLogs(filter.filter_id)
        # assert is_list_like(logs)
        # assert not logs

        result = web3.eth.uninstallFilter(filter.filter_id)
        assert result is True

    def test_eth_getLogs_without_logs(
            self, web3: "Web3", block_with_txn_with_log: BlockData) -> None:
        # Test with block range

        filter_params: FilterParams = {
            "fromBlock": BlockNumber(0),
            "toBlock": BlockNumber(block_with_txn_with_log['number'] - 1),
        }
        result = web3.eth.getLogs(filter_params)
        assert len(result) == 0

        # the range is wrong
        filter_params = {
            "fromBlock": block_with_txn_with_log['number'],
            "toBlock": BlockNumber(block_with_txn_with_log['number'] - 1),
        }
        result = web3.eth.getLogs(filter_params)
        assert len(result) == 0

        # Test with `address`

        # filter with other address
        filter_params = {
            "fromBlock": BlockNumber(0),
            "address": UNKNOWN_ADDRESS,
        }
        result = web3.eth.getLogs(filter_params)
        assert len(result) == 0

        # Test with multiple `address`

        # filter with other address
        filter_params = {
            "fromBlock": BlockNumber(0),
            "address": [UNKNOWN_ADDRESS, UNKNOWN_ADDRESS],
        }
        result = web3.eth.getLogs(filter_params)
        assert len(result) == 0

    def test_eth_getLogs_with_logs(
        self,
        web3: "Web3",
        block_with_txn_with_log: BlockData,
        emitter_contract_address: ChecksumAddress,
        txn_hash_with_log: HexStr,
    ) -> None:
        def assert_contains_log(result: Sequence[LogReceipt]) -> None:
            assert len(result) == 1
            log_entry = result[0]
            assert log_entry['blockNumber'] == block_with_txn_with_log[
                'number']
            assert log_entry['blockHash'] == block_with_txn_with_log['hash']
            assert log_entry['logIndex'] == 0
            assert is_same_address(log_entry['address'],
                                   emitter_contract_address)
            assert log_entry['transactionIndex'] == 0
            assert log_entry['transactionHash'] == HexBytes(txn_hash_with_log)

        # Test with block range

        # the range includes the block where the log resides in
        filter_params: FilterParams = {
            "fromBlock": block_with_txn_with_log['number'],
            "toBlock": block_with_txn_with_log['number'],
        }
        result = web3.eth.getLogs(filter_params)
        assert_contains_log(result)

        # specify only `from_block`. by default `to_block` should be 'latest'
        filter_params = {
            "fromBlock": BlockNumber(0),
        }
        result = web3.eth.getLogs(filter_params)
        assert_contains_log(result)

        # Test with `address`

        # filter with emitter_contract.address
        filter_params = {
            "fromBlock": BlockNumber(0),
            "address": emitter_contract_address,
        }

    def test_eth_getLogs_with_logs_topic_args(
        self,
        web3: "Web3",
        block_with_txn_with_log: BlockData,
        emitter_contract_address: ChecksumAddress,
        txn_hash_with_log: HexStr,
    ) -> None:
        def assert_contains_log(result: Sequence[LogReceipt]) -> None:
            assert len(result) == 1
            log_entry = result[0]
            assert log_entry['blockNumber'] == block_with_txn_with_log[
                'number']
            assert log_entry['blockHash'] == block_with_txn_with_log['hash']
            assert log_entry['logIndex'] == 0
            assert is_same_address(log_entry['address'],
                                   emitter_contract_address)
            assert log_entry['transactionIndex'] == 0
            assert log_entry['transactionHash'] == HexBytes(txn_hash_with_log)

        # Test with None event sig

        filter_params: FilterParams = {
            "fromBlock":
            BlockNumber(0),
            "topics": [
                None,
                HexStr(
                    '0x000000000000000000000000000000000000000000000000000000000000d431'
                )
            ],
        }

        result = web3.eth.getLogs(filter_params)
        assert_contains_log(result)

        # Test with None indexed arg
        filter_params = {
            "fromBlock":
            BlockNumber(0),
            "topics": [
                HexStr(
                    '0x057bc32826fbe161da1c110afcdcae7c109a8b69149f727fc37a603c60ef94ca'
                ), None
            ],
        }
        result = web3.eth.getLogs(filter_params)
        assert_contains_log(result)

    def test_eth_getLogs_with_logs_none_topic_args(self, web3: "Web3") -> None:
        # Test with None overflowing
        filter_params: FilterParams = {
            "fromBlock": BlockNumber(0),
            "topics": [None, None, None],
        }

        result = web3.eth.getLogs(filter_params)
        assert len(result) == 0

    def test_eth_call_old_contract_state(
            self, web3: "Web3", math_contract: "Contract",
            unlocked_account: ChecksumAddress) -> None:
        start_block = web3.eth.getBlock('latest')
        block_num = start_block["number"]
        block_hash = start_block["hash"]

        math_contract.functions.increment().transact(
            {'from': unlocked_account})

        # This isn't an incredibly convincing test since we can't mine, and
        # the default resolved block is latest, So if block_identifier was ignored
        # we would get the same result. For now, we mostly depend on core tests.
        # Ideas to improve this test:
        #  - Enable on-demand mining in more clients
        #  - Increment the math contract in all of the fixtures, and check the value in an old block
        block_hash_call_result = math_contract.functions.counter().call(
            block_identifier=block_hash)
        block_num_call_result = math_contract.functions.counter().call(
            block_identifier=block_num)
        latest_call_result = math_contract.functions.counter().call(
            block_identifier='latest')
        default_call_result = math_contract.functions.counter().call()
        pending_call_result = math_contract.functions.counter().call(
            block_identifier='pending')

        assert block_hash_call_result == 0
        assert block_num_call_result == 0
        assert latest_call_result == 0
        assert default_call_result == 0

        if pending_call_result != 1:
            raise AssertionError("pending call result was %d instead of 1" %
                                 pending_call_result)

    def test_eth_uninstallFilter(self, web3: "Web3") -> None:
        filter = web3.eth.filter({})
        assert is_string(filter.filter_id)

        success = web3.eth.uninstallFilter(filter.filter_id)
        assert success is True

        failure = web3.eth.uninstallFilter(filter.filter_id)
        assert failure is False

    def test_eth_getTransactionFromBlock_deprecation(
            self, web3: "Web3", block_with_txn: BlockData) -> None:
        with pytest.raises(DeprecationWarning):
            web3.eth.getTransactionFromBlock(block_with_txn['hash'], 0)

    def test_eth_getCompilers_deprecation(self, web3: "Web3") -> None:
        with pytest.raises(DeprecationWarning):
            web3.eth.getCompilers()

    def test_eth_submitHashrate(self, web3: "Web3") -> None:
        # node_id from EIP 1474: https://github.com/ethereum/EIPs/pull/1474/files
        node_id = HexStr(
            '59daa26581d0acd1fce254fb7e85952f4c09d0915afd33d3886cd914bc7d283c')
        result = web3.eth.submitHashrate(5000, node_id)
        assert result is True

    def test_eth_submitWork(self, web3: "Web3") -> None:
        nonce = 1
        pow_hash = HexStr(
            '0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef'
        )
        mix_digest = HexStr(
            '0xD1FE5700000000000000000000000000D1FE5700000000000000000000000000'
        )
        result = web3.eth.submitWork(nonce, pow_hash, mix_digest)
        assert result is False
示例#9
0
 def test_eth_getTransactionByHash(self, web3: "Web3",
                                   mined_txn_hash: HexStr) -> None:
     transaction = web3.eth.getTransaction(mined_txn_hash)
     assert is_dict(transaction)
     assert transaction['hash'] == HexBytes(mined_txn_hash)
示例#10
0
def encode_abi(web3, abi, arguments, vmtype, data=None, setabi=None):
    arguments = list(arguments)
    if vmtype == 1:
        inputlength = len(abi['inputs'])
        if inputlength == len(arguments):
            if arguments:
                arrinputs = abi['inputs']
                paramabi = encodeparameters(arrinputs, arguments, setabi)
            else:
                paramabi = []
        else:
            raise Exception(
                'The number of arguments is not matching the methods required number.'
                'You need to pass {} arguments.'.format(inputlength))
        magicnum = ['00', '61', '73', '6d']
        paramabi.insert(0, fnv1_64(bytes(abi['name'], 'utf8')))
        if abi['type'] == 'constructor':
            if data:
                data1 = bytes.fromhex(str(data, encoding='utf8'))
                deploydata = rlp.encode([data1, rlp.encode(paramabi)])
                encodata = ''.join(magicnum) + deploydata.hex()
                return '0x' + encodata
            else:
                return '0x' + rlp.encode(paramabi).hex()
        else:
            encodata = rlp.encode(paramabi).hex()
            return '0x' + encodata

    else:
        argument_types = get_abi_input_types(abi)
        for j in range(len(argument_types)):
            if argument_types[j]:
                if argument_types[j] == 'address':
                    hrpgot, data1 = bech32.decode(arguments[j][:3],
                                                  arguments[j])
                    addr = to_checksum_address(bytes(data1))
                    arguments[j] = addr  # .split(",")
                elif argument_types[j] == 'address[]':
                    for i in range(len(arguments[j])):
                        hrpgot, data1 = bech32.decode(arguments[j][i][:3],
                                                      arguments[j][i])
                        addr = to_checksum_address(bytes(data1))
                        arguments[j][i] = addr

        if not check_if_arguments_can_be_encoded(abi, arguments, {}):
            raise TypeError(
                "One or more arguments could not be encoded to the necessary "
                "ABI type.  Expected types are: {0}".format(
                    ', '.join(argument_types), ))

        try:
            normalizers = [
                abi_ens_resolver(web3),
                abi_address_to_hex,
                abi_bytes_to_bytes,
                abi_string_to_text,
            ]
            normalized_arguments = map_abi_data(
                normalizers,
                argument_types,
                arguments,
            )
            encoded_arguments = eth_abi_encode_abi(
                argument_types,
                normalized_arguments,
            )
        except EncodingError as e:
            raise TypeError(
                "One or more arguments could not be encoded to the necessary "
                "ABI type: {0}".format(str(e)))

        if data:
            return to_hex(HexBytes(data) + encoded_arguments)
        else:
            return encode_hex(encoded_arguments)
示例#11
0
def wasmevent_decode(hrp, types, data):
    if isinstance(data, HexBytes) or isinstance(data, bytes):
        bufs = detail_decode_data(rlp.decode(data))
    else:
        bufs = data
    data1 = []
    if (not any(bufs)) and ('int' in types):
        bufs = ['0']
    if (not isinstance(bufs, tuple)) and (not isinstance(types, tuple)):
        buf = bufs
        type = types
        if type == 'string':
            tem = []
            if isinstance(buf, list):
                if not isinstance(buf[0], list):
                    for i in buf:
                        tem.append(bytes.decode(HexBytes(i)))
                    data1 = ''.join(tem)
                else:
                    data1 = [
                        wasmevent_decode(hrp, {
                            'type': type,
                            'name': ''
                        }, j) for j in buf
                    ]
            elif isinstance(buf, str):
                data1 = bytes.decode(HexBytes(buf))
            elif isinstance(buf, tuple):
                data1 = [
                    wasmevent_decode(hrp, {
                        'type': type,
                        'name': ''
                    }, j) for j in buf
                ]
        elif type.startswith('uint') and not type.endswith(']'):
            digit = 0
            if len(buf) <= 1:
                data1 = int(buf[0], 16)
            else:
                for i in range(len(buf)):
                    digit += int(buf[i], 16) * (256**(len(buf) - 1 - i))
                data1 = digit
        elif type == 'bool':
            if not buf:
                data1 = False
            elif int(buf[0], 16):
                data1 = True
            else:
                data1 = False
        elif type in ['int8', 'int16', 'int32', 'int64']:
            if isinstance(buf, list):
                buf = ''.join(buf)
            temp = int(buf, 16)
            data1 = (temp >> 1) ^ (temp & 1) * (-1)
        elif type == 'float':
            data1 = struct.unpack('>f', HexBytes(buf))
        elif type == 'double':
            data1 = struct.unpack('>d', HexBytes(buf))
        elif type.endswith(']'):
            lasti = type.rindex('[')
            vectype = type[0:lasti]
            if vectype == 'uint8':
                data1 = buf
            else:
                data1 = [
                    wasmevent_decode(hrp, {
                        'type': vectype,
                        'name': ''
                    }, i) for i in buf
                ]
        elif type.startswith('FixedHash'):
            data1 = '0x' + tostring_hex(buf)
            if type.endswith('<20>'):
                temp = []
                try:
                    temp = tobech32address(hrp, data1)
                except:
                    raise (
                        'wasmdecode error ! can not match FixedHash<20> type !'
                    )
                finally:
                    data1 = temp
    else:
        if len(bufs) != len(types):
            if len(bufs[0]) == len(types):
                data1 = []
                for i in range(len(bufs[0])):
                    buf = bufs[0][i]
                    type = types[i]
                    data1.append(wasmevent_decode(hrp, type, buf))
        else:
            data1 = []
            for i in range(len(bufs)):
                buf = bufs[i]
                type = types[i]
                data1.append(wasmevent_decode(hrp, type, buf))
    return data1
示例#12
0
def wasmdecode_abi(hrp, types, data, setabi=None):
    if isinstance(data, HexBytes) or isinstance(data, bytes):
        buf = detail_decode_data(rlp.decode(data))
    else:
        buf = data
    type = types['type']
    name = types['name']
    if (not any(buf)) and ('int' in type):
        buf = ['0']
    if type == 'string':
        tem = []
        if isinstance(buf, list):
            if not isinstance(buf[0], list):
                for i in buf:
                    tem.append(bytes.decode(HexBytes(i)))
                data1 = ''.join(tem)
            else:
                data1 = [
                    wasmdecode_abi(hrp, {
                        'type': type,
                        'name': ''
                    }, j, setabi) for j in buf
                ]
        elif isinstance(buf, str):
            data1 = bytes.decode(HexBytes(buf))
        elif isinstance(buf, tuple):
            data1 = [
                wasmdecode_abi(hrp, {
                    'type': type,
                    'name': ''
                }, j, setabi) for j in buf
            ]

    elif type.startswith('uint') and not type.endswith(']'):
        digit = 0
        if len(buf) <= 1:
            data1 = int(buf[0], 16)
        else:
            for i in range(len(buf)):
                digit += int(buf[i], 16) * (256**(len(buf) - 1 - i))
            data1 = digit
    elif type == 'bool':
        if not buf:
            data1 = False
        elif int(buf[0], 16):
            data1 = True
        else:
            data1 = False
    elif type in ['int8', 'int16', 'int32', 'int64']:
        if isinstance(buf, list):
            buf = ''.join(buf)
        temp = int(buf, 16)
        data1 = (temp >> 1) ^ (temp & 1) * (-1)
    elif type == 'float':
        data1 = struct.unpack('>f', HexBytes(buf))
    elif type == 'double':
        data1 = struct.unpack('>d', HexBytes(buf))
    elif type.endswith(']'):
        lasti = type.rindex('[')
        vectype = type[0:lasti]
        if vectype == 'uint8':
            data1 = buf
        else:
            data1 = [
                wasmdecode_abi(hrp, {
                    'type': vectype,
                    'name': ''
                }, i, setabi) for i in buf
            ]

    elif type.startswith('list'):
        i1 = type.index('<')
        i2 = type.index('>')
        itype = type[i1 + 1:i2]
        if isinstance(buf, tuple) and len(buf) <= 1:
            buf = buf[0]
        data1 = [
            wasmdecode_abi(hrp, {
                'type': itype,
                'name': ''
            }, j, setabi) for j in buf
        ]
    elif type.startswith('map'):
        i1 = type.index('<')
        i2 = type.index(',')
        i3 = type.index('>')
        ktype = type[i1 + 1:i2]
        vtype = type[i2 + 1:i3]
        data1 = []
        for j in range(len(buf)):
            if len(buf[j]) <= 1 and len(buf[j][0]) >= 2:
                kvalue = wasmdecode_abi(hrp, {
                    'type': ktype,
                    'name': ''
                }, buf[j][0][0], setabi)
                vvalue = wasmdecode_abi(hrp, {
                    'type': vtype,
                    'name': ''
                }, buf[j][0][1], setabi)
            else:
                kvalue = wasmdecode_abi(hrp, {
                    'type': ktype,
                    'name': ''
                }, buf[j][0], setabi)
                vvalue = wasmdecode_abi(hrp, {
                    'type': vtype,
                    'name': ''
                }, buf[j][1], setabi)
            data1.append([kvalue, vvalue])
    elif type.startswith('pair'):
        i1 = type.index('<')
        i2 = type.index(',')
        i3 = type.index('>')
        ktype = type[i1 + 1:i2]
        vtype = type[i2 + 1:i3]
        data1 = [
            wasmdecode_abi(hrp, {
                'type': ktype,
                'name': ''
            }, buf[0], setabi),
            wasmdecode_abi(hrp, {
                'type': vtype,
                'name': ''
            }, buf[1], setabi)
        ]
    elif type.startswith('set'):
        i1 = type.index('<')
        i2 = type.index('>')
        stype = type[i1 + 1:i2]
        if isinstance(buf, tuple) and len(buf) <= 1:
            buf = buf[0]
        data1 = [
            wasmdecode_abi(hrp, {
                'type': stype,
                'name': ''
            }, j, setabi) for j in buf
        ]
        data1 = set(data1)
    elif type == 'struct':
        structtype = [
            item for item in setabi
            if item['type'] == 'struct' and item['name'] == name
        ]
        if not structtype:
            raise Exception('can not find struct in {} .'.format(name))
        else:
            data1 = [0 for x in range(len(structtype[0]['inputs']))]
            for i in range(len(structtype[0]['inputs'])):
                data1[i] = wasmdecode_abi(hrp, structtype[0]['inputs'][i],
                                          buf[i], setabi)

    elif type.startswith('FixedHash'):
        data1 = '0x' + tostring_hex(buf)
        if type.endswith('<20>'):
            temp = []
            try:
                temp = tobech32address(hrp, data1)
            except:
                raise ('wasmdecode error ! can not match FixedHash<20> type !')
            finally:
                data1 = temp

    else:
        structtype = [item for item in setabi if item['name'] == type]
        if not structtype:
            raise Exception('can not find struct through {} .'.format(type))
        else:
            data1 = [0 for x in range(len(structtype[0]['inputs']))]
            for i in range(len(structtype[0]['inputs'])):
                data1[i] = wasmdecode_abi(hrp, structtype[0]['inputs'][i],
                                          buf[i], setabi)

    return data1
示例#13
0
 def get_prep_value(self, value: ChecksumAddress) -> Optional[bytes]:
     if value:
         return HexBytes(self.to_python(value))
示例#14
0
 def from_db_value(self, value: memoryview, expression,
                   connection) -> Optional[bytes]:
     if value:
         return HexBytes(value.tobytes()).hex()
示例#15
0
class Web3ModuleTest:
    def test_web3_clientVersion(self, web3):
        client_version = web3.version.node
        self._check_web3_clientVersion(client_version)

    def _check_web3_clientVersion(self, client_version):
        raise NotImplementedError("Must be implemented by subclasses")

    # Contract that calculated test values can be found at
    # https://kovan.etherscan.io/address/0xb9be06f5b99372cf9afbccadbbb9954ccaf7f4bb#code
    @pytest.mark.parametrize(
        'types,values,expected',
        (
            (
                ['bool'],
                [True],
                HexBytes("0x5fe7f977e71dba2ea1a68e21057beebb9be2ac30c6410aa38d4f3fbe41dcffd2"),
            ),
            (
                ['uint8', 'uint8', 'uint8'],
                [97, 98, 99],
                HexBytes("0x4e03657aea45a94fc7d47ba826c8d667c0d1e6e33a64a036ec44f58fa12d6c45"),
            ),
            (
                ['uint248'],
                [30],
                HexBytes("0x30f95d210785601eb33ae4d53d405b26f920e765dff87cca8e9a4aec99f82671"),
            ),
            (
                ['bool', 'uint16'],
                [True, 299],
                HexBytes("0xed18599ccd80ee9fae9a28b0e34a5573c3233d7468f808fd659bc171cf0b43bd"),
            ),
            (
                ['int256'],
                [-10],
                HexBytes("0xd6fb717f7e270a360f5093ce6a7a3752183e89c9a9afe5c0cb54b458a304d3d5"),
            ),
            (
                ['int256'],
                [10],
                HexBytes("0xc65a7bb8d6351c1cf70c95a316cc6a92839c986682d98bc35f958f4883f9d2a8"),
            ),
            (
                ['int8', 'uint8'],
                [-10, 18],
                HexBytes("0x5c6ab1e634c08d9c0f4df4d789e8727943ef010dd7ca8e3c89de197a26d148be"),
            ),
            (
                ['address'],
                ["0x49eddd3769c0712032808d86597b84ac5c2f5614"],
                InvalidAddress,
            ),
            (
                ['address'],
                ["0x49EdDD3769c0712032808D86597B84ac5c2F5614"],
                HexBytes("0x2ff37b5607484cd4eecf6d13292e22bd6e5401eaffcc07e279583bc742c68882"),
            ),
            (
                ['bytes2'],
                ['0x5402'],
                HexBytes("0x4ed9171bda52fca71ab28e7f452bd6eacc3e5a568a47e0fa53b503159a9b8910"),
            ),
            (
                ['bytes3'],
                ['0x5402'],
                HexBytes("0x4ed9171bda52fca71ab28e7f452bd6eacc3e5a568a47e0fa53b503159a9b8910"),
            ),
            (
                ['bytes'],
                [
                    '0x636865636b6c6f6e6762797465737472696e676167'
                    '61696e7374736f6c6964697479736861336861736866756e6374696f6e'
                ],
                HexBytes("0xd78a84d65721b67e4011b10c99dafdedcdcd7cb30153064f773e210b4762e22f"),
            ),
            (
                ['string'],
                ['testing a string!'],
                HexBytes("0xe8c275c0b4070a5ec6cfcb83f0ba394b30ddd283de785d43f2eabfb04bd96747"),
            ),
            (
                ['string', 'bool', 'uint16', 'bytes2', 'address'],
                [
                    'testing a string!',
                    False,
                    299,
                    '0x5402',
                    "0x49eddd3769c0712032808d86597b84ac5c2f5614",
                ],
                InvalidAddress,
            ),
            (
                ['string', 'bool', 'uint16', 'bytes2', 'address'],
                [
                    'testing a string!',
                    False,
                    299,
                    '0x5402',
                    "0x49EdDD3769c0712032808D86597B84ac5c2F5614",
                ],
                HexBytes("0x8cc6eabb25b842715e8ca39e2524ed946759aa37bfb7d4b81829cf5a7e266103"),
            ),
            (
                ['bool[2][]'],
                [[[True, False], [False, True]]],
                HexBytes("0x1eef261f2eb51a8c736d52be3f91ff79e78a9ec5df2b7f50d0c6f98ed1e2bc06"),
            ),
            (
                ['bool[]'],
                [[True, False, True]],
                HexBytes("0x5c6090c0461491a2941743bda5c3658bf1ea53bbd3edcde54e16205e18b45792"),
            ),
            (
                ['uint24[]'],
                [[1, 0, 1]],
                HexBytes("0x5c6090c0461491a2941743bda5c3658bf1ea53bbd3edcde54e16205e18b45792"),
            ),
            (
                ['uint8[2]'],
                [[8, 9]],
                HexBytes("0xc7694af312c4f286114180fd0ba6a52461fcee8a381636770b19a343af92538a"),
            ),
            (
                ['uint256[2]'],
                [[8, 9]],
                HexBytes("0xc7694af312c4f286114180fd0ba6a52461fcee8a381636770b19a343af92538a"),
            ),
            (
                ['uint8[]'],
                [[8]],
                HexBytes("0xf3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee3"),
            ),
            (
                ['address[]'],
                [[
                    "0x49EdDD3769c0712032808D86597B84ac5c2F5614",
                    "0xA6b759bBbf4B59D24acf7E06e79f3a5D104fdCE5",
                ]],
                HexBytes("0xb98565c0c26a962fd54d93b0ed6fb9296e03e9da29d2281ed3e3473109ef7dde"),
            ),
            (
                ['address[]'],
                [[
                    "0x49EdDD3769c0712032808D86597B84ac5c2F5614",
                    "0xa6b759bbbf4b59d24acf7e06e79f3a5d104fdce5",
                ]],
                InvalidAddress,
            ),
        ),
    )
    def test_solidityKeccak(self, web3, types, values, expected):
        if isinstance(expected, type) and issubclass(expected, Exception):
            with pytest.raises(expected):
                web3.solidityKeccak(types, values)
            return

        actual = web3.solidityKeccak(types, values)
        assert actual == expected

    @pytest.mark.parametrize(
        'types, values, expected',
        (
            (
                ['address'],
                ['one.eth'],
                HexBytes("0x2ff37b5607484cd4eecf6d13292e22bd6e5401eaffcc07e279583bc742c68882"),
            ),
            (
                ['address[]'],
                [['one.eth', 'two.eth']],
                HexBytes("0xb98565c0c26a962fd54d93b0ed6fb9296e03e9da29d2281ed3e3473109ef7dde"),
            ),
        ),
    )
    def test_solidityKeccak_ens(self, web3, types, values, expected):
        with ens_addresses(web3, {
            'one.eth': "0x49EdDD3769c0712032808D86597B84ac5c2F5614",
            'two.eth': "0xA6b759bBbf4B59D24acf7E06e79f3a5D104fdCE5",
        }):
            # when called as class method, any name lookup attempt will fail
            with pytest.raises(InvalidAddress):
                Web3.solidityKeccak(types, values)

            # when called as instance method, ens lookups can succeed
            actual = web3.solidityKeccak(types, values)
            assert actual == expected

    @pytest.mark.parametrize(
        'types,values',
        (
            (['address'], ['0xA6b759bBbf4B59D24acf7E06e79f3a5D104fdCE5', True]),
            (['address', 'bool'], ['0xA6b759bBbf4B59D24acf7E06e79f3a5D104fdCE5']),
            ([], ['0xA6b759bBbf4B59D24acf7E06e79f3a5D104fdCE5']),
        )
    )
    def test_solidityKeccak_same_number_of_types_and_values(self, web3, types, values):
        with pytest.raises(ValueError):
            web3.solidityKeccak(types, values)

    def test_is_connected(self, web3):
        assert web3.isConnected()
示例#16
0
 def test_eth_getTransactionByBlockHashAndIndex(
         self, web3: "Web3", block_with_txn: BlockData,
         mined_txn_hash: HexStr) -> None:
     transaction = web3.eth.getTransactionByBlock(block_with_txn['hash'], 0)
     assert is_dict(transaction)
     assert transaction['hash'] == HexBytes(mined_txn_hash)
示例#17
0
def update_eth_pol_status(debug=False):
    # get active ETH->POL transaction

    polygon_transactions = PanamaTransaction.objects.filter(
        type=PanamaTransaction.SWAP_POLYGON,
        from_network=ETHEREUM_NETWORK,
        to_network=POLYGON_NETWORK,
        status__iexact=ETH_POL_STATUS,
    )

    if not polygon_transactions:
        return 0

    # connect to providers
    # try:
    #     network = Network.displayed_objects.get(
    #         title=ETHEREUM_NETWORK,
    #         testnet=TESTNET,
    #     )
    # except Network.DoesNotExist:
    #     logging.error(f"Network {ETHEREUM_NETWORK} with Testnet:{TESTNET} doesn't exist")
    #     return 0

    # try:
    #     w3 = get_infura_provider(provider_url=network.provider_url)
    # except Exception:
    #     logging.error(f'Ethereum->polygon error on provider connection')
    #     return 0
    # w3 = get_infura_provider(provider_url=INFURA_URL)
    # w3 = get_infura_provider(provider_url=INFURA_URL_GOERLI_TESTNET)
    w3 = get_infura_provider(
        provider_url=INFURA_URL if debug else INFURA_URL_GOERLI_TESTNET
    )

    # network = Network.displayed_objects.get(
    #     title=POLYGON_NETWORK,
    #     testnet=TESTNET,
    # )
    # try:
    #     pol_provider = get_infura_provider(provider_url=network.provider_url)
    # except Exception:
    #     return 0
    # pol_provider = get_infura_provider(provider_url=POL_PR_URL)
    # pol_provider = get_infura_provider(provider_url=POL_TEST_PR_URL)
    pol_provider = get_infura_provider(
        provider_url=POL_PR_URL if debug else POL_TEST_PR_URL
    )

    # check status for active transaction on blockchain
    for transaction in polygon_transactions:
        try:

            # get transaction receipt
            receipt = w3.eth.getTransactionReceipt(transaction.transaction_id)

            # magic code from polygon docs ------
            # load some contract
            some_abi = get_abi_by_filename(SOME_ABI_NAME)
            some_contract = pol_provider.eth.contract(
                abi=some_abi,
                address=SOME_ADDRESS,
            )

            # get pol counter (no one know what is it)
            polygon_counter = some_contract.functions.lastStateId().call()

            # get eth counter
            eth_counter = 0
            for log in receipt.logs:
                if log.topics[0] == HexBytes(LOG_ZERO_TOPIC_HASH):
                    eth_counter = int(bytes.hex(log.topics[1]), 16)

            # magic counters check
            if eth_counter:
                if polygon_counter >= eth_counter:
                    transaction.status = ETH_POL_STATUS_COMPLETED
                    transaction.save()

            logging.info(
                'Ethereum -> Polygon second part updating on {}.'.format(
                    transaction.second_transaction_id
                )
            )
        except Exception as exception_error:
            logging.error(
                """
                Ethereum-> Polygon error on {tx_id}.
                Error description:
                {error_message}
                """.format(
                    tx_id=transaction.second_transaction_id,
                    error_message=exception_error.__str__(),
                )
            )

            continue
示例#18
0
def normalize_bytecode(bytecode):
    if bytecode:
        bytecode = HexBytes(bytecode)
    return bytecode
示例#19
0
    def sign_transaction(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, 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

            >>> 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(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.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,
            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,
        })
示例#20
0
    def recoverHash(self, message_hash, vrs=None, signature=None):
        '''
        Get the address of the account that signed the message with the given hash.
        You must specify exactly one of: vrs or signature

        :param message_hash: the hash of the message that you want to verify
        :type message_hash: hex str or bytes or int
        :param vrs: the three pieces generated by an elliptic curve signature
        :type vrs: tuple(v, r, s), each element is hex str, bytes or int
        :param signature: signature bytes concatenated as r+s+v
        :type signature: hex str or bytes or int
        :returns: address of signer, hex-encoded & checksummed
        :rtype: str

        .. code-block:: python

            >>> msg = "I♥SF"
            >>> msghash = '0x1476abb745d423bf09273f1afd887d951181d25adc66c4834a70491911b7f750'
            >>> vrs = (
                  28,
                  '0xe6ca9bba58c88611fad66a6ce8f996908195593807c4b38bd528d2cff09d4eb3',
                  '0x3e5bfbbf4d3e39b1a2fd816a7680c19ebebaf3a141b239934ad43cb33fcec8ce')
            >>> Account.recoverHash(msghash, vrs=vrs)
            '0x5ce9454909639D2D17A3F753ce7d93fa0b9aB12E'

            # All of these recover calls are equivalent:

            # variations on msghash
            >>> msghash = b"\\x14v\\xab\\xb7E\\xd4#\\xbf\\t'?\\x1a\\xfd\\x88}\\x95\\x11\\x81\\xd2Z\\xdcf\\xc4\\x83JpI\\x19\\x11\\xb7\\xf7P"  # noqa: E501
            >>> Account.recoverHash(msghash, vrs=vrs)
            >>> msghash = 0x1476abb745d423bf09273f1afd887d951181d25adc66c4834a70491911b7f750
            >>> Account.recoverHash(msghash, vrs=vrs)

            # variations on vrs
            >>> vrs = (
                  '0x1c',
                  '0xe6ca9bba58c88611fad66a6ce8f996908195593807c4b38bd528d2cff09d4eb3',
                  '0x3e5bfbbf4d3e39b1a2fd816a7680c19ebebaf3a141b239934ad43cb33fcec8ce')
            >>> Account.recoverHash(msghash, vrs=vrs)
            >>> vrs = (
                  b'\\x1c',
                  b'\\xe6\\xca\\x9b\\xbaX\\xc8\\x86\\x11\\xfa\\xd6jl\\xe8\\xf9\\x96\\x90\\x81\\x95Y8\\x07\\xc4\\xb3\\x8b\\xd5(\\xd2\\xcf\\xf0\\x9dN\\xb3',  # noqa: E501
                  b'>[\\xfb\\xbfM>9\\xb1\\xa2\\xfd\\x81jv\\x80\\xc1\\x9e\\xbe\\xba\\xf3\\xa1A\\xb29\\x93J\\xd4<\\xb3?\\xce\\xc8\\xce')  # noqa: E501
            >>> Account.recoverHash(msghash, vrs=vrs)
            >>> vrs = (
                  0x1c,
                  0xe6ca9bba58c88611fad66a6ce8f996908195593807c4b38bd528d2cff09d4eb3,
                  0x3e5bfbbf4d3e39b1a2fd816a7680c19ebebaf3a141b239934ad43cb33fcec8ce)
            >>> Account.recoverHash(msghash, vrs=vrs)

            # variations on signature
            >>> signature = '0xe6ca9bba58c88611fad66a6ce8f996908195593807c4b38bd528d2cff09d4eb33e5bfbbf4d3e39b1a2fd816a7680c19ebebaf3a141b239934ad43cb33fcec8ce1c'  # noqa: E501
            >>> Account.recoverHash(msghash, signature=signature)
            >>> signature = b'\\xe6\\xca\\x9b\\xbaX\\xc8\\x86\\x11\\xfa\\xd6jl\\xe8\\xf9\\x96\\x90\\x81\\x95Y8\\x07\\xc4\\xb3\\x8b\\xd5(\\xd2\\xcf\\xf0\\x9dN\\xb3>[\\xfb\\xbfM>9\\xb1\\xa2\\xfd\\x81jv\\x80\\xc1\\x9e\\xbe\\xba\\xf3\\xa1A\\xb29\\x93J\\xd4<\\xb3?\\xce\\xc8\\xce\\x1c'  # noqa: E501
            >>> Account.recoverHash(msghash, signature=signature)
            >>> signature = 0xe6ca9bba58c88611fad66a6ce8f996908195593807c4b38bd528d2cff09d4eb33e5bfbbf4d3e39b1a2fd816a7680c19ebebaf3a141b239934ad43cb33fcec8ce1c  # noqa: E501
            >>> Account.recoverHash(msghash, signature=signature)
        '''
        hash_bytes = HexBytes(message_hash)
        if len(hash_bytes) != 32:
            raise ValueError("The message hash must be exactly 32-bytes")
        if vrs is not None:
            v, r, s = map(hexstr_if_str(to_int), vrs)
            v_standard = to_standard_v(v)
            signature_obj = self._keys.Signature(vrs=(v_standard, r, s))
        elif signature is not None:
            signature_bytes = HexBytes(signature)
            signature_bytes_standard = to_standard_signature_bytes(
                signature_bytes)
            signature_obj = self._keys.Signature(
                signature_bytes=signature_bytes_standard)
        else:
            raise TypeError(
                "You must supply the vrs tuple or the signature bytes")
        pubkey = signature_obj.recover_public_key_from_msg_hash(hash_bytes)
        return pubkey.to_checksum_address()
示例#21
0
    def test_produce_registry_events_from_blockchain(
            self, mock_get_current_block_no, mock_last_block_number,
            mock_get_contract_instance):
        registry_event_producer = RegistryEventProducer(
            "wss://ropsten.infura.io/ws", Repository(NETWORKS))

        org_created_event_object = Mock()
        event_repository = EventRepository(Repository(NETWORKS))
        org_created_event_object.createFilter = Mock(return_value=Mock(
            get_all_entries=Mock(return_value=[
                AttributeDict({
                    'args':
                    AttributeDict({
                        'orgId':
                        b'snet\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
                    }),
                    'event':
                    'OrganizationCreated',
                    'logIndex':
                    1,
                    'transactionIndex':
                    15,
                    'transactionHash':
                    HexBytes(
                        '0x7934a42442792f6d5a171df218b66161021c885085187719c991ec58d7459821'
                    ),
                    'address':
                    '0x663422c6999Ff94933DBCb388623952CF2407F6f',
                    'blockHash':
                    HexBytes(
                        '0x1da77d63b7d57e0a667ffb9f6d23be92f3ffb5f4b27b39b86c5d75bb167d6779'
                    ),
                    'blockNumber':
                    6243627
                })
            ])))

        mock_get_contract_instance.return_value = Mock(
            events=Mock(organizationCreated=org_created_event_object,
                        abi=[{
                            "type": "event",
                            "name": "organizationCreated"
                        }]))

        mock_last_block_number.return_value = 50
        mock_get_current_block_no.return_value = 50

        blockchain_events = registry_event_producer.produce_event(3)
        assert blockchain_events == [
            AttributeDict({
                'args':
                AttributeDict({
                    'orgId':
                    b'snet\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
                }),
                'event':
                'OrganizationCreated',
                'logIndex':
                1,
                'transactionIndex':
                15,
                'transactionHash':
                HexBytes(
                    '0x7934a42442792f6d5a171df218b66161021c885085187719c991ec58d7459821'
                ),
                'address':
                '0x663422c6999Ff94933DBCb388623952CF2407F6f',
                'blockHash':
                HexBytes(
                    '0x1da77d63b7d57e0a667ffb9f6d23be92f3ffb5f4b27b39b86c5d75bb167d6779'
                ),
                'blockNumber':
                6243627
            })
        ]
示例#22
0
    def signHash(self, message_hash, private_key):
        '''
        Sign the hash provided.

        .. WARNING:: *Never* sign a hash that you didn't generate,
            it can be an arbitrary transaction. For example, it might
            send all of your account's ether to an attacker.

        If you would like compatibility with
        :meth:`w3.eth.sign() <web3.eth.Eth.sign>`
        you can use :meth:`~eth_account.messages.defunct_hash_message`.

        Several other message standards are proposed, but none have a clear
        consensus. You'll need to manually comply with any of those message standards manually.

        :param message_hash: the 32-byte message hash to be signed
        :type message_hash: hex str, bytes or int
        :param private_key: the key to sign the message 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: ~eth_account.datastructures.AttributeDict

        .. code-block:: python

            >>> msg = "I♥SF"
            >>> from eth_account.messages import defunct_hash_message
            >>> msghash = defunct_hash_message(text=msg)
            HexBytes('0x1476abb745d423bf09273f1afd887d951181d25adc66c4834a70491911b7f750')
            >>> key = "0xb25c7db31feed9122727bf0939dc769a96564b2de4c4726d035b36ecf1e5b364"
            >>> Account.signHash(msghash, key)
            {'messageHash': HexBytes('0x1476abb745d423bf09273f1afd887d951181d25adc66c4834a70491911b7f750'),  # noqa: E501
             'r': 104389933075820307925104709181714897380569894203213074526835978196648170704563,
             's': 28205917190874851400050446352651915501321657673772411533993420917949420456142,
             'signature': HexBytes('0xe6ca9bba58c88611fad66a6ce8f996908195593807c4b38bd528d2cff09d4eb33e5bfbbf4d3e39b1a2fd816a7680c19ebebaf3a141b239934ad43cb33fcec8ce1c'),  # noqa: E501
             'v': 28}

            # these are equivalent:
            >>> Account.signHash(
                0x1476abb745d423bf09273f1afd887d951181d25adc66c4834a70491911b7f750,
                key
            )
            >>> Account.signHash(
                "0x1476abb745d423bf09273f1afd887d951181d25adc66c4834a70491911b7f750",
                key
            )
        '''
        msg_hash_bytes = HexBytes(message_hash)
        if len(msg_hash_bytes) != 32:
            raise ValueError("The message hash must be exactly 32-bytes")

        key = self._parsePrivateKey(private_key)

        (v, r, s, eth_signature_bytes) = sign_message_hash(key, msg_hash_bytes)
        return AttributeDict({
            'messageHash': msg_hash_bytes,
            'r': r,
            's': s,
            'v': v,
            'signature': HexBytes(eth_signature_bytes),
        })
示例#23
0
def convert_id_to_number_or_hash(block_id):
    try:
        return int(block_id)
    except ValueError:
        return HexBytes(block_id)
示例#24
0
from vault.eth import sign_transfer
from hexbytes import HexBytes

PRIVATE_KEY = b"\xb2\\}\xb3\x1f\xee\xd9\x12''\xbf\t9\xdcv\x9a\x96VK-\xe4\xc4rm\x03[6\xec\xf1\xe5\xb3d"

FROM_ADDR = '0x5ce9454909639D2D17A3F753ce7d93fa0b9aB12E'


signed = sign_transfer(
    PRIVATE_KEY,
    FROM_ADDR, '0xd3CdA913deB6f67967B99D67aCDFa1712C293601', '10')
repr(signed.rawTransaction)
assert signed.rawTransaction == HexBytes('0xf86c8085202170e40082520894d3cda913deb6f67967b99d67acdfa1712c293601888abcd74d5558e000801ca074cd478946d0599179316473d9c9d04688b8a348b1ecb494509b25f7ba2a1a33a037fc6f9d9f8458c7965f083fdd8946ec9d360176a864c470a4ce9f63c3ef9331')
示例#25
0
    def __init__(self, receipt):
        self.raw_receipt = receipt
        self.transaction_hash = receipt['transactionHash']
        self.gas_used = receipt['gasUsed']
        self.transfers = []
        self.result = None

        receipt_logs = receipt['logs']
        if (receipt_logs is not None) and (len(receipt_logs) > 0):
            self.successful = True
            for receipt_log in receipt_logs:
                if len(receipt_log['topics']) > 0:
                    # $ seth keccak $(seth --from-ascii "Transfer(address,address,uint256)")
                    # 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef
                    if receipt_log['topics'][0] == HexBytes(
                            '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'
                    ):
                        from pymaker.token import ERC20Token
                        transfer_abi = [
                            abi for abi in ERC20Token.abi
                            if abi.get('name') == 'Transfer'
                        ][0]
                        codec = ABICodec(default_registry)
                        event_data = get_event_data(codec, transfer_abi,
                                                    receipt_log)
                        self.transfers.append(
                            Transfer(
                                token_address=Address(event_data['address']),
                                from_address=Address(
                                    event_data['args']['from']),
                                to_address=Address(event_data['args']['to']),
                                value=Wad(event_data['args']['value'])))

                    # $ seth keccak $(seth --from-ascii "Mint(address,uint256)")
                    # 0x0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d4121396885
                    if receipt_log['topics'][0] == HexBytes(
                            '0x0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d4121396885'
                    ):
                        from pymaker.token import DSToken
                        transfer_abi = [
                            abi for abi in DSToken.abi
                            if abi.get('name') == 'Mint'
                        ][0]
                        codec = ABICodec(default_registry)
                        event_data = get_event_data(codec, transfer_abi,
                                                    receipt_log)
                        self.transfers.append(
                            Transfer(
                                token_address=Address(event_data['address']),
                                from_address=Address(
                                    '0x0000000000000000000000000000000000000000'
                                ),
                                to_address=Address(event_data['args']['guy']),
                                value=Wad(event_data['args']['wad'])))

                    # $ seth keccak $(seth --from-ascii "Burn(address,uint256)")
                    # 0xcc16f5dbb4873280815c1ee09dbd06736cffcc184412cf7a71a0fdb75d397ca5
                    if receipt_log['topics'][0] == HexBytes(
                            '0xcc16f5dbb4873280815c1ee09dbd06736cffcc184412cf7a71a0fdb75d397ca5'
                    ):
                        from pymaker.token import DSToken
                        transfer_abi = [
                            abi for abi in DSToken.abi
                            if abi.get('name') == 'Burn'
                        ][0]
                        codec = ABICodec(default_registry)
                        event_data = get_event_data(codec, transfer_abi,
                                                    receipt_log)
                        self.transfers.append(
                            Transfer(
                                token_address=Address(event_data['address']),
                                from_address=Address(
                                    event_data['args']['guy']),
                                to_address=Address(
                                    '0x0000000000000000000000000000000000000000'
                                ),
                                value=Wad(event_data['args']['wad'])))

        else:
            self.successful = False
                              address_conversion_func):
    return deploy(web3, FixedReflectionContract, address_conversion_func)


@pytest.fixture()
def call_transaction():
    return {
        'data': '0x61bc221a',
        'to': '0xc305c901078781C232A2a521C2aF7980f8385ee9'
    }


@pytest.fixture(params=[
    '0x0406040604060406040604060406040604060406040604060406040604060406',
    '0406040604060406040604060406040604060406040604060406040604060406',
    HexBytes(
        '0406040604060406040604060406040604060406040604060406040604060406'),
])
def bytes32_contract(web3, Bytes32Contract, request, address_conversion_func):
    return deploy(web3,
                  Bytes32Contract,
                  address_conversion_func,
                  args=[request.param])


@pytest.fixture()
def undeployed_math_contract(web3, MathContract, address_conversion_func):
    empty_address = address_conversion_func(
        "0x000000000000000000000000000000000000dEaD")
    _undeployed_math_contract = MathContract(address=empty_address)
    return _undeployed_math_contract
示例#27
0
class Erc20Manager:
    # keccak('Transfer(address,address,uint256)')
    # ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef
    TRANSFER_TOPIC = HexBytes(ERC20_721_TRANSFER_TOPIC)

    def __init__(self, ethereum_client: 'EthereumClient',
                 slow_provider_timeout: int):
        self.ethereum_client = ethereum_client
        self.w3 = ethereum_client.w3
        self.slow_w3 = Web3(
            self.ethereum_client.get_slow_provider(
                timeout=slow_provider_timeout))

    def decode_logs(self, logs: List[Dict[str, Any]]):
        decoded_logs = []
        for log in logs:
            decoded = self._decode_erc20_or_erc721_log(log.data, log.topics)
            if decoded:
                log_copy = dict(log)
                log_copy['args'] = decoded
                decoded_logs.append(log_copy)
        return decoded_logs

    def _decode_erc20_or_erc721_log(
            self, data: bytes,
            topics: List[bytes]) -> Optional[Dict[str, Any]]:
        decoded = self._decode_erc20_log(data, topics)
        if not decoded:
            decoded = self._decode_erc721_log(topics)
        return decoded

    def _decode_erc20_log(self, data: bytes,
                          topics: List[bytes]) -> Optional[Dict[str, Any]]:
        if topics and topics[0] == self.TRANSFER_TOPIC and len(topics) == 3:
            value = eth_abi.decode_single('uint256', HexBytes(data))
            _from, to = [
                Web3.toChecksumAddress(address)
                for address in eth_abi.decode_abi(['address', 'address'],
                                                  b''.join(topics[1:]))
            ]
            return {'from': _from, 'to': to, 'value': value}
        else:
            # Not compliant ERC20 Transfer(address indexed from, address indexed to, uint256 value)
            # Maybe ERC712 Transfer(address indexed from, address indexed to, uint256 indexed tokenId)
            return None

    def _decode_erc721_log(self,
                           topics: List[bytes]) -> Optional[Dict[str, Any]]:
        if topics and topics[0] == self.TRANSFER_TOPIC and len(topics) == 4:
            _from, to, token_id = eth_abi.decode_abi(
                ['address', 'address', 'uint256'], b''.join(topics[1:]))
            _from, to = [
                Web3.toChecksumAddress(address) for address in (_from, to)
            ]
            return {'from': _from, 'to': to, 'tokenId': token_id}
        else:
            # Not compliant ERC20 Transfer(address indexed from, address indexed to, uint256 value)
            # Maybe ERC712 Transfer(address indexed from, address indexed to, uint256 indexed tokenId)
            return None

    def get_balance(self, address: str, erc20_address: str) -> int:
        """
        Get balance of address for `erc20_address`
        :param address: owner address
        :param erc20_address: erc20 token address
        :return: balance
        """
        return get_erc20_contract(
            self.w3, erc20_address).functions.balanceOf(address).call()

    def get_balances(
            self, address: str,
            erc20_addresses: List[str]) -> List[Dict[str, Union[str, int]]]:
        # Build ether `eth_getBalance` query
        balance_query = {
            "jsonrpc": "2.0",
            "method": "eth_getBalance",
            "params": [address, "latest"],
            "id": 0
        }
        queries = [balance_query]

        # Build tokens `balanceOf` query
        for i, erc20_address in enumerate(erc20_addresses):
            queries.append({
                "jsonrpc":
                "2.0",
                "method":
                "eth_call",
                "params": [
                    {
                        "to":
                        erc20_address,  # Balance of
                        "data":
                        "0x70a08231" +
                        '{:0>64}'.format(address.replace('0x', '').lower())
                    },
                    "latest"
                ],
                "id":
                i + 1
            })
        response = requests.post(self.ethereum_client.ethereum_node_url,
                                 json=queries)
        balances = []
        for token_address, data in zip([None] + erc20_addresses,
                                       response.json()):
            balances.append({
                'token_address':
                token_address,
                'balance':
                0 if data['result'] == '0x' else int(data['result'], 16)
            })
        return balances

    def get_name(self, erc20_address: str) -> str:
        erc20 = get_erc20_contract(self.w3, erc20_address)
        data = erc20.functions.name().buildTransaction({
            'gas': 0,
            'gasPrice': 0
        })['data']
        result = self.w3.eth.call({'to': erc20_address, 'data': data})
        return decode_string_or_bytes32(result)

    def get_symbol(self, erc20_address: str) -> str:
        erc20 = get_erc20_contract(self.w3, erc20_address)
        data = erc20.functions.symbol().buildTransaction({
            'gas': 0,
            'gasPrice': 0
        })['data']
        result = self.w3.eth.call({'to': erc20_address, 'data': data})
        return decode_string_or_bytes32(result)

    def get_decimals(self, erc20_address: str) -> int:
        erc20 = get_erc20_contract(self.w3, erc20_address)
        return erc20.functions.decimals().call()

    def get_info(self, erc20_address: str) -> Erc20Info:
        """
        Get erc20 information (`name`, `symbol` and `decimals`)
        :param erc20_address:
        :return: Erc20Info
        """
        # We use the `example erc20` as the `erc20 interface` doesn't have `name`, `symbol` nor `decimals`
        try:
            name = self.get_name(erc20_address)
            symbol = self.get_symbol(erc20_address)
            decimals = self.get_decimals(erc20_address)
            return Erc20Info(name, symbol, decimals)
        except (InsufficientDataBytes, ValueError) as e:
            raise InvalidERC20Info from e

    def get_total_transfer_history(
            self,
            addresses: List[str],
            from_block: int = 0,
            to_block: Optional[int] = None,
            token_address: Optional[str] = None) -> List[Dict[str, Any]]:
        """
        Get events for erc20 and erc721 transfers from and to an `address`. We decode it manually
        An example of an erc20 event:
        {'logIndex': 0,
         'transactionIndex': 0,
         'transactionHash': HexBytes('0x4d0f25313603e554e3b040667f7f391982babbd195c7ae57a8c84048189f7794'),
         'blockHash': HexBytes('0x90fa67d848a0eaf3be625235dae28815389f5292d4465c48d1139f0c207f8d42'),
         'blockNumber': 791,
         'address': '0xf7d0Bd47BF3214494E7F5B40E392A25cb4788620',
         'data': '0x000000000000000000000000000000000000000000000000002001f716742000',
         'topics': [HexBytes('0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'),
          HexBytes('0x000000000000000000000000f5984365fca2e3bc7d2e020abb2c701df9070eb7'),
          HexBytes('0x0000000000000000000000001df62f291b2e969fb0849d99d9ce41e2f137006e')],
         'type': 'mined'
         'args': {'from': '0xf5984365FcA2e3bc7D2E020AbB2c701DF9070eB7',
                  'to': '0x1dF62f291b2E969fB0849d99D9Ce41e2F137006e',
                  'value': 9009360000000000
                 }
        }
        An example of an erc721 event
        {'address': '0x6631FcbB50677DfC6c02CCDcc03a8f68Db427a64',
         'blockHash': HexBytes('0x95c71c6c9373e9a8ca2c767dda1cd5083eb6addcce36fc216c9e1f458d6970f9'),
         'blockNumber': 5341681,
         'data': '0x',
         'logIndex': 0,
         'removed': False,
         'topics': [HexBytes('0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'),
          HexBytes('0x0000000000000000000000000000000000000000000000000000000000000000'),
          HexBytes('0x000000000000000000000000b5239c032ab9fb5abfc3903e770a4b6a9095542c'),
          HexBytes('0x0000000000000000000000000000000000000000000000000000000000000063')],
         'transactionHash': HexBytes('0xce8c8af0503e6f8a421345c10cdf92834c95186916a3f5b1437d2bba63d2db9e'),
         'transactionIndex': 0,
         'transactionLogIndex': '0x0',
         'type': 'mined',
         'args': {'from': '0x0000000000000000000000000000000000000000',
                  'to': '0xb5239C032AB9fB5aBFc3903e770A4B6a9095542C',
                  'tokenId': 99
                 }
         }
        :param addresses: Search events `from` and `to` these `addresses`
        :param from_block: Block to start querying from
        :param to_block: Block to stop querying from
        :param token_address: Address of the token
        :return: List of events sorted by blockNumber
        """
        topic_0 = self.TRANSFER_TOPIC.hex()
        addresses_encoded = [
            HexBytes(eth_abi.encode_single('address', address)).hex()
            for address in addresses
        ]
        # Topics for transfer `to` and `from` an address
        topics_from = [topic_0, addresses_encoded]
        topics_to = [topic_0, None, addresses_encoded]
        parameters: Dict[str, Any] = {'fromBlock': from_block}
        if to_block:
            parameters['toBlock'] = to_block
        if token_address:
            parameters['address'] = token_address

        all_events: List[Dict] = []
        # Do the request to `eth_getLogs`
        for topics in (topics_to, topics_from):
            parameters['topics'] = topics
            all_events.extend(self.slow_w3.eth.getLogs(parameters))

        # Decode events. Just pick valid ERC20 Transfer events (ERC721 `Transfer` has the same signature)
        erc20_events = []
        for event in all_events:
            event['args'] = self._decode_erc20_or_erc721_log(
                event['data'], event['topics'])
            if event['args']:
                erc20_events.append(event)
        erc20_events.sort(key=lambda x: x['blockNumber'])
        return erc20_events

    def get_transfer_history(
            self,
            from_block: int,
            to_block: Optional[int] = None,
            from_address: Optional[str] = None,
            to_address: Optional[str] = None,
            token_address: Optional[str] = None) -> List[Dict[str, Any]]:
        """
        DON'T USE, it will fail in some cases until they fix https://github.com/ethereum/web3.py/issues/1351
        Get events for erc20/erc721 transfers. At least one of `from_address`, `to_address` or `token_address` must be
        defined
        An example of decoded event:
        {
            "args": {
                "from": "0x1Ce67Ea59377A163D47DFFc9BaAB99423BE6EcF1",
                "to": "0xaE9E15896fd32E59C7d89ce7a95a9352D6ebD70E",
                "value": 15000000000000000
            },
            "event": "Transfer",
            "logIndex": 42,
            "transactionIndex": 60,
            "transactionHash": "0x71d6d83fef3347bad848e83dfa0ab28296e2953de946ee152ea81c6dfb42d2b3",
            "address": "0xfecA834E7da9D437645b474450688DA9327112a5",
            "blockHash": "0x054de9a496fc7d10303068cbc7ee3e25181a3b26640497859a5e49f0342e7db2",
            "blockNumber": 7265022
        }
        :param from_block: Block to start querying from
        :param to_block: Block to stop querying from
        :param from_address: Address sending the erc20 transfer
        :param to_address: Address receiving the erc20 transfer
        :param token_address: Address of the token
        :return: List of events (decoded)
        :throws: ReadTimeout
        """
        assert from_address or to_address or token_address, 'At least one parameter must be provided'

        erc20 = get_erc20_contract(self.slow_w3)

        argument_filters = {}
        if from_address:
            argument_filters['from'] = from_address
        if to_address:
            argument_filters['to'] = to_address

        return erc20.events.Transfer.createFilter(
            fromBlock=from_block,
            toBlock=to_block,
            address=token_address,
            argument_filters=argument_filters).get_all_entries()

    def send_tokens(self,
                    to: str,
                    amount: int,
                    erc20_address: str,
                    private_key: str,
                    nonce: Optional[int] = None,
                    gas_price: Optional[int] = None,
                    gas: Optional[int] = None) -> bytes:
        """
        Send tokens to address
        :param to:
        :param amount:
        :param erc20_address:
        :param private_key:
        :param nonce:
        :param gas_price:
        :param gas:
        :return: tx_hash
        """
        erc20 = get_erc20_contract(self.w3, erc20_address)
        account = Account.from_key(private_key)
        tx_options = {'from': account.address}
        if nonce:
            tx_options['nonce'] = nonce
        if gas_price:
            tx_options['gasPrice'] = gas_price
        if gas:
            tx_options['gas'] = gas

        tx = erc20.functions.transfer(to, amount).buildTransaction(tx_options)
        return self.ethereum_client.send_unsigned_transaction(
            tx, private_key=private_key)
示例#28
0
    def test_hash_safe_multisig_tx(self):
        # -------- Old version of the contract --------------------------
        expected_hash = HexBytes(
            '0xc9d69a2350aede7978fdee58e702647e4bbdc82168577aa4a43b66ad815c6d1a'
        )
        tx_hash = SafeTx(self.ethereum_client,
                         '0x692a70d2e424a56d2c6c27aa97d1a86395877b3a',
                         '0x5AC255889882aaB35A2aa939679E3F3d4Cea221E',
                         5000000,
                         HexBytes('0x00'),
                         0,
                         50000,
                         100,
                         10000,
                         '0x' + '0' * 40,
                         '0x' + '0' * 40,
                         safe_nonce=67,
                         safe_version='0.1.0').safe_tx_hash
        self.assertEqual(expected_hash, tx_hash)

        expected_hash = HexBytes(
            '0x8ca8db91d72b379193f6e229eb2dff0d0621b6ef452d90638ee3206e9b7349b3'
        )
        tx_hash = SafeTx(self.ethereum_client,
                         '0x692a70d2e424a56d2c6c27aa97d1a86395877b3a',
                         '0x' + '0' * 40,
                         80000000,
                         HexBytes('0x562944'),
                         2,
                         54522,
                         773,
                         22000000,
                         '0x' + '0' * 40,
                         '0x' + '0' * 40,
                         safe_nonce=257000,
                         safe_version='0.1.0').safe_tx_hash
        self.assertEqual(expected_hash, tx_hash)

        # -------- New version of the contract --------------------------
        expected_hash = HexBytes(
            '0x7c60341f3e1b4483575f38e84e97d6b332a2dd55b9290f39e6e26eef29a04fe7'
        )
        tx_hash = SafeTx(self.ethereum_client,
                         '0x692a70d2e424a56d2c6c27aa97d1a86395877b3a',
                         '0x5AC255889882aaB35A2aa939679E3F3d4Cea221E',
                         5000000,
                         HexBytes('0x00'),
                         0,
                         50000,
                         100,
                         10000,
                         '0x' + '0' * 40,
                         '0x' + '0' * 40,
                         safe_nonce=67).safe_tx_hash
        self.assertEqual(expected_hash, tx_hash)

        expected_hash = HexBytes(
            '0xf585279fd867c94738096f4eab964e9e202014d2f0d5155d751099ad85cbe504'
        )
        tx_hash = SafeTx(self.ethereum_client,
                         '0x692a70d2e424a56d2c6c27aa97d1a86395877b3a',
                         '0x' + '0' * 40,
                         80000000,
                         HexBytes('0x562944'),
                         2,
                         54522,
                         773,
                         22000000,
                         '0x' + '0' * 40,
                         '0x' + '0' * 40,
                         safe_nonce=257000).safe_tx_hash
        self.assertEqual(expected_hash, tx_hash)

        safe_create2_tx = self.deploy_test_safe()
        safe_address = safe_create2_tx.safe_address
        # Expected hash must be the same calculated by `getTransactionHash` of the contract
        expected_hash = get_safe_contract(
            self.ethereum_client.w3,
            safe_address).functions.getTransactionHash(
                '0x5AC255889882aaB35A2aa939679E3F3d4Cea221E', 5212459,
                HexBytes(0x00), 1, 123456, 122, 12345, '0x' + '2' * 40,
                '0x' + '2' * 40, 10789).call()
        safe_tx_hash = SafeTx(self.ethereum_client,
                              safe_address,
                              '0x5AC255889882aaB35A2aa939679E3F3d4Cea221E',
                              5212459,
                              HexBytes(0x00),
                              1,
                              123456,
                              122,
                              12345,
                              '0x' + '2' * 40,
                              '0x' + '2' * 40,
                              safe_nonce=10789).safe_tx_hash
        self.assertEqual(HexBytes(expected_hash), safe_tx_hash)
    def test_decode_multisend(self):
        # Change Safe contract master copy and set fallback manager multisend transaction
        safe_contract_address = "0x5B9ea52Aaa931D4EEf74C8aEaf0Fe759434FeD74"
        value = "0"
        operation = MultiSendOperation.CALL.value
        data = HexBytes(
            "0x8d80ff0a0000000000000000000000000000000000000000000000000000000000000020000000000000000000"
            "00000000000000000000000000000000000000000000f2005b9ea52aaa931d4eef74c8aeaf0fe759434fed740000"
            "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
            "000000000000000000000000000000247de7edef00000000000000000000000034cfac646f301356faa8b21e9422"
            "7e3583fe3f5f005b9ea52aaa931d4eef74c8aeaf0fe759434fed7400000000000000000000000000000000000000"
            "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024f0"
            "8a0323000000000000000000000000d5d82b6addc9027b22dca772aa68d5d74cdbdf440000000000000000000000"
            "000000")
        change_master_copy_data = HexBytes(
            "0x7de7edef00000000000000000000000034cfac646f301356faa8b21e94227e3583fe3f5f"
        )
        change_fallback_manager_data = HexBytes(
            "0xf08a0323000000000000000000000000d5d82b6addc9027b22dca772aa68d5d74cd"
            "bdf44")
        tx_decoder = get_tx_decoder()
        expected = [
            {
                "operation": operation,
                "to": safe_contract_address,
                "value": value,
                "data": change_master_copy_data.hex(),
                "data_decoded": {
                    "method":
                    "changeMasterCopy",
                    "parameters": [{
                        "name":
                        "_masterCopy",
                        "type":
                        "address",
                        "value":
                        "0x34CfAC646f301356fAa8B21e94227e3583Fe3F5F",
                    }],
                },
            },
            {
                "operation": operation,
                "to": safe_contract_address,
                "value": value,
                "data": change_fallback_manager_data.hex(),
                "data_decoded": {
                    "method":
                    "setFallbackHandler",
                    "parameters": [{
                        "name":
                        "handler",
                        "type":
                        "address",
                        "value":
                        "0xd5D82B6aDDc9027B22dCA772Aa68D5d74cdBdF44",
                    }],
                },
            },
        ]
        # Get just the multisend object
        self.assertEqual(tx_decoder.decode_multisend_data(data), expected)

        # Now decode all the data
        expected = (
            "multiSend",
            [{
                "name":
                "transactions",
                "type":
                "bytes",
                "value":
                "0x005b9ea52aaa931d4eef74c8aeaf0fe759434fed74000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000247de7edef00000000000000000000000034cfac646f301356faa8b21e94227e3583fe3f5f005b9ea52aaa931d4eef74c8aeaf0fe759434fed7400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024f08a0323000000000000000000000000d5d82b6addc9027b22dca772aa68d5d74cdbdf44",
                "value_decoded": [
                    {
                        "operation": operation,
                        "to": safe_contract_address,
                        "value": value,
                        "data": change_master_copy_data.hex(),
                        "data_decoded": {
                            "method":
                            "changeMasterCopy",
                            "parameters": [{
                                "name":
                                "_masterCopy",
                                "type":
                                "address",
                                "value":
                                "0x34CfAC646f301356fAa8B21e94227e3583Fe3F5F",
                            }],
                        },
                    },
                    {
                        "operation": operation,
                        "to": safe_contract_address,
                        "value": value,
                        "data": change_fallback_manager_data.hex(),
                        "data_decoded": {
                            "method":
                            "setFallbackHandler",
                            "parameters": [{
                                "name":
                                "handler",
                                "type":
                                "address",
                                "value":
                                "0xd5D82B6aDDc9027B22dCA772Aa68D5d74cdBdF44",
                            }],
                        },
                    },
                ],
            }],
        )
        self.assertEqual(tx_decoder.decode_transaction_with_types(data),
                         expected)

        # Safe tx decoder cannot decode it. It would be problematic for the internal tx indexer
        safe_tx_decoder = get_safe_tx_decoder()
        with self.assertRaises(CannotDecode):
            safe_tx_decoder.decode_transaction_with_types(data)
示例#30
0
 def _get_block_hash(self, key: str) -> Optional[HexBytes]:
     address = self.db.get(key)[0]
     return HexBytes(address.decode("utf-8")) if address else None