Пример #1
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
Пример #2
0
def test_contract_estimateGas(web3, math_contract):
    if isinstance(web3.currentProvider, TestRPCProvider):
        pytest.skip("The testrpc server doesn't implement `eth_estimateGas`")

    increment_abi = math_contract.find_matching_abi("increment", [])
    call_data = function_abi_to_4byte_selector(increment_abi)
    gas_estimate = math_contract.estimateGas().increment()

    assert abs(gas_estimate - 21272) < 200
Пример #3
0
def test_contract_estimateGas(web3, math_contract):
    increment_abi = math_contract._find_matching_fn_abi('increment', [])
    call_data = function_abi_to_4byte_selector(increment_abi)
    gas_estimate = math_contract.estimateGas().increment()

    try:
        assert abs(gas_estimate - 21472) < 200  # Geth
    except AssertionError:
        assert abs(gas_estimate - 43020) < 200  # TestRPC
        pass
Пример #4
0
def test_contract_estimateGas(web3, math_contract):
    increment_abi = math_contract._find_matching_fn_abi('increment', [])
    call_data = function_abi_to_4byte_selector(increment_abi)
    gas_estimate = math_contract.estimateGas().increment()

    try:
        assert abs(gas_estimate - 21272) < 200  # Geth
    except AssertionError:
        assert abs(gas_estimate - 42820) < 200  # TestRPC
        pass
Пример #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 = function_abi_to_4byte_selector(fn_abi)

        fn_arguments = merge_args_and_kwargs(fn_abi, args, kwargs)

        return fn_abi, fn_selector, fn_arguments
Пример #6
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
Пример #7
0
def test_eth_estimateGas(web3, math_contract):
    if isinstance(web3.currentProvider, TestRPCProvider):
        pytest.skip("The testrpc server doesn't implement `eth_estimateGas`")

    increment_abi = math_contract.find_matching_abi('increment', [])
    call_data = function_abi_to_4byte_selector(increment_abi)
    gas_estimate = web3.eth.estimateGas({
        'to': math_contract.address,
        'from': web3.eth.coinbase,
        'data': call_data,
    })

    assert abs(gas_estimate - 21272) < 200
Пример #8
0
def test_eth_estimateGas(web3, math_contract):
    increment_abi = math_contract.find_matching_fn_abi('increment', [])
    call_data = function_abi_to_4byte_selector(increment_abi)
    gas_estimate = web3.eth.estimateGas({
        'to': math_contract.address,
        'from': web3.eth.coinbase,
        'data': call_data,
    })

    try:
        assert abs(gas_estimate - 21272) < 200  # Geth
    except AssertionError:
        assert abs(gas_estimate - 42820) < 200  # TestRPC
        pass
Пример #9
0
def test_eth_estimateGas(web3, math_contract):
    increment_abi = math_contract._find_matching_fn_abi('increment', [])
    call_data = function_abi_to_4byte_selector(increment_abi)
    gas_estimate = web3.eth.estimateGas({
        'to': math_contract.address,
        'from': web3.eth.coinbase,
        'data': call_data,
    })

    try:
        assert abs(gas_estimate - 21272) < 200  # Geth
    except AssertionError:
        assert abs(gas_estimate - 42820) < 200  # TestRPC
        pass
Пример #10
0
    def execute(
        self, to_contract: Contract, func: str, args=None, amount_in_eth: Optional[Decimal] = None, max_gas=100000
    ):
        """Calls a smart contract from the hosted wallet.

        Creates a transaction that is proxyed through hosted wallet execute method. We need to have ABI as Populus Contract instance.

        :param wallet_address: Wallet address
        :param contract: Contract to called as address bound Populus Contract class
        :param func: Method name to be called
        :param args: Arguments passed to the method
        :param value: Additional value carried in the call in ETH
        :param gas: The max amount of gas the coinbase account is allowed to pay for this transaction.
        :return: txid of the execution as hex string
        """

        assert isinstance(to_contract, Contract)

        if amount_in_eth:
            assert isinstance(amount_in_eth, Decimal)  # Don't let floats slip through
            value = to_wei(amount_in_eth)
        else:
            value = 0

        # Encode function arguments
        function_abi = to_contract._find_matching_fn_abi(func, args)
        # 4 byte function hash
        function_selector = function_abi_to_4byte_selector(function_abi)

        # data payload passed to the function
        arg_data = to_contract.encodeABI(func, args=args)

        call_data = function_selector + arg_data[2:]

        # test_event_execute() call data should look like
        # function selector + random int as 256-bit
        # 0x5093dc7d000000000000000000000000000000000000000000000000000000002a3f58fe

        # web3 takes bytes argument as actual bytes, not hex
        call_data = binascii.unhexlify(call_data[2:])

        tx_info = {
            # The Ethereum account that pays the gas for this operation
            "from": self.contract.web3.eth.coinbase,
            "gas": max_gas,
        }

        txid = self.contract.transact(tx_info).execute(to_contract.address, value, max_gas, call_data)
        return txid
Пример #11
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
Пример #12
0
def estimate_gas_for_function(contract=None,
                              function_name=None,
                              transaction=None,
                              *arguments):
    if not arguments:
        arguments = []

    function_abi = contract.find_matching_abi(function_name, arguments)
    function_selector = function_abi_to_4byte_selector(function_abi)

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

    gas_estimate = contract.web3.eth.estimateGas(transaction)
    return gas_estimate
Пример #13
0
def transact_with_contract_function(contract=None,
                                    function_name=None,
                                    transaction=None,
                                    *arguments):
    if not arguments:
        arguments = []

    function_abi = contract.find_matching_abi(function_name, arguments)
    function_selector = function_abi_to_4byte_selector(function_abi)

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

    txn_hash = contract.web3.eth.sendTransaction(transaction)
    return txn_hash
Пример #14
0
def call_contract_function(contract=None,
                           function_name=None,
                           transaction=None,
                           *arguments):
    if not arguments:
        arguments = []

    function_abi = contract.find_matching_abi(function_name, arguments)
    function_selector = function_abi_to_4byte_selector(function_abi)

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

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

    output_types = get_abi_output_types(function_abi)
    output_data = decode_abi(output_types, return_data)
    if len(output_data) == 1:
        return output_data[0]
    else:
        return output_data
Пример #15
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