Esempio n. 1
0
def build_transaction_for_function(abi,
                                   address,
                                   web3,
                                   function_name=None,
                                   transaction=None,
                                   *args,
                                   **kwargs):
    """Builds a dictionary with the fields required to make the given transaction

    Don't call this directly, instead use :meth:`Contract.buildTransaction`
    on your contract instance.
    """
    prepared_transaction = prepare_transaction(
        abi,
        address,
        web3,
        fn_name=function_name,
        fn_args=args,
        fn_kwargs=kwargs,
        transaction=transaction,
    )

    prepared_transaction = fill_transaction_defaults(web3, prepared_transaction)

    return prepared_transaction
Esempio n. 2
0
def build_transaction_for_function(abi,
                                   address,
                                   web3,
                                   function_name=None,
                                   transaction=None,
                                   *args,
                                   **kwargs):
    """Builds a dictionary with the fields required to make the given transaction

    Don't call this directly, instead use :meth:`Contract.buildTransaction`
    on your contract instance.
    """
    prepared_transaction = prepare_transaction(
        abi,
        address,
        web3,
        fn_identifier=function_name,
        fn_args=args,
        fn_kwargs=kwargs,
        transaction=transaction,
    )

    prepared_transaction = fill_transaction_defaults(web3,
                                                     prepared_transaction)

    return prepared_transaction
Esempio n. 3
0
def estimate_gas_for_function(
    address,
    web3,
    fn_identifier=None,
    transaction=None,
    contract_abi=None,
    fn_abi=None,
    block_identifier=None,
    *args,
    **kwargs,
):
    """Temporary workaround until next web3.py release (5.X.X)"""
    estimate_transaction = prepare_transaction(
        address,
        web3,
        fn_identifier=fn_identifier,
        contract_abi=contract_abi,
        fn_abi=fn_abi,
        transaction=transaction,
        fn_args=args,
        fn_kwargs=kwargs,
    )

    try:
        gas_estimate = web3.eth.estimateGas(estimate_transaction,
                                            block_identifier)
    except ValueError as e:
        if check_value_error_for_parity(e, ParityCallType.ESTIMATE_GAS):
            gas_estimate = None
        else:
            # else the error is not denoting estimate gas failure and is something else
            raise e

    return gas_estimate
Esempio n. 4
0
def estimate_gas_for_function(
        address,
        web3,
        fn_identifier=None,
        transaction=None,
        contract_abi=None,
        fn_abi=None,
        block_identifier=None,
        *args,
        **kwargs,
):
    """Temporary workaround until next web3.py release (5.X.X)"""
    estimate_transaction = prepare_transaction(
        address,
        web3,
        fn_identifier=fn_identifier,
        contract_abi=contract_abi,
        fn_abi=fn_abi,
        transaction=transaction,
        fn_args=args,
        fn_kwargs=kwargs,
    )

    gas_estimate = web3.eth.estimateGas(estimate_transaction, block_identifier)
    return gas_estimate
def transact_with_contract_function(address,
                                    web3,
                                    function_name=None,
                                    transaction=None,
                                    contract_abi=None,
                                    fn_abi=None,
                                    *args,
                                    **kwargs):
    """
    Helper function for interacting with a contract function by sending a
    transaction. This is copied from web3 `transact_with_contract_function`
    so we can use `personal_sendTransaction` when possible.
    """
    transact_transaction = prepare_transaction(
        address,
        web3,
        fn_identifier=function_name,
        contract_abi=contract_abi,
        transaction=transaction,
        fn_abi=fn_abi,
        fn_args=args,
        fn_kwargs=kwargs,
    )

    passphrase = None
    account_key = None
    if transaction and 'passphrase' in transaction:
        passphrase = transaction['passphrase']
        transact_transaction.pop('passphrase')
        if 'account_key' in transaction:
            account_key = transaction['account_key']
            transact_transaction.pop('account_key')

    # Restrict transactions to raw transactions for now (security first)
    # if not (passphrase and key_file):
    #     raise AssertionError(
    #         'password and key file are required for signing transactions locally.'
    #     )

    if account_key:
        raw_tx = Wallet(web3, account_key,
                        passphrase).sign_tx(transact_transaction)
        logging.debug(
            f'sending raw tx: function: {function_name}, tx hash: {raw_tx.hex()}'
        )
        txn_hash = web3.eth.sendRawTransaction(raw_tx)
    elif passphrase:
        txn_hash = web3.personal.sendTransaction(transact_transaction,
                                                 passphrase)
    else:
        txn_hash = web3.eth.sendTransaction(transact_transaction)

    return txn_hash
