def test_error_when_invalid_args_kwargs_combo_provided():
    with pytest.raises(TypeError):
        merge_args_and_kwargs(GENERATED_FUNCTION_ABI, (
            1,
            2,
        ), {
            'a': 1,
            'b': 2
        })
Example #2
0
def get_constructor_arguments(contract: Contract,
                              args: Optional[list] = None,
                              kwargs: Optional[dict] = None):
    """Get constructor arguments for Etherscan verify.

    https://etherscanio.freshdesk.com/support/solutions/articles/16000053599-contract-verification-constructor-arguments
    """

    # return contract._encode_constructor_data(args=args, kwargs=kwargs)
    constructor_abi = get_constructor_abi(contract.abi)

    # constructor_abi can be none in case of libraries
    if constructor_abi is None:
        return to_hex(contract.bytecode)

    if args is not None:
        return contract.encodeABI(constructor_abi['name'], args)[2:]  # No 0x
    else:
        constructor_abi = get_constructor_abi(contract.abi)
        kwargs = kwargs or {}
        arguments = merge_args_and_kwargs(constructor_abi, [], kwargs)
        # deploy_data = add_0x_prefix(
        #    contract._encode_abi(constructor_abi, arguments)
        # )

        # TODO: Looks like recent Web3.py ABI change
        deploy_data = encode_abi(contract.web3, constructor_abi, arguments)
        return deploy_data
Example #3
0
def estimate_gas_for_function(contract=None,
                              function_name=None,
                              transaction=None,
                              *args,
                              **kwargs):
    """Estimates gas cost a function call would take.

    Don't call this directly, instead use :meth:`Contract.estimateGas`
    on your contract instance.
    """
    if transaction is None:
        estimate_transaction = {}
    else:
        estimate_transaction = dict(**transaction)

    function_abi = contract.find_matching_fn_abi(function_name, args, kwargs)
    function_selector = function_abi_to_4byte_selector(function_abi)

    arguments = merge_args_and_kwargs(function_abi, args, kwargs)

    estimate_transaction['data'] = contract.encodeABI(
        function_name,
        arguments,
        data=function_selector,
    )

    gas_estimate = contract.web3.eth.estimateGas(estimate_transaction)
    return gas_estimate
Example #4
0
    def _get_function_info(cls, fn_name, args=None, kwargs=None):
        if args is None:
            args = tuple()
        if kwargs is None:
            kwargs = {}

        fn_abi = cls._find_matching_fn_abi(fn_name, args, kwargs)
        fn_selector = function_abi_to_4byte_selector(fn_abi)

        fn_arguments = merge_args_and_kwargs(fn_abi, args, kwargs)

        return fn_abi, fn_selector, fn_arguments
Example #5
0
    def _get_function_info(cls, fn_name, args=None, kwargs=None):
        if args is None:
            args = tuple()
        if kwargs is None:
            kwargs = {}

        fn_abi = cls._find_matching_fn_abi(fn_name, args, kwargs)
        fn_selector = encode_hex(function_abi_to_4byte_selector(fn_abi))

        fn_arguments = merge_args_and_kwargs(fn_abi, args, kwargs)

        return fn_abi, fn_selector, fn_arguments
Example #6
0
def get_function_info(abi, fn_name, args=None, kwargs=None):
    if args is None:
        args = tuple()
    if kwargs is None:
        kwargs = {}

    fn_abi = find_matching_fn_abi(abi, fn_name, args, kwargs)
    fn_selector = encode_hex(function_abi_to_4byte_selector(fn_abi))

    fn_arguments = merge_args_and_kwargs(fn_abi, args, kwargs)

    return fn_abi, fn_selector, fn_arguments
Example #7
0
    def _set_function_info(self):
        self.abi = find_matching_fn_abi(self.contract_abi,
                                        self.function_identifier,
                                        self.args,
                                        self.kwargs)

        if self.function_identifier is FallbackFn:
            self.selector = encode_hex(b'')
        elif is_text(self.function_identifier):
            self.selector = encode_hex(function_abi_to_4byte_selector(self.abi))
        else:
            raise TypeError("Unsupported function identifier")

        self.arguments = merge_args_and_kwargs(self.abi, self.args, self.kwargs)
Example #8
0
    def _set_function_info(self):
        self.abi = find_matching_fn_abi(self.contract_abi,
                                        self.function_identifier,
                                        self.args,
                                        self.kwargs)

        if self.function_identifier is FallbackFn:
            self.selector = encode_hex(b'')
        elif is_text(self.function_identifier):
            self.selector = encode_hex(function_abi_to_4byte_selector(self.abi))
        else:
            raise TypeError("Unsupported function identifier")

        self.arguments = merge_args_and_kwargs(self.abi, self.args, self.kwargs)
