def signature(self, value):
     """Set the signature."""
     self.signature_ = HexBytes(value).hex() if value is not None else None
Example #2
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_version='1.0.0').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_version='1.0.0').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_version='1.0.0').safe_tx_hash
        self.assertEqual(HexBytes(expected_hash), safe_tx_hash)
Example #3
0
def test_hash(test_case):
    expected = test_case["expected_hash"]
    transaction = TypedTransaction.from_dict(test_case["transaction"])
    hash = transaction.hash()
    actual = HexBytes(hash).hex()
    assert actual == expected
Example #4
0
def eip1167_initcode(_addr):
    addr = HexBytes(_addr)
    pre = HexBytes("0x602D3D8160093D39F3363d3d373d3d3d363d73")
    post = HexBytes("0x5af43d82803e903d91602b57fd5bf3")
    return HexBytes(pre + (addr + HexBytes(0) * (20 - len(addr))) + post)
Example #5
0
def get_encrypt_test_params():
    """
    Params for testing Account#encrypt. Due to not being able to provide fixtures to
    pytest.mark.parameterize, we opt for creating the params in a non-fixture method
    here instead of providing fixtures for the private key and password.
    """
    key = '0x4c0883a69102937d6231471b5dbb6204fe5129617082792ae468d01a3f362318'
    key_bytes = to_bytes(hexstr=key)
    private_key = keys.PrivateKey(HexBytes(key))
    password = '******'

    # 'private_key, password, kdf, iterations, expected_decrypted_key, expected_kdf'
    return [
        (
            key,
            password,
            None,
            None,
            key_bytes,
            'scrypt'
        ),
        (
            private_key,
            password,
            None,
            None,
            private_key.to_bytes(),
            'scrypt'
        ),
        (
            key,
            password,
            'pbkdf2',
            None,
            key_bytes,
            'pbkdf2'
        ),
        (
            key,
            password,
            None,
            1024,
            key_bytes,
            'scrypt'
        ),
        (
            key,
            password,
            'pbkdf2',
            1024,
            key_bytes,
            'pbkdf2'
        ),
        (
            key,
            password,
            'scrypt',
            1024,
            key_bytes,
            'scrypt'
        ),
    ]
Example #6
0
def normalize_bytecode(bytecode):
    if bytecode:
        bytecode = HexBytes(bytecode)
    return bytecode
Example #7
0
def vyper_initcode(runtime_bytecode):
    bytecode_len_hex = hex(len(runtime_bytecode))[2:].rjust(6, "0")
    return HexBytes("0x62" + bytecode_len_hex +
                    "3d81600b3d39f3") + runtime_bytecode
Example #8
0
 def __init__(self, address, account, priv_key):
     self._acct = account
     self.private_key = priv_key
     self.public_key = eth_keys.keys.PrivateKey(
         HexBytes(priv_key)).public_key
     super().__init__(address)
Example #9
0
 def getBlock(self, number):
     """Always return genesis block since this is what we care about in the tests"""
     genesis = (
         b'\xd4\xe5g@\xf8v\xae\xf8\xc0\x10\xb8j@\xd5\xf5gE\xa1\x18\xd0\x90j4'
         b'\xe6\x9a\xec\x8c\r\xb1\xcb\x8f\xa3')
     return {'hash': HexBytes(genesis)}
Example #10
0
 def raise_for_status(self):
     if self.gas_limit is not None and self.ran_out_of_gas:
         raise OutOfGasError()
     elif self.status != TransactionStatusEnum.NO_ERROR:
         txn_hash = HexBytes(self.txn_hash).hex()
         raise TransactionError(message=f"Transaction '{txn_hash}' failed.")
Example #11
0
class MockContractAgent:

    FAKE_TX_HASH = HexBytes(b'FAKE29890FAKE8349804')

    FAKE_RECEIPT = {
        'transactionHash': FAKE_TX_HASH,
        'gasUsed': 1,
        'blockNumber': CURRENT_BLOCK.number,
        'blockHash': HexBytes(b'FAKE43434343FAKE43443434')
    }

    FAKE_CALL_RESULT = 1

    # Internal
    __COLLECTION_MARKER = "contract_api"  # decorator attribute
    __DEFAULTS = {
        CONTRACT_CALL: FAKE_CALL_RESULT,
        CONTRACT_ATTRIBUTE: FAKE_CALL_RESULT,
        TRANSACTION: FAKE_RECEIPT,
    }

    _MOCK_METHODS = list()
    _REAL_METHODS = list()

    # Mock Nucypher Contract API
    contract = Mock()
    contract_address = NULL_ADDRESS

    # Mock Blockchain Interfaces
    registry = Mock()
    blockchain = MOCK_TESTERCHAIN

    def __init__(self, agent_class: Type[EthereumContractAgent]):
        """Bind mock agent attributes to the *subclass* with default values"""
        self.agent_class = agent_class
        self.__setup_mock(agent_class=agent_class)

    def __repr__(self) -> str:
        r = f'Mock{self.agent_class.__name__}(id={id(self)})'
        return r

    def __setup_mock(self, agent_class: Type[Agent]) -> None:

        api_methods: Iterable[Callable] = list(
            self.__collect_contract_api(agent_class=agent_class))
        mock_methods, mock_properties = list(), dict()

        for agent_interface in api_methods:

            # Handle
            try:
                # TODO: #2022: This might be a method also decorated @property
                # Get the inner function of the property
                real_method: Callable = agent_interface.fget  # Handle properties
            except AttributeError:
                real_method = agent_interface

            # Get
            interface = getattr(real_method, self.__COLLECTION_MARKER)
            default_return = self.__DEFAULTS.get(interface)

            # TODO: #2022 Special handling of PropertyMocks?
            # # Setup
            # if interface == CONTRACT_ATTRIBUTE:
            #     mock = PropertyMock()
            #     mock_properties[real_method.__name__] = mock
            # else:
            mock = Mock(return_value=default_return)

            # Mark
            setattr(mock, self.__COLLECTION_MARKER, interface)
            mock_methods.append(mock)

            # Bind
            setattr(self, real_method.__name__, mock)

        self._MOCK_METHODS = mock_methods
        self._REAL_METHODS = api_methods

    def __get_interface_calls(self, interface: Enum) -> List[Callable]:
        predicate = lambda method: bool(method.contract_api == interface)
        interface_calls = list(filter(predicate, self._MOCK_METHODS))
        return interface_calls

    @classmethod
    def __is_contract_method(cls, agent_class: Type[Agent],
                             method_name: str) -> bool:
        method_or_property = getattr(agent_class, method_name)
        try:
            real_method: Callable = method_or_property.fget  # Property (getter)
        except AttributeError:
            real_method: Callable = method_or_property  # Method
        contract_api: bool = hasattr(real_method, cls.__COLLECTION_MARKER)
        return contract_api

    @classmethod
    def __collect_contract_api(
            cls, agent_class: Type[Agent]) -> Generator[Callable, None, None]:
        agent_attrs = dir(agent_class)
        predicate = cls.__is_contract_method
        methods = (getattr(agent_class, name) for name in agent_attrs
                   if predicate(agent_class, name))
        return methods

    #
    # Test Utilities
    #

    @property
    def all_transactions(self) -> List[Callable]:
        interface = TRANSACTION
        transaction_functions = self.__get_interface_calls(interface=interface)
        return transaction_functions

    @property
    def contract_calls(self) -> List[Callable]:
        interface = CONTRACT_CALL
        transaction_functions = self.__get_interface_calls(interface=interface)
        return transaction_functions

    def get_unexpected_transactions(
            self, allowed: Union[Iterable[Callable], None]) -> List[Callable]:
        if allowed:
            predicate = lambda tx: tx not in allowed and tx.called
        else:
            predicate = lambda tx: tx.called
        unexpected_transactions = list(filter(predicate,
                                              self.all_transactions))
        return unexpected_transactions

    def assert_only_transactions(self, allowed: Iterable[Callable]) -> None:
        unexpected_transactions = self.get_unexpected_transactions(
            allowed=allowed)
        assert not bool(unexpected_transactions)

    def assert_no_transactions(self) -> None:
        unexpected_transactions = self.get_unexpected_transactions(
            allowed=None)
        assert not bool(unexpected_transactions)

    def reset(self,
              clear_side_effects: bool = True,
              clear_return_values: bool = True) -> None:
        for mock in self._MOCK_METHODS:
            mock.reset_mock(return_value=clear_return_values,
                            side_effect=clear_side_effects)
            if clear_return_values:
                interface = getattr(mock, self.__COLLECTION_MARKER)
                default_return = self.__DEFAULTS.get(interface)
                mock.return_value = default_return