Esempio n. 6
0
    def _prepare_transaction(cls,
                             fn_name,
                             fn_args=None,
                             fn_kwargs=None,
                             transaction=None):

        return prepare_transaction(cls.abi,
                                   cls.address,
                                   cls.web3,
                                   fn_identifier=fn_name,
                                   fn_args=fn_args,
                                   fn_kwargs=fn_kwargs,
                                   transaction=transaction)
Esempio n. 7
0
    def _prepare_transaction(cls,
                             fn_name,
                             fn_args=None,
                             fn_kwargs=None,
                             transaction=None):

        return prepare_transaction(cls.abi,
                                   cls.address,
                                   cls.web3,
                                   fn_name=fn_name,
                                   fn_args=fn_args,
                                   fn_kwargs=fn_kwargs,
                                   transaction=transaction)
Esempio n. 8
0
def call_contract_function(abi, web3, address, normalizers, function_name,
                           transaction, *args, **kwargs):
    """
    Helper function for interacting with a contract function using the
    `eth_call` API.
    """
    call_transaction = prepare_transaction(
        abi,
        address,
        web3,
        fn_name=function_name,
        fn_args=args,
        fn_kwargs=kwargs,
        transaction=transaction,
    )

    return_data = web3.eth.call(call_transaction)

    function_abi = find_matching_fn_abi(abi, function_name, args, kwargs)

    output_types = get_abi_output_types(function_abi)

    try:
        output_data = decode_abi(output_types, return_data)
    except DecodingError as e:
        # Provide a more helpful error message than the one provided by
        # eth-abi-utils
        is_missing_code_error = (return_data in ACCEPTABLE_EMPTY_STRINGS
                                 and web3.eth.getCode(address)
                                 in ACCEPTABLE_EMPTY_STRINGS)
        if is_missing_code_error:
            msg = (
                "Could not transact with/call contract function, is contract "
                "deployed correctly and chain synced?")
        else:
            msg = (
                "Could not decode contract function call {} return data {} for "
                "output_types {}".format(function_name, return_data,
                                         output_types))
        raise BadFunctionCallOutput(msg) from e

    _normalizers = itertools.chain(
        BASE_RETURN_NORMALIZERS,
        normalizers,
    )
    normalized_data = map_abi_data(_normalizers, output_types, output_data)

    if len(normalized_data) == 1:
        return normalized_data[0]
    else:
        return normalized_data
Esempio n. 9
0
def transact_with_contract_function(abi,
                                    address,
                                    web3,
                                    function_name=None,
                                    transaction=None,
                                    *args,
                                    **kwargs):
    """
    Helper function for interacting with a contract function by sending a
    transaction.
    """
    transact_transaction = prepare_transaction(
        abi,
        address,
        web3,
        fn_identifier=function_name,
        fn_args=args,
        fn_kwargs=kwargs,
        transaction=transaction,
    )

    txn_hash = web3.eth.sendTransaction(transact_transaction)
    return txn_hash