Example #9
0
def get_constructor_arguments(contract: Contract, args: Optional[list]=None, kwargs: Optional[dict]=None):
    """Get constructor arguments for Etherscan verify.

    https://etherscanio.freshdesk.com/support/solutions/articles/16000053599-contract-verification-constructor-arguments
    """
    constructor_abi = get_constructor_abi(contract.abi)

    if args is not None:
        return contract._encode_abi(constructor_abi, args)[2:]  # No 0x
    else:
        constructor_abi = get_constructor_abi(contract.abi)
        arguments = merge_args_and_kwargs(constructor_abi, [], kwargs)
        deploy_data = add_0x_prefix(
            contract._encode_abi(constructor_abi, arguments)
        )
        return deploy_data
Example #10
0
def call_contract_function(contract, function_name, transaction, *args,
                           **kwargs):
    """Calls a contract constant or function.

    The function must not have state changing effects.
    For those see :func:`transact_with_contract_function`

    For usual cases, you do not want to call this directly,
    but interact with your contract through :meth:`Contract.call` method.

    :param contract: :class:`web3.contract.Contract` object instance
    :param function_name: Contract function name to call
    :param transaction: Transaction parameters to pass to underlying ``web3.eth.call``
    :param *arguments: Arguments to be passed to contract function. Automatically encoded
    :return: Function call results, encoded to Python object
    """
    if transaction is None:
        call_transaction = {}
    else:
        call_transaction = dict(**transaction)

    function_abi = contract.find_matching_fn_abi(function_name, args, kwargs)
    function_selector = function_abi_to_4byte_selector(function_abi)

    arguments = merge_args_and_kwargs(function_abi, args, kwargs)

    call_transaction['data'] = contract.encodeABI(
        function_name,
        arguments,
        data=function_selector,
    )

    return_data = contract.web3.eth.call(call_transaction)

    output_types = get_abi_output_types(function_abi)
    output_data = decode_abi(output_types, return_data)

    normalized_data = [
        normalize_return_type(data_type, data_value)
        for data_type, data_value in zip(output_types, output_data)
    ]

    if len(normalized_data) == 1:
        return normalized_data[0]
    else:
        return normalized_data
Example #11
0
    def _encode_data_in_transaction(self, *args, **kwargs):
        constructor_abi = get_constructor_abi(self.abi)

        if constructor_abi:
            if not args:
                args = tuple()
            if not kwargs:
                kwargs = {}

            arguments = merge_args_and_kwargs(constructor_abi, args, kwargs)
            data = add_0x_prefix(
                encode_abi(self.web3, constructor_abi, arguments, data=self.bytecode)
            )
        else:
            data = to_hex(self.bytecode)

        return data
Example #12
0
    def _encode_constructor_data(cls, args=None, kwargs=None):
        constructor_abi = get_constructor_abi(cls.abi)

        if constructor_abi:
            if args is None:
                args = tuple()
            if kwargs is None:
                kwargs = {}

            arguments = merge_args_and_kwargs(constructor_abi, args, kwargs)

            deploy_data = add_0x_prefix(
                cls._encode_abi(constructor_abi, arguments, data=cls.bytecode))
        else:
            deploy_data = add_0x_prefix(cls.bytecode)

        return deploy_data
Example #13
0
    def _encode_constructor_data(cls, args=None, kwargs=None):
        constructor_abi = get_constructor_abi(cls.abi)

        if constructor_abi:
            if args is None:
                args = tuple()
            if kwargs is None:
                kwargs = {}

            arguments = merge_args_and_kwargs(constructor_abi, args, kwargs)

            deploy_data = add_0x_prefix(
                cls._encode_abi(constructor_abi, arguments, data=cls.bytecode)
            )
        else:
            deploy_data = add_0x_prefix(cls.bytecode)

        return deploy_data
Example #14
0
def encode_constructor_data(abi, bytecode, web3, args=None, kwargs=None):

    constructor_abi = get_constructor_abi(abi)

    if constructor_abi:
        if args is None:
            args = tuple()
        if kwargs is None:
            kwargs = {}

        arguments = merge_args_and_kwargs(constructor_abi, args, kwargs)

        deploy_data = add_0x_prefix(
            encode_abi(web3, constructor_abi, arguments, data=bytecode))
    else:
        deploy_data = to_hex(bytecode)

    return deploy_data
def test_error_when_invalid_args_kwargs_combo_provided():
    with pytest.raises(TypeError):
        merge_args_and_kwargs(GENERATED_FUNCTION_ABI, (1, 2,), {'a': 1, 'b': 2})
def test_kwargs_is_disallowed_when_merging_with_unnamed_inputs():
    with pytest.raises(TypeError):
        merge_args_and_kwargs(GENERATED_FUNCTION_ABI, tuple(), {
            'x': 1,
            'y': 2
        })
def test_merging_of_args_and_kwargs_with_no_inputs():
    actual = merge_args_and_kwargs(NO_INPUTS_FUNCTION_ABI, tuple(), {})
    assert actual == tuple()