Example #12
0
def _get_memory(step, idx):
    offset = int(step['stack'][idx], 16) * 2
    length = int(step['stack'][idx - 1], 16) * 2
    return HexBytes("".join(step['memory'])[offset:offset + length])
Example #13
0
    def _expand_trace(self):
        '''Adds the following attributes to each step of the stack trace:

        address: The address executing this contract.
        contractName: The name of the contract.
        fn: The name of the function.
        jumpDepth: Number of jumps made since entering this contract. The
                   initial value is 0.
        source: {
            filename: path to the source file for this step
            offset: Start and end offset associated source code
        }
        '''

        if 'trace' in self.__dict__:
            return
        if self._trace is None:
            self._get_trace()
        self.trace = trace = self._trace
        if not trace or 'fn' in trace[0]:
            coverage.add(self.coverage_hash, {})
            return

        # last_map gives a quick reference of previous values at each depth
        last_map = {
            0: {
                'address': self.receiver.address,
                'contract': self.receiver,
                'name': self.receiver._name,
                'fn': [self._full_name()],
                'jumpDepth': 0,
                'pc_map': self.receiver._build['pcMap']
            }
        }

        coverage_eval = {self.receiver._name: {}}
        active_branches = set()

        for i in range(len(trace)):
            # if depth has increased, tx has called into a different contract
            if trace[i]['depth'] > trace[i - 1]['depth']:
                # get call signature
                stack_idx = -4 if trace[i - 1]['op'] in {'CALL', 'CALLCODE'
                                                         } else -3
                offset = int(trace[i - 1]['stack'][stack_idx], 16) * 2
                sig = HexBytes("".join(trace[i - 1]['memory'])[offset:offset +
                                                               8]).hex()

                # get contract and method name
                address = web3.toChecksumAddress(trace[i -
                                                       1]['stack'][-2][-40:])
                contract = _contracts.find(address)

                # update last_map
                last_map[trace[i]['depth']] = {
                    'address': address,
                    'contract': contract,
                    'name': contract._name,
                    'fn': [f"{contract._name}.{contract.get_method(sig)}"],
                    'jumpDepth': 0,
                    'pc_map': contract._build['pcMap']
                }
                if contract._name not in coverage_eval:
                    coverage_eval[contract._name] = {}

            # update trace from last_map
            last = last_map[trace[i]['depth']]
            trace[i].update({
                'address': last['address'],
                'contractName': last['name'],
                'fn': last['fn'][-1],
                'jumpDepth': last['jumpDepth'],
                'source': False
            })
            pc = last['pc_map'][trace[i]['pc']]
            if 'path' not in pc:
                continue

            trace[i]['source'] = {
                'filename': pc['path'],
                'offset': pc['offset']
            }

            if 'fn' not in pc:
                continue

            # calculate coverage
            if '<string' not in pc['path']:
                if pc['path'] not in coverage_eval[last['name']]:
                    coverage_eval[last['name']][pc['path']] = [
                        set(), set(), set()
                    ]
                if 'statement' in pc:
                    coverage_eval[last['name']][pc['path']][0].add(
                        pc['statement'])
                if 'branch' in pc:
                    if pc['op'] != "JUMPI":
                        active_branches.add(pc['branch'])
                    elif pc['branch'] in active_branches:
                        # false, true
                        key = 1 if trace[i +
                                         1]['pc'] == trace[i]['pc'] + 1 else 2
                        coverage_eval[last['name']][pc['path']][key].add(
                            pc['branch'])
                        active_branches.remove(pc['branch'])

            # ignore jumps with no function - they are compiler optimizations
            if 'jump' not in pc:
                continue

            # jump 'i' is calling into an internal function
            if pc['jump'] == 'i':
                try:
                    last['fn'].append(last['pc_map'][trace[i + 1]['pc']]['fn'])
                    last['jumpDepth'] += 1
                except KeyError:
                    continue
            # jump 'o' is returning from an internal function
            elif pc['jump'] == "o" and last['jumpDepth'] > 0:
                del last['fn'][-1]
                last['jumpDepth'] -= 1
        coverage.add(self.coverage_hash,
                     dict((k, v) for k, v in coverage_eval.items() if v))
    def to_json(
        self,
        include_hash=False,
        include_signature=True,
        include_exchange_address=None,
        for_web3=False,
    ):
        """Get a json representation of the SignedOrder.

        Args:
            include_hash (bool): whether to include the hash field
                (default: False)
            include_signature (bool): whether to include the signature
                (default: True)
            include_exchange_address (bool): whether to include the
                exchange_address field (default: None, which means if set to
                False for web3 and set to True for non-web3 use case)
            for_web3 (bool): whether the value types should be changed
                for calling 0x contracts through web3 library (default:
                False)
        """
        if for_web3:
            if include_exchange_address is None:
                include_exchange_address = False
            order = {
                "makerAddress":
                to_checksum_address(self.maker_address_),
                "takerAddress":
                to_checksum_address(self.taker_address_),
                "feeRecipientAddress":
                to_checksum_address(self.fee_recipient_address_),
                "senderAddress":
                to_checksum_address(self.sender_address_),
                "makerAssetAmount":
                int(self.maker_asset_amount_),
                "takerAssetAmount":
                int(self.taker_asset_amount_),
                "makerFee":
                int(self.maker_fee_),
                "takerFee":
                int(self.taker_fee_),
                "salt":
                int(self.salt_),
                "expirationTimeSeconds":
                int(self.expiration_time_seconds_),
                "makerAssetData":
                HexBytes(self.maker_asset_data_),
                "takerAssetData":
                HexBytes(self.taker_asset_data_),
            }
            if include_hash:
                order["hash"] = HexBytes(self.hash)
            if include_signature:
                order["signature"] = HexBytes(self.signature)
            if include_exchange_address:
                order["exchangeAddress"] = HexBytes(self.exchange_address_)
        else:
            if include_exchange_address is None:
                include_exchange_address = True
            order = {
                "makerAddress": self.maker_address_,
                "takerAddress": self.taker_address_,
                "feeRecipientAddress": self.fee_recipient_address_,
                "senderAddress": self.sender_address_,
                "makerAssetAmount": self.maker_asset_amount_,
                "takerAssetAmount": self.taker_asset_amount_,
                "makerFee": self.maker_fee_,
                "takerFee": self.taker_fee_,
                "salt": self.salt_,
                "expirationTimeSeconds": self.expiration_time_seconds_,
                "makerAssetData": self.maker_asset_data_,
                "takerAssetData": self.taker_asset_data_,
            }
            if include_hash:
                order["hash"] = self.hash
            if include_signature:
                order["signature"] = self.signature_
            if include_exchange_address:
                order["exchangeAddress"] = self.exchange_address_
        return order
    def txs_create_or_update_from_tx_hashes(self, tx_hashes: Collection[Union[str, bytes]]) -> List['EthereumTx']:
        # Search first in database
        ethereum_txs_dict = OrderedDict.fromkeys([HexBytes(tx_hash).hex() for tx_hash in tx_hashes])
        db_ethereum_txs = EthereumTx.objects.filter(tx_hash__in=tx_hashes).exclude(block=None)
        for db_ethereum_tx in db_ethereum_txs:
            ethereum_txs_dict[db_ethereum_tx.tx_hash] = db_ethereum_tx

        # Retrieve from the node the txs missing from database
        tx_hashes_not_in_db = [tx_hash for tx_hash, ethereum_tx in ethereum_txs_dict.items() if not ethereum_tx]
        if not tx_hashes_not_in_db:
            return list(ethereum_txs_dict.values())

        self.ethereum_client = EthereumClientProvider()

        # Get receipts for hashes not in db
        tx_receipts = []
        for tx_hash, tx_receipt in zip(tx_hashes_not_in_db,
                                       self.ethereum_client.get_transaction_receipts(tx_hashes_not_in_db)):
            tx_receipt = tx_receipt or self.ethereum_client.get_transaction_receipt(tx_hash)  # Retry fetching if failed
            if not tx_receipt:
                raise TransactionNotFoundException(f'Cannot find tx-receipt with tx-hash={HexBytes(tx_hash).hex()}')
            elif tx_receipt.get('blockNumber') is None:
                raise TransactionWithoutBlockException(f'Cannot find blockNumber for tx-receipt with '
                                                       f'tx-hash={HexBytes(tx_hash).hex()}')
            else:
                tx_receipts.append(tx_receipt)

        # Get transactions for hashes not in db
        txs = self.ethereum_client.get_transactions(tx_hashes_not_in_db)
        block_numbers = set()
        for tx_hash, tx in zip(tx_hashes_not_in_db, txs):
            tx = tx or self.ethereum_client.get_transaction(tx_hash)  # Retry fetching if failed
            if not tx:
                raise TransactionNotFoundException(f'Cannot find tx with tx-hash={HexBytes(tx_hash).hex()}')
            elif tx.get('blockNumber') is None:
                raise TransactionWithoutBlockException(f'Cannot find blockNumber for tx with '
                                                       f'tx-hash={HexBytes(tx_hash).hex()}')
            block_numbers.add(tx['blockNumber'])

        blocks = self.ethereum_client.get_blocks(block_numbers)
        block_dict = {}
        for block_number, block in zip(block_numbers, blocks):
            block = block or self.ethereum_client.get_block(block_number)  # Retry fetching if failed
            if not block:
                raise BlockNotFoundException(f'Block with number={block_number} was not found')
            assert block_number == block['number']
            block_dict[block['number']] = block

        # Create new transactions or update them if they have no receipt
        current_block_number = self.ethereum_client.current_block_number
        for tx, tx_receipt in zip(txs, tx_receipts):
            block = block_dict.get(tx['blockNumber'])
            confirmed = (current_block_number - block['number']) >= self.eth_reorg_blocks
            ethereum_block: EthereumBlock = EthereumBlock.objects.get_or_create_from_block(block, confirmed=confirmed)
            if HexBytes(ethereum_block.block_hash) != block['hash']:
                raise EthereumBlockHashMismatch(f'Stored block={ethereum_block.number} '
                                                f'with hash={ethereum_block.block_hash} '
                                                f'is not marching retrieved hash={block["hash"].hex()}')
            try:
                ethereum_tx = EthereumTx.objects.get(tx_hash=tx['hash'])
                # For txs stored before being mined
                ethereum_tx.update_with_block_and_receipt(ethereum_block, tx_receipt)
                ethereum_txs_dict[ethereum_tx.tx_hash] = ethereum_tx
            except EthereumTx.DoesNotExist:
                ethereum_tx = EthereumTx.objects.create_from_tx_dict(tx,
                                                                     tx_receipt=tx_receipt,
                                                                     ethereum_block=ethereum_block)
                ethereum_txs_dict[HexBytes(ethereum_tx.tx_hash).hex()] = ethereum_tx
        return list(ethereum_txs_dict.values())
    def __process_decoded_transaction(
            self, internal_tx_decoded: InternalTxDecoded) -> bool:
        """
        Decode internal tx and creates needed models
        :param internal_tx_decoded: InternalTxDecoded to process. It will be set as `processed`
        :return: True if tx could be processed, False otherwise
        """
        internal_tx = internal_tx_decoded.internal_tx
        logger.debug(
            "Start processing InternalTxDecoded in tx-hash=%s",
            HexBytes(internal_tx_decoded.internal_tx.ethereum_tx_id).hex(),
        )

        if internal_tx.gas_used < 1000:
            # When calling a non existing function, fallback of the proxy does not return any error but we can detect
            # this kind of functions due to little gas used. Some of this transactions get decoded as they were
            # valid in old versions of the proxies, like changes to `setup`
            logger.debug(
                "Calling a non existing function, will not process it", )
            return False

        function_name = internal_tx_decoded.function_name
        arguments = internal_tx_decoded.arguments
        contract_address = internal_tx._from
        master_copy = internal_tx.to
        processed_successfully = True

        if function_name == "setup" and contract_address != NULL_ADDRESS:
            # Index new Safes
            logger.debug("Processing Safe setup")
            owners = arguments["_owners"]
            threshold = arguments["_threshold"]
            fallback_handler = arguments.get("fallbackHandler", NULL_ADDRESS)
            nonce = 0
            try:
                safe_contract: SafeContract = SafeContract.objects.get(
                    address=contract_address)
                if (not safe_contract.ethereum_tx_id
                        or not safe_contract.erc20_block_number):
                    safe_contract.ethereum_tx = internal_tx.ethereum_tx
                    safe_contract.erc20_block_number = internal_tx.block_number
                    safe_contract.save(
                        update_fields=["ethereum_tx", "erc20_block_number"])
            except SafeContract.DoesNotExist:
                blocks_one_day = int(24 * 60 * 60 / 15)  # 15 seconds block
                SafeContract.objects.create(
                    address=contract_address,
                    ethereum_tx=internal_tx.ethereum_tx,
                    erc20_block_number=max(
                        internal_tx.block_number - blocks_one_day, 0),
                )
                logger.info("Found new Safe=%s", contract_address)

            self.store_new_safe_status(
                SafeLastStatus(
                    internal_tx=internal_tx,
                    address=contract_address,
                    owners=owners,
                    threshold=threshold,
                    nonce=nonce,
                    master_copy=master_copy,
                    fallback_handler=fallback_handler,
                ),
                internal_tx,
            )
        else:
            safe_last_status = self.get_last_safe_status_for_address(
                contract_address)
            if not safe_last_status:
                # Usually this happens from Safes coming from a not supported Master Copy
                # TODO When archive node is available, build SafeStatus from blockchain status
                logger.debug(
                    "Cannot process trace as `SafeLastStatus` is not found for Safe=%s",
                    contract_address,
                )
                processed_successfully = False
            elif function_name in (
                    "addOwnerWithThreshold",
                    "removeOwner",
                    "removeOwnerWithThreshold",
            ):
                logger.debug("Processing owner/threshold modification")
                safe_last_status.threshold = (arguments["_threshold"]
                                              or safe_last_status.threshold
                                              )  # Event doesn't have threshold
                owner = arguments["owner"]
                if function_name == "addOwnerWithThreshold":
                    safe_last_status.owners.insert(0, owner)
                else:  # removeOwner, removeOwnerWithThreshold
                    self.swap_owner(internal_tx, safe_last_status, owner, None)
                self.store_new_safe_status(safe_last_status, internal_tx)
            elif function_name == "swapOwner":
                logger.debug("Processing owner swap")
                old_owner = arguments["oldOwner"]
                new_owner = arguments["newOwner"]
                self.swap_owner(internal_tx, safe_last_status, old_owner,
                                new_owner)
                self.store_new_safe_status(safe_last_status, internal_tx)
            elif function_name == "changeThreshold":
                logger.debug("Processing threshold change")
                safe_last_status.threshold = arguments["_threshold"]
                self.store_new_safe_status(safe_last_status, internal_tx)
            elif function_name == "changeMasterCopy":
                logger.debug("Processing master copy change")
                # TODO Ban address if it doesn't have a valid master copy
                old_safe_version = self.get_safe_version_from_master_copy(
                    safe_last_status.master_copy)
                safe_last_status.master_copy = arguments["_masterCopy"]
                new_safe_version = self.get_safe_version_from_master_copy(
                    safe_last_status.master_copy)
                if (old_safe_version and new_safe_version
                        and self.is_version_breaking_signatures(
                            old_safe_version, new_safe_version)):
                    # Transactions queued not executed are not valid anymore
                    MultisigTransaction.objects.queued(
                        contract_address).delete()
                self.store_new_safe_status(safe_last_status, internal_tx)
            elif function_name == "setFallbackHandler":
                logger.debug("Setting FallbackHandler")
                safe_last_status.fallback_handler = arguments["handler"]
                self.store_new_safe_status(safe_last_status, internal_tx)
            elif function_name == "setGuard":
                safe_last_status.guard = (arguments["guard"]
                                          if arguments["guard"] != NULL_ADDRESS
                                          else None)
                if safe_last_status.guard:
                    logger.debug("Setting Guard")
                else:
                    logger.debug("Unsetting Guard")
                self.store_new_safe_status(safe_last_status, internal_tx)
            elif function_name == "enableModule":
                logger.debug("Enabling Module")
                safe_last_status.enabled_modules.append(arguments["module"])
                self.store_new_safe_status(safe_last_status, internal_tx)
            elif function_name == "disableModule":
                logger.debug("Disabling Module")
                safe_last_status.enabled_modules.remove(arguments["module"])
                self.store_new_safe_status(safe_last_status, internal_tx)
            elif function_name in {
                    "execTransactionFromModule",
                    "execTransactionFromModuleReturnData",
            }:
                logger.debug("Executing Tx from Module")
                # TODO Add test with previous traces for processing a module transaction
                ethereum_tx = internal_tx.ethereum_tx
                if "module" in arguments:
                    # L2 Safe with event SafeModuleTransaction indexed using events
                    module_address = arguments["module"]
                else:
                    # Regular Safe indexed using tracing
                    # Someone calls Module -> Module calls Safe Proxy -> Safe Proxy delegate calls Master Copy
                    # The trace that is been processed is the last one, so indexer needs to get the previous trace
                    previous_trace = self.ethereum_client.parity.get_previous_trace(
                        internal_tx.ethereum_tx_id,
                        internal_tx.trace_address_as_list,
                        skip_delegate_calls=True,
                    )
                    if not previous_trace:
                        message = (
                            f"Cannot find previous trace for tx-hash={HexBytes(internal_tx.ethereum_tx_id).hex()} "
                            f"and trace-address={internal_tx.trace_address}")
                        logger.warning(message)
                        raise ValueError(message)
                    module_internal_tx = InternalTx.objects.build_from_trace(
                        previous_trace, internal_tx.ethereum_tx)
                    module_address = (module_internal_tx._from
                                      if module_internal_tx else NULL_ADDRESS)
                failed = self.is_module_failed(ethereum_tx, module_address,
                                               contract_address)
                module_data = HexBytes(arguments["data"])
                ModuleTransaction.objects.get_or_create(
                    internal_tx=internal_tx,
                    defaults={
                        "created": internal_tx.timestamp,
                        "safe": contract_address,
                        "module": module_address,
                        "to": arguments["to"],
                        "value": arguments["value"],
                        "data": module_data if module_data else None,
                        "operation": arguments["operation"],
                        "failed": failed,
                    },
                )

            elif function_name == "approveHash":
                logger.debug("Processing hash approval")
                multisig_transaction_hash = arguments["hashToApprove"]
                ethereum_tx = internal_tx.ethereum_tx
                if "owner" in arguments:  # Event approveHash
                    owner = arguments["owner"]
                else:
                    previous_trace = self.ethereum_client.parity.get_previous_trace(
                        internal_tx.ethereum_tx_id,
                        internal_tx.trace_address_as_list,
                        skip_delegate_calls=True,
                    )
                    if not previous_trace:
                        message = (
                            f"Cannot find previous trace for tx-hash={HexBytes(internal_tx.ethereum_tx_id).hex()} and "
                            f"trace-address={internal_tx.trace_address}")
                        logger.warning(message)
                        raise ValueError(message)
                    previous_internal_tx = InternalTx.objects.build_from_trace(
                        previous_trace, internal_tx.ethereum_tx)
                    owner = previous_internal_tx._from
                safe_signature = SafeSignatureApprovedHash.build_for_owner(
                    owner, multisig_transaction_hash)
                (multisig_confirmation,
                 _) = MultisigConfirmation.objects.get_or_create(
                     multisig_transaction_hash=multisig_transaction_hash,
                     owner=owner,
                     defaults={
                         "created": internal_tx.timestamp,
                         "ethereum_tx": ethereum_tx,
                         "signature": safe_signature.export_signature(),
                         "signature_type": safe_signature.signature_type.value,
                     },
                 )
                if not multisig_confirmation.ethereum_tx_id:
                    multisig_confirmation.ethereum_tx = ethereum_tx
                    multisig_confirmation.save(update_fields=["ethereum_tx"])
            elif function_name == "execTransaction":
                logger.debug("Processing transaction execution")
                # Events for L2 Safes store information about nonce
                nonce = (arguments["nonce"]
                         if "nonce" in arguments else safe_last_status.nonce)
                if ("baseGas" in arguments
                    ):  # `dataGas` was renamed to `baseGas` in v1.0.0
                    base_gas = arguments["baseGas"]
                    safe_version = (self.get_safe_version_from_master_copy(
                        safe_last_status.master_copy) or "1.0.0")
                else:
                    base_gas = arguments["dataGas"]
                    safe_version = "0.0.1"
                safe_tx = SafeTx(
                    None,
                    contract_address,
                    arguments["to"],
                    arguments["value"],
                    arguments["data"],
                    arguments["operation"],
                    arguments["safeTxGas"],
                    base_gas,
                    arguments["gasPrice"],
                    arguments["gasToken"],
                    arguments["refundReceiver"],
                    HexBytes(arguments["signatures"]),
                    safe_nonce=nonce,
                    safe_version=safe_version,
                    chain_id=self.ethereum_client.get_chain_id(),
                )
                safe_tx_hash = safe_tx.safe_tx_hash

                ethereum_tx = internal_tx.ethereum_tx

                failed = self.is_failed(ethereum_tx, safe_tx_hash)
                multisig_tx, _ = MultisigTransaction.objects.get_or_create(
                    safe_tx_hash=safe_tx_hash,
                    defaults={
                        "created": internal_tx.timestamp,
                        "safe": contract_address,
                        "ethereum_tx": ethereum_tx,
                        "to": safe_tx.to,
                        "value": safe_tx.value,
                        "data": safe_tx.data if safe_tx.data else None,
                        "operation": safe_tx.operation,
                        "safe_tx_gas": safe_tx.safe_tx_gas,
                        "base_gas": safe_tx.base_gas,
                        "gas_price": safe_tx.gas_price,
                        "gas_token": safe_tx.gas_token,
                        "refund_receiver": safe_tx.refund_receiver,
                        "nonce": safe_tx.safe_nonce,
                        "signatures": safe_tx.signatures,
                        "failed": failed,
                        "trusted": True,
                    },
                )

                # Don't modify created
                if not multisig_tx.ethereum_tx_id:
                    multisig_tx.ethereum_tx = ethereum_tx
                    multisig_tx.failed = failed
                    multisig_tx.signatures = HexBytes(arguments["signatures"])
                    multisig_tx.trusted = True
                    multisig_tx.save(update_fields=[
                        "ethereum_tx", "failed", "signatures", "trusted"
                    ])

                for safe_signature in SafeSignature.parse_signature(
                        safe_tx.signatures, safe_tx_hash):
                    (
                        multisig_confirmation,
                        _,
                    ) = MultisigConfirmation.objects.get_or_create(
                        multisig_transaction_hash=safe_tx_hash,
                        owner=safe_signature.owner,
                        defaults={
                            "created": internal_tx.timestamp,
                            "ethereum_tx": None,
                            "multisig_transaction": multisig_tx,
                            "signature": safe_signature.export_signature(),
                            "signature_type":
                            safe_signature.signature_type.value,
                        },
                    )
                    if multisig_confirmation.signature != safe_signature.signature:
                        multisig_confirmation.signature = (
                            safe_signature.export_signature())
                        multisig_confirmation.signature_type = (
                            safe_signature.signature_type.value)
                        multisig_confirmation.save(
                            update_fields=["signature", "signature_type"])

                safe_last_status.nonce = nonce + 1
                self.store_new_safe_status(safe_last_status, internal_tx)
            elif function_name == "execTransactionFromModule":
                logger.debug("Not processing execTransactionFromModule")
                # No side effects or nonce increasing, but trace will be set as processed
            else:
                processed_successfully = False
                logger.warning(
                    "Cannot process InternalTxDecoded function_name=%s and arguments=%s",
                    function_name,
                    arguments,
                )
        logger.debug("End processing")
        return processed_successfully