Esempio n. 10
0
def transact_with_contract_function(abi,
                                    address,
                                    web3,
                                    function_name=None,
                                    transaction=None,
                                    *args,
                                    **kwargs):
    """
    Helper function for interacting with a contract function by sending a
    transaction.
    """
    transact_transaction = prepare_transaction(
        abi,
        address,
        web3,
        fn_name=function_name,
        fn_args=args,
        fn_kwargs=kwargs,
        transaction=transaction,
    )

    txn_hash = web3.eth.sendTransaction(transact_transaction)
    return txn_hash
Esempio n. 11
0
def estimate_gas_for_function(abi,
                              address,
                              web3,
                              fn_identifier=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.
    """
    estimate_transaction = prepare_transaction(
        abi,
        address,
        web3,
        fn_identifier=fn_identifier,
        fn_args=args,
        fn_kwargs=kwargs,
        transaction=transaction,
    )

    gas_estimate = web3.eth.estimateGas(estimate_transaction)
    return gas_estimate
Esempio n. 12
0
def transact_with_contract_function(address,
                                    web3,
                                    function_name=None,
                                    transaction=None,
                                    contract_abi=None,
                                    fn_abi=None,
                                    *args,
                                    **kwargs):
    """
    Helper function for interacting with a contract function by sending a
    transaction. This is copied from web3 `transact_with_contract_function`
    so we can use `personal_sendTransaction` when possible.
    """
    transact_transaction = prepare_transaction(
        address,
        web3,
        fn_identifier=function_name,
        contract_abi=contract_abi,
        transaction=transaction,
        fn_abi=fn_abi,
        fn_args=args,
        fn_kwargs=kwargs,
    )

    passphrase = None
    if transaction and 'passphrase' in transaction:
        passphrase = transaction['passphrase']
        transact_transaction.pop('passphrase')

    if passphrase:
        txn_hash = web3.personal.sendTransaction(transact_transaction,
                                                 passphrase)
    else:
        txn_hash = web3.eth.sendTransaction(transact_transaction)

    return txn_hash
Esempio n. 13
0
def estimate_gas_for_function(abi,
                              address,
                              web3,
                              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.
    """
    estimate_transaction = prepare_transaction(
        abi,
        address,
        web3,
        fn_name=function_name,
        fn_args=args,
        fn_kwargs=kwargs,
        transaction=transaction,
    )

    gas_estimate = web3.eth.estimateGas(estimate_transaction)
    return gas_estimate
Esempio n. 14
0
def call_contract_function(abi,
                           web3,
                           address,
                           normalizers,
                           function_name,
                           transaction,
                           *args,
                           **kwargs):
    """
    Helper function for interacting with a contract function using the
    `eth_call` API.
    """
    call_transaction = prepare_transaction(
        abi,
        address,
        web3,
        fn_name=function_name,
        fn_args=args,
        fn_kwargs=kwargs,
        transaction=transaction,
    )

    return_data = web3.eth.call(call_transaction)

    function_abi = find_matching_fn_abi(abi, function_name, args, kwargs)

    output_types = get_abi_output_types(function_abi)

    try:
        output_data = decode_abi(output_types, return_data)
    except DecodingError as e:
        # Provide a more helpful error message than the one provided by
        # eth-abi-utils
        is_missing_code_error = (
            return_data in ACCEPTABLE_EMPTY_STRINGS and
            web3.eth.getCode(address) in ACCEPTABLE_EMPTY_STRINGS
        )
        if is_missing_code_error:
            msg = (
                "Could not transact with/call contract function, is contract "
                "deployed correctly and chain synced?"
            )
        else:
            msg = (
                "Could not decode contract function call {} return data {} for "
                "output_types {}".format(
                    function_name,
                    return_data,
                    output_types
                )
            )
        raise BadFunctionCallOutput(msg) from e

    _normalizers = itertools.chain(
        BASE_RETURN_NORMALIZERS,
        normalizers,
    )
    normalized_data = map_abi_data(_normalizers, output_types, output_data)

    if len(normalized_data) == 1:
        return normalized_data[0]
    else:
        return normalized_data