def test_merging_of_args_and_kwargs(args, kwargs, expected_args):
    actual_args = merge_args_and_kwargs(FUNCTION_ABI, args, kwargs)
    assert actual_args == expected_args
Example #19
0
 def _set_function_info(self):
     self.abi = find_matching_fn_abi(self.contract_abi, self.fn_name, self.args, self.kwargs)
     self.selector = encode_hex(function_abi_to_4byte_selector(self.abi))
     self.arguments = merge_args_and_kwargs(self.abi, self.args, self.kwargs)
Example #20
0
 def _set_function_info(self):
     self.abi = find_matching_fn_abi(self.contract_abi, self.fn_name,
                                     self.args, self.kwargs)
     self.selector = encode_hex(function_abi_to_4byte_selector(self.abi))
     self.arguments = merge_args_and_kwargs(self.abi, self.args,
                                            self.kwargs)
def test_kwargs_is_disallowed_when_merging_with_unnamed_inputs():
    with pytest.raises(TypeError):
        merge_args_and_kwargs(GENERATED_FUNCTION_ABI, tuple(), {'x': 1, 'y': 2})
Example #22
0
def transact_with_contract_function(contract=None,
                                    function_name=None,
                                    transaction=None,
                                    *args,
                                    **kwargs):
    """Transacts with a contract.

    Sends in a transaction that interacts with the contract.
    You should specify the account that pays the gas for this
    transaction in `transaction`.

    Example:

    .. code-block:: python

        def withdraw(self,
                     to_address: str,
                     amount_in_eth: Decimal,
                     from_account=None,
                     max_gas=50000) -> str:
            '''Withdraw funds from a wallet contract.

            :param amount_in_eth: How much as ETH
            :param to_address: Destination address we are withdrawing to
            :param from_account: Which Geth accout pays the gas
            :return: Transaction hash
            '''

            assert isinstance(amount_in_eth, Decimal)  # Don't let floats slip through

            wei = to_wei(amount_in_eth)

            if not from_account:
                # Default to coinbase for transaction fees
                from_account = self.contract.web3.eth.coinbase

            tx_info = {
                # The Ethereum account that pays the gas for this operation
                "from": from_account,
                "gas": max_gas,
            }

            # Interact with underlying wrapped contract
            txid = transact_with_contract_function(
                self.contract, "withdraw", tx_info, to_address, wei,
            )
            return txid

    The transaction is created in the Ethereum node memory pool.
    Transaction receipt is not available until the transaction has been mined.
    See :func:`populus.utils.transactions.wait_for_transaction`.

    Usually there is no reason to call directly. Instead
    use :meth:`Contract.transact` interface.

    :param contract: :class:`web3.contract.Contract` object instance
    :param function_name: Contract function name to call
    :param transaction: Dictionary of transaction parameters to pass to
                        underlying ``web3.eth.sendTransaction``
    :param *arguments: Arguments to be passed to contract function. Automatically encoded
    :return: String, 0x formatted transaction hash.
    """
    if transaction is None:
        transact_transaction = {}
    else:
        transact_transaction = dict(**transaction)

    function_abi = contract.find_matching_fn_abi(function_name, args, kwargs)
    function_selector = function_abi_to_4byte_selector(function_abi)

    arguments = merge_args_and_kwargs(function_abi, args, kwargs)

    transact_transaction['data'] = contract.encodeABI(
        function_name,
        arguments,
        data=function_selector,
    )

    txn_hash = contract.web3.eth.sendTransaction(transact_transaction)
    return txn_hash
def test_args_allowed_when_duplicate_named_inputs():
    actual = merge_args_and_kwargs(DUPLICATE_NAMES_FUNCTION_ABI, (1, 2, 3), {})
    assert actual == (1, 2, 3)
def test_kwargs_allowed_if_no_intersections_with_duplicate_input_names():
    with pytest.raises(TypeError):
        merge_args_and_kwargs(DUPLICATE_NAMES_FUNCTION_ABI, (1, ), {
            'a': 2,
            'b': 3
        })
def test_args_allowed_when_duplicate_named_inputs():
    actual = merge_args_and_kwargs(DUPLICATE_NAMES_FUNCTION_ABI, (1, 2, 3), {})
    assert actual == (1, 2, 3)
def test_args_works_when_merging_with_unnamed_inputs():
    actual = merge_args_and_kwargs(GENERATED_FUNCTION_ABI, (1, 2), {})
    assert actual == (1, 2)
def test_args_works_when_merging_with_unnamed_inputs():
    actual = merge_args_and_kwargs(GENERATED_FUNCTION_ABI, (1, 2), {})
    assert actual == (1, 2)
def test_kwargs_not_allowed_for_duplicate_input_names():
    with pytest.raises(TypeError):
        merge_args_and_kwargs(DUPLICATE_NAMES_FUNCTION_ABI, (1,), {'a': 2, 'b': 3})