Example #17
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]
                        event_data = get_event_data(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]
                        event_data = get_event_data(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]
                        event_data = get_event_data(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
Example #18
0
from eth_typing import (
    ChecksumAddress,
    HexAddress,
    HexStr,
)
from hexbytes import (
    HexBytes, )

ACCEPTABLE_STALE_HOURS = 48

AUCTION_START_GAS_CONSTANT = 25000
AUCTION_START_GAS_MARGINAL = 39000

EMPTY_SHA3_BYTES = HexBytes(b'\0' * 32)
EMPTY_ADDR_HEX = HexAddress(HexStr('0x' + '00' * 20))

REVERSE_REGISTRAR_DOMAIN = 'addr.reverse'

ENS_MAINNET_ADDR = ChecksumAddress(
    HexAddress(HexStr('0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e')))

# --- interface ids --- #

GET_TEXT_INTERFACE_ID = HexStr("0x59d1d43c")
EXTENDED_RESOLVER_INTERFACE_ID = HexStr('0x9061b923')  # ENSIP-10
Example #19
0
def test_create_from_factory(
    get_contract,
    deploy_factory_for,
    w3,
    keccak,
    create2_address_of,
    assert_tx_failed,
    factory_prefix,
):
    code = """
@external
def foo() -> uint256:
    return 123
    """

    prefix_len = len(factory_prefix)
    deployer_code = f"""
created_address: public(address)

@external
def test(target: address):
    self.created_address = create_from_factory(target, code_offset={prefix_len})

@external
def test2(target: address, salt: bytes32):
    self.created_address = create_from_factory(target, code_offset={prefix_len}, salt=salt)
    """

    # deploy a foo so we can compare its bytecode with factory deployed version
    foo_contract = get_contract(code)
    expected_runtime_code = w3.eth.get_code(foo_contract.address)

    f, FooContract = deploy_factory_for(code, initcode_prefix=factory_prefix)

    d = get_contract(deployer_code)

    d.test(f.address, transact={})

    test = FooContract(d.created_address())
    assert w3.eth.get_code(test.address) == expected_runtime_code
    assert test.foo() == 123

    # extcodesize check
    zero_address = "0x" + "00" * 20
    assert_tx_failed(lambda: d.test(zero_address))

    # now same thing but with create2
    salt = keccak(b"vyper")
    d.test2(f.address, salt, transact={})

    test = FooContract(d.created_address())
    assert w3.eth.get_code(test.address) == expected_runtime_code
    assert test.foo() == 123

    # check if the create2 address matches our offchain calculation
    initcode = w3.eth.get_code(f.address)
    initcode = initcode[len(factory_prefix):]  # strip the prefix
    assert HexBytes(test.address) == create2_address_of(
        d.address, salt, initcode)

    # can't collide addresses
    assert_tx_failed(lambda: d.test2(f.address, salt))
Example #20
0
def build_webhook_payload(
    sender: Type[Model],
    instance: Union[TokenTransfer, InternalTx, MultisigConfirmation,
                    MultisigTransaction],
) -> List[Dict[str, Any]]:
    """
    :param sender: Sender type
    :param instance: Sender instance
    :return: A list of webhooks generated from the instance provided
    """
    payloads: List[Dict[str, Any]] = []
    if sender == MultisigConfirmation and instance.multisig_transaction_id:
        payloads = [{
            "address":
            instance.multisig_transaction.safe,  # This could make a db call
            "type":
            WebHookType.NEW_CONFIRMATION.name,
            "owner":
            instance.owner,
            "safeTxHash":
            HexBytes(instance.multisig_transaction.safe_tx_hash).hex(),
        }]
    elif sender == MultisigTransaction:
        payload = {
            "address": instance.safe,
            #  'type': None,  It will be assigned later
            "safeTxHash": HexBytes(instance.safe_tx_hash).hex(),
        }
        if instance.executed:
            payload["type"] = WebHookType.EXECUTED_MULTISIG_TRANSACTION.name
            payload["failed"] = json.dumps(
                instance.failed)  # Firebase only accepts strings
            payload["txHash"] = HexBytes(instance.ethereum_tx_id).hex()
        else:
            payload["type"] = WebHookType.PENDING_MULTISIG_TRANSACTION.name
        payloads = [payload]
    elif sender == InternalTx and instance.is_ether_transfer:  # INCOMING_ETHER
        incoming_payload = {
            "address": instance.to,
            "type": WebHookType.INCOMING_ETHER.name,
            "txHash": HexBytes(instance.ethereum_tx_id).hex(),
            "value": str(instance.value),
        }
        outgoing_payload = dict(incoming_payload)
        outgoing_payload["type"] = WebHookType.OUTGOING_ETHER.name
        outgoing_payload["address"] = instance._from
        payloads = [incoming_payload, outgoing_payload]
    elif sender in (ERC20Transfer, ERC721Transfer):
        # INCOMING_TOKEN / OUTGOING_TOKEN
        incoming_payload = {
            "address": instance.to,
            "type": WebHookType.INCOMING_TOKEN.name,
            "tokenAddress": instance.address,
            "txHash": HexBytes(instance.ethereum_tx_id).hex(),
        }
        if isinstance(instance, ERC20Transfer):
            incoming_payload["value"] = str(instance.value)
        else:
            incoming_payload["tokenId"] = str(instance.token_id)
        outgoing_payload = dict(incoming_payload)
        outgoing_payload["type"] = WebHookType.OUTGOING_TOKEN.name
        outgoing_payload["address"] = instance._from
        payloads = [incoming_payload, outgoing_payload]
    elif sender == SafeContract:  # Safe created
        payloads = [{
            "address": instance.address,
            "type": WebHookType.SAFE_CREATED.name,
            "txHash": HexBytes(instance.ethereum_tx_id).hex(),
            "blockNumber": instance.created_block_number,
        }]
    elif sender == ModuleTransaction:
        payloads = [{
            "address":
            instance.safe,
            "type":
            WebHookType.MODULE_TRANSACTION.name,
            "module":
            instance.module,
            "txHash":
            HexBytes(instance.internal_tx.ethereum_tx_id).hex(),
        }]

    # Add chainId to every payload
    for payload in payloads:
        payload["chainId"] = str(get_ethereum_network().value)

    return payloads
Example #21
0
def test_create_from_factory_args(get_contract, deploy_factory_for, w3, keccak,
                                  create2_address_of, assert_tx_failed):
    code = """
struct Bar:
    x: String[32]

FOO: immutable(String[128])
BAR: immutable(Bar)

@external
def __init__(foo: String[128], bar: Bar):
    FOO = foo
    BAR = bar

@external
def foo() -> String[128]:
    return FOO

@external
def bar() -> Bar:
    return BAR
    """

    deployer_code = """
struct Bar:
    x: String[32]

created_address: public(address)

@external
def test(target: address, arg1: String[128], arg2: Bar):
    self.created_address = create_from_factory(target, arg1, arg2)

@external
def test2(target: address, arg1: String[128], arg2: Bar, salt: bytes32):
    self.created_address = create_from_factory(target, arg1, arg2, salt=salt)

@external
def should_fail(target: address, arg1: String[129], arg2: Bar):
    self.created_address = create_from_factory(target, arg1, arg2)
    """
    FOO = "hello!"
    BAR = ("world!", )

    # deploy a foo so we can compare its bytecode with factory deployed version
    foo_contract = get_contract(code, FOO, BAR)
    expected_runtime_code = w3.eth.get_code(foo_contract.address)

    f, FooContract = deploy_factory_for(code)

    d = get_contract(deployer_code)

    initcode = w3.eth.get_code(f.address)

    d.test(f.address, FOO, BAR, transact={})

    test = FooContract(d.created_address())
    assert w3.eth.get_code(test.address) == expected_runtime_code
    assert test.foo() == FOO
    assert test.bar() == BAR

    # extcodesize check
    assert_tx_failed(lambda: d.test("0x" + "00" * 20, FOO, BAR))

    # now same thing but with create2
    salt = keccak(b"vyper")
    d.test2(f.address, FOO, BAR, salt, transact={})

    test = FooContract(d.created_address())
    assert w3.eth.get_code(test.address) == expected_runtime_code
    assert test.foo() == FOO
    assert test.bar() == BAR

    encoded_args = encode_single("(string,(string))", (FOO, BAR))
    assert HexBytes(test.address) == create2_address_of(
        d.address, salt, initcode + encoded_args)

    # can't collide addresses
    assert_tx_failed(lambda: d.test2(f.address, FOO, BAR, salt))

    # but creating a contract with different args is ok
    FOO = "bar"
    d.test2(f.address, FOO, BAR, salt, transact={})
    # just for kicks
    assert FooContract(d.created_address()).foo() == FOO
    assert FooContract(d.created_address()).bar() == BAR

    # Foo constructor should fail
    FOO = b"\x01" * 129
    BAR = ("", )
    assert_tx_failed(lambda: d.should_fail(f.address, FOO, BAR))
Example #22
0
class EthModuleTest(object):
    def test_eth_protocolVersion(self, web3):
        protocol_version = web3.version.ethereum

        assert is_string(protocol_version)
        assert protocol_version.isdigit()

    def test_eth_syncing(self, web3):
        syncing = web3.eth.syncing

        assert is_boolean(syncing) or is_dict(syncing)

        if is_boolean(syncing):
            assert syncing is False
        elif is_dict(syncing):
            assert 'startingBlock' in syncing
            assert 'currentBlock' in syncing
            assert 'highestBlock' in syncing

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

    def test_eth_coinbase(self, web3):
        coinbase = web3.eth.coinbase
        assert is_checksum_address(coinbase)

    def test_eth_mining(self, web3):
        mining = web3.eth.mining
        assert is_boolean(mining)

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

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

    def test_eth_accounts(self, web3):
        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):
        block_number = web3.eth.blockNumber
        assert is_integer(block_number)
        assert block_number >= 0

    def test_eth_getBalance(self, web3):
        coinbase = web3.eth.coinbase

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

        balance = web3.eth.getBalance(coinbase)

        assert is_integer(balance)
        assert balance >= 0

    def test_eth_getStorageAt(self, web3):
        coinbase = web3.eth.coinbase

        with pytest.raises(InvalidAddress):
            web3.eth.getStorageAt(coinbase.lower(), 0)

    def test_eth_getTransactionCount(self, web3):
        coinbase = web3.eth.coinbase
        transaction_count = web3.eth.getTransactionCount(coinbase)
        with pytest.raises(InvalidAddress):
            web3.eth.getTransactionCount(coinbase.lower())

        assert is_integer(transaction_count)
        assert transaction_count >= 0

    def test_eth_getBlockTransactionCountByHash_empty_block(
            self, web3, empty_block):
        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, empty_block):
        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, block_with_txn):
        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, block_with_txn):
        transaction_count = web3.eth.getBlockTransactionCount(
            block_with_txn['number'])

        assert is_integer(transaction_count)
        assert transaction_count >= 1

    def test_eth_getUncleCountByBlockHash(self, web3, empty_block):
        uncle_count = web3.eth.getUncleCount(empty_block['hash'])

        assert is_integer(uncle_count)
        assert uncle_count == 0

    def test_eth_getUncleCountByBlockNumber(self, web3, empty_block):
        uncle_count = web3.eth.getUncleCount(empty_block['number'])

        assert is_integer(uncle_count)
        assert uncle_count == 0

    def test_eth_getCode(self, web3, math_contract):
        code = web3.eth.getCode(math_contract.address)
        with pytest.raises(InvalidAddress):
            code = web3.eth.getCode(math_contract.address.lower())
        assert is_string(code)
        assert len(code) > 2

    def test_eth_sign(self, web3, unlocked_account):
        signature = web3.eth.sign(unlocked_account,
                                  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,
            hexstr=
            '0x4d6573736167652074c3b6207369676e2e204c6f6e676572207468616e206861736821'
        )
        assert hexsign == signature

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

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

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

    def test_eth_sendTransaction_addr_checksum_required(
            self, web3, unlocked_account):
        non_checksum_addr = unlocked_account.lower()
        txn_params = {
            'from': unlocked_account,
            'to': unlocked_account,
            'value': 1,
            'gas': 21000,
            'gasPrice': web3.eth.gasPrice,
        }

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

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

    def test_eth_sendTransaction(self, web3, unlocked_account):
        txn_params = {
            'from': unlocked_account,
            'to': unlocked_account,
            'value': 1,
            'gas': 21000,
            'gasPrice': web3.eth.gasPrice,
        }
        txn_hash = web3.eth.sendTransaction(txn_params)
        txn = web3.eth.getTransaction(txn_hash)

        assert is_same_address(txn['from'], txn_params['from'])
        assert is_same_address(txn['to'], 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, unlocked_account):
        txn_params = {
            'from': unlocked_account,
            'to': unlocked_account,
            'value': 1,
            'gas': 21000,
            # Increased gas price to ensure transaction hash different from other tests
            'gasPrice': web3.eth.gasPrice * 2,
            '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'], txn_params['from'])
        assert is_same_address(txn['to'], txn_params['to'])
        assert txn['value'] == 1
        assert txn['gas'] == 21000
        assert txn['gasPrice'] == txn_params['gasPrice']
        assert txn['nonce'] == txn_params['nonce']

    @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, raw_transaction,
                                    funded_account_for_raw_txn, expected_hash):
        txn_hash = web3.eth.sendRawTransaction(raw_transaction)
        assert txn_hash == web3.toBytes(hexstr=expected_hash)

    def test_eth_call(self, web3, math_contract):
        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 = decode_single('uint256', call_result)
        assert result == 18

    def test_eth_call_with_0_result(self, web3, math_contract):
        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 = decode_single('uint256', call_result)
        assert result == 0

    def test_eth_estimateGas(self, web3):
        coinbase = web3.eth.coinbase
        gas_estimate = web3.eth.estimateGas({
            'from': coinbase,
            'to': coinbase,
            'value': 1,
        })
        assert is_integer(gas_estimate)
        assert gas_estimate > 0

    def test_eth_getBlockByHash(self, web3, empty_block):
        block = web3.eth.getBlock(empty_block['hash'])
        assert block['hash'] == empty_block['hash']

    def test_eth_getBlockByHash_not_found(self, web3, empty_block):
        block = web3.eth.getBlock(UNKNOWN_HASH)
        assert block is None

    def test_eth_getBlockByNumber_with_integer(self, web3, empty_block):
        block = web3.eth.getBlock(empty_block['number'])
        assert block['number'] == empty_block['number']

    def test_eth_getBlockByNumber_latest(self, web3, empty_block):
        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, empty_block):
        block = web3.eth.getBlock(12345)
        assert block is None

    def test_eth_getBlockByNumber_pending(self, web3, empty_block):
        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, empty_block):
        genesis_block = web3.eth.getBlock(0)
        block = web3.eth.getBlock('earliest')
        assert block['number'] == 0
        assert block['hash'] == genesis_block['hash']

    def test_eth_getBlockByNumber_full_transactions(self, web3,
                                                    block_with_txn):
        block = web3.eth.getBlock(block_with_txn['number'], True)
        transaction = block['transactions'][0]
        assert transaction['hash'] == block_with_txn['transactions'][0]

    def test_eth_getTransactionByHash(self, web3, mined_txn_hash):
        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, math_contract_deploy_txn_hash):
        transaction = web3.eth.getTransaction(math_contract_deploy_txn_hash)
        assert is_dict(transaction)
        assert transaction['to'] is None

    def test_eth_getTransactionByBlockHashAndIndex(self, web3, block_with_txn,
                                                   mined_txn_hash):
        transaction = web3.eth.getTransactionFromBlock(block_with_txn['hash'],
                                                       0)
        assert is_dict(transaction)
        assert transaction['hash'] == HexBytes(mined_txn_hash)

    def test_eth_getTransactionByBlockNumberAndIndex(self, web3,
                                                     block_with_txn,
                                                     mined_txn_hash):
        transaction = web3.eth.getTransactionFromBlock(
            block_with_txn['number'], 0)
        assert is_dict(transaction)
        assert transaction['hash'] == HexBytes(mined_txn_hash)

    def test_eth_getTransactionReceipt_mined(self, web3, block_with_txn,
                                             mined_txn_hash):
        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)

    def test_eth_getTransactionReceipt_unmined(self, web3, unlocked_account):
        txn_hash = web3.eth.sendTransaction({
            'from': unlocked_account,
            'to': unlocked_account,
            'value': 1,
            'gas': 21000,
            'gasPrice': web3.eth.gasPrice,
        })
        receipt = web3.eth.getTransactionReceipt(txn_hash)
        assert receipt is None

    def test_eth_getTransactionReceipt_with_log_entry(self, web3,
                                                      block_with_txn_with_log,
                                                      emitter_contract,
                                                      txn_hash_with_log):
        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):
        # TODO: how do we make uncles....
        pass

    def test_eth_getUncleByBlockNumberAndIndex(self, web3):
        # TODO: how do we make uncles....
        pass

    def test_eth_getCompilers(self, web3):
        # TODO: do we want to test this?
        pass

    def test_eth_compileSolidity(self, web3):
        # TODO: do we want to test this?
        pass

    def test_eth_compileLLL(self, web3):
        # TODO: do we want to test this?
        pass

    def test_eth_compileSerpent(self, web3):
        # TODO: do we want to test this?
        pass

    def test_eth_newFilter(self, web3):
        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):
        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):
        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, block_with_txn_with_log):
        # Test with block range

        filter_params = {
            "fromBlock": 0,
            "toBlock": 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": 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": 0,
            "address": UNKNOWN_ADDRESS,
        }
        result = web3.eth.getLogs(filter_params)
        assert len(result) == 0

    def test_eth_getLogs_with_logs(self, web3, block_with_txn_with_log,
                                   emitter_contract, txn_hash_with_log):
        def assert_contains_log(result):
            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 = {
            "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": 0,
        }
        result = web3.eth.getLogs(filter_params)
        assert_contains_log(result)

        # Test with `address`

        # filter with emitter_contract.address
        filter_params = {
            "fromBlock": 0,
            "address": emitter_contract.address,
        }
        result = web3.eth.getLogs(filter_params)
        assert_contains_log(result)

    def test_eth_uninstallFilter(self, web3):
        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
Example #23
0
        "nonce": 0,
        "gasPrice": 1000000000000,
        "gas": 10000,
        "to": "",
        "value": 0,
        "data": "6025515b525b600a37f260003556601b596020356000355760015b525b54602052f260255860005b525b54602052f2",  # noqa: 501
        "unsigned": "f83f8085e8d4a510008227108080af6025515b525b600a37f260003556601b596020356000355760015b525b54602052f260255860005b525b54602052f2808080",  # noqa: 501
        "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)
ACCT_ADDRESS = '0xa79F6f349C853F9Ea0B29636779ae3Cb4E3BA729'

PRIVATE_KEY_AS_BYTES_ALT = b'rainbows' * 4
Example #24
0
 def test_eth_getTransactionByHash(self, web3, mined_txn_hash):
     transaction = web3.eth.getTransaction(mined_txn_hash)
     assert is_dict(transaction)
     assert transaction['hash'] == HexBytes(mined_txn_hash)
Example #25
0
        15655399131600894366408541311673616702363115109327707006109616887384920764603,
    )
    msg_hash = b'\xbb\r\x8a\xba\x9f\xf7\xa1<N,s{i\x81\x86r\x83{\xba\x9f\xe2\x1d\xaa\xdd\xb3\xd6\x01\xda\x00\xb7)\xa1'  # noqa: E501
    from_account = acct.recoverHash(msg_hash, vrs=(v, r, s))
    assert from_account == '0xFeC2079e80465cc8C687fFF9EE6386ca447aFec4'


@pytest.mark.parametrize(
    'message, key, expected_bytes, expected_hash, v, r, s, signature',
    (
        (
            'Some data',
            '0x4c0883a69102937d6231471b5dbb6204fe5129617082792ae468d01a3f362318',
            b'Some data',
            HexBytes(
                '0x1da44b586eb0729ff70a73c326926f6ed5a25f5b056e7f47fbc6e58d86871655'
            ),
            28,
            83713930994764734002432606962255364472443135907807238282514898577139886061053,
            43435997768575461196683613590576722655951133545204789519877940758262837256233,
            HexBytes(
                '0xb91467e570a6466aa9e9876cbcd013baba02900b8979d43fe208a4a4f339f5fd6007e74cd82e037b800186422fc2da167c747ef045e5d18a5f5d4300f8e1a0291c'
            ),  # noqa: E501
        ),
        (
            '10284',
            '0x4c0883a69102937d6231471b5dbb6204fe5129617082792ae468d01a3f362318',
            b'10284',
            HexBytes(
                '0x0a162a5efbba02f38db3114531c8acba39fe676f09f7e471d93e8a06c471821c'
            ),
Example #26
0
 def test_eth_getTransactionByBlockHashAndIndex(self, web3, block_with_txn,
                                                mined_txn_hash):
     transaction = web3.eth.getTransactionFromBlock(block_with_txn['hash'],
                                                    0)
     assert is_dict(transaction)
     assert transaction['hash'] == HexBytes(mined_txn_hash)
Example #27
0
def contract_call_string(call_result):
    length = int(call_result[66:130], 16) * 2
    data = call_result[130:130 + length]
    ret = HexBytes(data).decode()
    return ret.lower()
Example #28
0
class Web3ModuleTest:
    def test_web3_clientVersion(self, web3: Web3) -> None:
        client_version = web3.clientVersion
        self._check_web3_clientVersion(client_version)

    def _check_web3_clientVersion(self, client_version: str) -> NoReturn:
        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: "Web3", types: Sequence[TypeStr], values: Sequence[Any], expected: HexBytes
    ) -> None:
        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: "Web3", types: Sequence[TypeStr], values: Sequence[str], expected: HexBytes
    ) -> None:
        with ens_addresses(web3, {
            'one.eth': ChecksumAddress(
                HexAddress(HexStr("0x49EdDD3769c0712032808D86597B84ac5c2F5614"))
            ),
            'two.eth': ChecksumAddress(
                HexAddress(HexStr("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: "Web3", types: Sequence[TypeStr], values: Sequence[Any]
    ) -> None:
        with pytest.raises(ValueError):
            web3.solidityKeccak(types, values)

    def test_is_connected(self, web3: "Web3") -> None:
        assert web3.isConnected()
Example #29
0
def test_encode(test_case):
    expected = test_case["expected_raw_transaction"]
    transaction = TypedTransaction.from_dict(test_case["transaction"])
    raw_transaction = transaction.encode()
    actual = HexBytes(raw_transaction).hex()
    assert actual == expected
def revert_contract(web3, RevertContract, address_conversion_func):
    return deploy(web3, RevertContract, 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):
    if is_text(request.param) and request.param[:2] != '0x':
        with pytest.warns(DeprecationWarning):
            return deploy(web3, Bytes32Contract, address_conversion_func, args=[request.param])
    else:
        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