Smart contracts are programs deployed to the Ethereum network. See the ethereum.org docs for a proper introduction.
To run this example, you will need to install a few extra features:
- The sandbox node provided by eth-tester. You can install it with:
$ pip install -U "web3[tester]"
py-solc-x
. This is the supported route to installing the solidity compilersolc
. You can install it with:
$ pip install py-solc-x
After py-solc-x
is installed, you will need to install a version of solc
. You can install the latest version via a new REPL with:
>>> from solcx import install_solc
>>> install_solc(version='latest')
You should now be set up to run the contract deployment example below:
>>> from web3 import Web3
>>> from solcx import compile_source
# Solidity source code
>>> compiled_sol = compile_source(
... '''
... pragma solidity >0.5.0;
...
... contract Greeter {
... string public greeting;
...
... constructor() public {
... greeting = 'Hello';
... }
...
... function setGreeting(string memory _greeting) public {
... greeting = _greeting;
... }
...
... function greet() view public returns (string memory) {
... return greeting;
... }
... }
... ''',
... output_values=['abi', 'bin']
... )
# retrieve the contract interface
>>> contract_id, contract_interface = compiled_sol.popitem()
# get bytecode / bin
>>> bytecode = contract_interface['bin']
# get abi
>>> abi = contract_interface['abi']
# web3.py instance
>>> w3 = Web3(Web3.EthereumTesterProvider())
# set pre-funded account as sender
>>> w3.eth.default_account = w3.eth.accounts[0]
>>> Greeter = w3.eth.contract(abi=abi, bytecode=bytecode)
# Submit the transaction that deploys the contract
>>> tx_hash = Greeter.constructor().transact()
# Wait for the transaction to be mined, and get the transaction receipt
>>> tx_receipt = w3.eth.wait_for_transaction_receipt(tx_hash)
>>> greeter = w3.eth.contract(
... address=tx_receipt.contractAddress,
... abi=abi
... )
>>> greeter.functions.greet().call()
'Hello'
>>> tx_hash = greeter.functions.setGreeting('Nihao').transact()
>>> tx_receipt = w3.eth.wait_for_transaction_receipt(tx_hash)
>>> greeter.functions.greet().call()
'Nihao'
These factories are not intended to be initialized directly. Instead, create contract objects using the w3.eth.contract() <web3.eth.Eth.contract>
method. By default, the contract factory is Contract
.
Each Contract Factory exposes the following properties.
Each Contract Factory exposes the following methods.
Creates a new event filter, an instance of :py
web3.utils.filters.LogFilter
.
fromBlock
is a mandatory field. Defines the starting block (exclusive) filter block range. It can be either the starting block number, or 'latest' for the last mined block, or 'pending' for unmined transactions. In the case offromBlock
, 'latest' and 'pending' set the 'latest' or 'pending' block as a static value for the starting filter block.toBlock
optional. Defaults to 'latest'. Defines the ending block (inclusive) in the filter block range. Special values 'latest' and 'pending' set a dynamic range that always includes the 'latest' or 'pending' blocks for the filter's upper block range.address
optional. Defaults to the contract address. The filter matches the event logs emanating fromaddress
.argument_filters
, optional. Expects a dictionary of argument names and values. When provided event logs are filtered for the event argument values. Event arguments can be both indexed or unindexed. Indexed values with be translated to their corresponding topic arguments. Unindexed arguments will be filtered using a regular expression.topics
optional, accepts the standard JSON-RPC topics argument. See the JSON-RPC documentation for eth_newFilter more information on thetopics
parameters.
Note
Contract
methods all_functions
, get_function_by_signature
, find_functions_by_name
, get_function_by_name
, get_function_by_selector
, find_functions_by_args
and get_function_by_args
can only be used when abi is provided to the contract.
Note
web3.py rejects the initialization of contracts that have more than one function with the same selector or signature. eg. blockHashAddendsInexpansible(uint256)
and blockHashAskewLimitary(uint256)
have the same selector value equal to 0x00000000
. A contract containing both of these functions will be rejected.
Below is an example of a contract that has multiple functions of the same name, and the arguments are ambiguous.
>>> contract_source_code = """
pragma solidity ^0.4.21;
contract AmbiguousDuo {
function identity(uint256 input, bool uselessFlag) returns (uint256) {
return input;
}
function identity(int256 input, bool uselessFlag) returns (int256) {
return input;
}
}
"""
# fast forward all the steps of compiling and deploying the contract.
>>> ambiguous_contract.functions.identity(1, True) # raises Web3ValidationError
>>> identity_func = ambiguous_contract.get_function_by_signature('identity(uint256,bool)')
>>> identity_func(1, True)
<Function identity(uint256,bool) bound to (1, True)>
>>> identity_func(1, True).call()
1
By default, web3 is strict when it comes to hex and bytes values, as of v6
. If an abi specifies a byte size, but the value that gets passed in is not the specified size, web3 will invalidate the value. For example, if an abi specifies a type of bytes4
, web3 will invalidate the following values:
Input | Reason |
---|---|
'' |
Needs to be prefixed with a "0x" to be interpreted as an empty hex string |
2 |
Wrong type |
'ah' |
String is not valid hex |
'1234' |
Needs to either be a bytestring (b'1234') or be a hex value of the right size, prefixed with 0x (in this case: '0x31323334') |
b'' |
Needs to have exactly 4 bytes |
b'ab' |
Needs to have exactly 4 bytes |
'0xab' |
Needs to have exactly 4 bytes |
'0x6162636464' |
Needs to have exactly 4 bytes |
However, you may want to be less strict with acceptable values for bytes types. This may prove useful if you trust that values coming through are what they are meant to be with respect to the ABI. In this case, the automatic padding might be convenient for inferred types. For this, you can set the w3.strict_bytes_type_checking
flag to False
, which is available on the Web3 instance. A Web3 instance which has this flag set to False
will have a less strict set of rules on which values are accepted. A bytes
type will allow values as a hex string, a bytestring, or a regular Python string that can be decoded as a hex. 0x-prefixed hex strings are also not required.
Valid byte and hex strings for a non-strict bytes4 type
- A Python string that is not prefixed with
0x
is valid.- A bytestring whose length is less than the specified byte size is valid.
Input | Normalizes to |
---|---|
'' |
b'\x00\x00\x00\x00' |
'0x' |
b'\x00\x00\x00\x00' |
b'' |
b'\x00\x00\x00\x00' |
b'ab' |
b'ab\x00\x00' |
'0xab' |
b'\xab\x00\x00\x00' |
'1234' |
b'\x124\x00\x00' |
'0x61626364' |
b'abcd' |
'1234' |
b'1234' |
Taking the following contract code as an example:
arrayscontract
from web3 import Web3 w3 = Web3(Web3.EthereumTesterProvider()) bytecode = "608060405234801561001057600080fd5b506040516106103803806106108339810180604052602081101561003357600080fd5b81019080805164010000000081111561004b57600080fd5b8281019050602081018481111561006157600080fd5b815185602082028301116401000000008211171561007e57600080fd5b5050929190505050806000908051906020019061009c9291906100a3565b505061019c565b82805482825590600052602060002090600f0160109004810192821561015a5791602002820160005b8382111561012a57835183826101000a81548161ffff02191690837e010000000000000000000000000000000000000000000000000000000000009004021790555092602001926002016020816001010492830192600103026100cc565b80156101585782816101000a81549061ffff021916905560020160208160010104928301926001030261012a565b505b509050610167919061016b565b5090565b61019991905b8082111561019557600081816101000a81549061ffff021916905550600101610171565b5090565b90565b610465806101ab6000396000f3fe608060405260043610610051576000357c0100000000000000000000000000000000000000000000000000000000900480633b3230ee14610056578063d7c8a410146100e7578063dfe3136814610153575b600080fd5b34801561006257600080fd5b5061008f6004803603602081101561007957600080fd5b8101908080359060200190929190505050610218565b60405180827dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916815260200191505060405180910390f35b3480156100f357600080fd5b506100fc61026c565b6040518080602001828103825283818151815260200191508051906020019060200280838360005b8381101561013f578082015181840152602081019050610124565b505050509050019250505060405180910390f35b34801561015f57600080fd5b506102166004803603602081101561017657600080fd5b810190808035906020019064010000000081111561019357600080fd5b8201836020820111156101a557600080fd5b803590602001918460208302840111640100000000831117156101c757600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600081840152601f19601f820116905080830192505050505050509192919290505050610326565b005b60008181548110151561022757fe5b9060005260206000209060109182820401919006600202915054906101000a90047e010000000000000000000000000000000000000000000000000000000000000281565b6060600080548060200260200160405190810160405280929190818152602001828054801561031c57602002820191906000526020600020906000905b82829054906101000a90047e01000000000000000000000000000000000000000000000000000000000000027dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916815260200190600201906020826001010492830192600103820291508084116102a95790505b5050505050905090565b806000908051906020019061033c929190610340565b5050565b82805482825590600052602060002090600f016010900481019282156103f75791602002820160005b838211156103c757835183826101000a81548161ffff02191690837e01000000000000000000000000000000000000000000000000000000000000900402179055509260200192600201602081600101049283019260010302610369565b80156103f55782816101000a81549061ffff02191690556002016020816001010492830192600103026103c7565b505b5090506104049190610408565b5090565b61043691905b8082111561043257600081816101000a81549061ffff02191690555060010161040e565b5090565b9056fea165627a7a72305820a8f9f1f4815c1eedfb8df31298a5cd13b198895de878871328b5d96296b69b4e0029" abi = ''' [ { "constant": true, "inputs": [ { "name": "", "type": "uint256" } ], "name": "bytes2Value", "outputs": [ { "name": "", "type": "bytes2" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [], "name": "getBytes2Value", "outputs": [ { "name": "", "type": "bytes2[]" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": false, "inputs": [ { "name": "_bytes2Value", "type": "bytes2[]" } ], "name": "setBytes2Value", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function" }, { "inputs": [ { "name": "_bytes2Value", "type": "bytes2[]" } ], "payable": false, "stateMutability": "nonpayable", "type": "constructor" } ] '''.strip()
>>> # pragma solidity >=0.4.22 <0.6.0;
...
... # contract ArraysContract {
... # bytes2[] public bytes2Value;
... # constructor(bytes2[] memory _bytes2Value) public {
... # bytes2Value = _bytes2Value;
... # }
... # function setBytes2Value(bytes2[] memory _bytes2Value) public {
... # bytes2Value = _bytes2Value;
... # }
... # function getBytes2Value() public view returns (bytes2[] memory) {
... # return bytes2Value;
... # }
... # }
>>> # abi = "..."
>>> # bytecode = "6080..."
arrayscontract
>>> arrays_contract_instance = w3.eth.contract(abi=abi, bytecode=bytecode)
>>> tx_hash = arrays_contract_instance.constructor([b'bb']).transact() >>> tx_receipt = w3.eth.wait_for_transaction_receipt(tx_hash) >>> arrays_contract = w3.eth.contract( ... address=tx_receipt.contractAddress, ... abi=abi ... ) >>> arrays_contract.functions.getBytes2Value().call() [b'bb']
>>> # set value with appropriate byte size >>> arrays_contract.functions.setBytes2Value([b'aa']).transact({'gas': 420000, "maxPriorityFeePerGas": 10 ** 9, "maxFeePerGas": 10 ** 9}) HexBytes('0xcb95151142ea56dbf2753d70388aef202a7bb5a1e323d448bc19f1d2e1fe3dc9') >>> # check value >>> arrays_contract.functions.getBytes2Value().call() [b'aa']
>>> # trying to set value without appropriate size (bytes2) is not valid >>> arrays_contract.functions.setBytes2Value([b'b']).transact() Traceback (most recent call last): ... web3.exceptions.Web3ValidationError: Could not identify the intended function with name >>> # check value is still b'aa' >>> arrays_contract.functions.getBytes2Value().call() [b'aa']
>>> # disabling strict byte checking... >>> w3.strict_bytes_type_checking = False
>>> tx_hash = arrays_contract_instance.constructor([b'b']).transact() >>> tx_receipt = w3.eth.wait_for_transaction_receipt(tx_hash) >>> arrays_contract = w3.eth.contract( ... address=tx_receipt.contractAddress, ... abi=abi ... ) >>> # check value is zero-padded... i.e. b'bx00' >>> arrays_contract.functions.getBytes2Value().call() [b'bx00']
>>> # set the flag back to True >>> w3.strict_bytes_type_checking = True
>>> arrays_contract.functions.setBytes2Value([b'a']).transact() Traceback (most recent call last): ... web3.exceptions.Web3ValidationError: Could not identify the intended function with name
The named functions exposed through the :pyContract.functions
property are of the ContractFunction type. This class is not to be used directly, but instead through :pyContract.functions
.
For example:
myContract = web3.eth.contract(address=contract_address, abi=contract_abi) twentyone = myContract.functions.multiply7(3).call()
If you have the function name in a variable, you might prefer this alternative:
func_to_call = 'multiply7' contract_func = myContract.functions[func_to_call] twentyone = contract_func(3).call()
:pyContractFunction
provides methods to interact with contract functions. Positional and keyword arguments supplied to the contract function subclass will be used to find the contract function by signature, and forwarded to the contract function when applicable.
EIP-3668 introduced support for the OffchainLookup
revert / CCIP Read support. CCIP Read is set to True
for calls by default, as recommended in EIP-3668. This is done via a global global_ccip_read_enabled
flag on the provider. If raising the OffchainLookup
revert is preferred for a specific call, the ccip_read_enabled
flag on the call may be set to False
.
>>> # raises the revert instead of handling the offchain lookup >>> myContract.functions.revertsWithOffchainLookup(myData).call(ccip_read_enabled=False) *** web3.exceptions.OffchainLookup
Disabling CCIP Read support can be useful if a transaction needs to be sent to the callback function. In such cases, "preflighting" with an eth_call
, handling the OffchainLookup
, and sending the data via a transaction may be necessary. See ccip-read-example
in the examples section for how to preflight a transaction with a contract call.
Similarly, if CCIP Read is globally set to False
via the global_ccip_read_enabled
flag on the provider, it may be enabled on a per-call basis - overriding the global flag. This ensures only explicitly enabled calls will handle the OffchainLookup
revert appropriately.
>>> # global flag set to `False` >>> w3.provider.global_ccip_read_enabled = False >>> # does not raise the revert since explicitly enabled on the call: >>> response = myContract.functions.revertsWithOffchainLookup(myData).call(ccip_read_enabled=True)
If the function called results in a revert
error, a ContractLogicError
will be raised. If there is an error message with the error, web3.py attempts to parse the message that comes back and return it to the user as the error string. As of v6.3.0, the raw data is also returned and can be accessed via the data
attribute on ContractLogicError
.
The Contract Factory also offers an API to interact with the fallback function, which supports four methods like normal functions:
The named events exposed through the :pyContract.events
property are of the ContractEvents type. This class is not to be used directly, but instead through :pyContract.events
.
For example:
myContract = web3.eth.contract(address=contract_address, abi=contract_abi) tx_hash = myContract.functions.myFunction().transact() receipt = web3.eth.get_transaction_receipt(tx_hash) myContract.events.myEvent().process_receipt(receipt)
:pyContractEvent
provides methods to interact with contract events. Positional and keyword arguments supplied to the contract event subclass will be used to find the contract event by signature.
The Event Log Object is a python dictionary with the following keys:
args
: Dictionary - The arguments coming from the event.event
: String - The event name.logIndex
: Number - integer of the log index position in the block.transactionIndex
: Number - integer of the transactions index position log was created from.transactionHash
: String, 32 Bytes - hash of the transactions this log was created from.address
: String, 32 Bytes - address from which this log originated.blockHash
: String, 32 Bytes - hash of the block where this log was in. null when it's pending.blockNumber
: Number - the block number where this log was in. null when it's pending.
create_filter
from web3 import Web3 from hexbytes import HexBytes w3 = Web3(Web3.EthereumTesterProvider()) bytecode = '6060604052341561000c57fe5b604051602080610acb833981016040528080519060200190919050505b620f42408114151561003b5760006000fd5b670de0b6b3a76400008102600281905550600254600060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055505b505b610a27806100a46000396000f30060606040523615610097576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806306fdde0314610099578063095ea7b31461013257806318160ddd1461018957806323b872dd146101af578063313ce5671461022557806370a082311461025157806395d89b411461029b578063a9059cbb14610334578063dd62ed3e1461038b575bfe5b34156100a157fe5b6100a96103f4565b60405180806020018281038252838181518152602001915080519060200190808383600083146100f8575b8051825260208311156100f8576020820191506020810190506020830392506100d4565b505050905090810190601f1680156101245780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561013a57fe5b61016f600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803590602001909190505061042e565b604051808215151515815260200191505060405180910390f35b341561019157fe5b610199610521565b6040518082815260200191505060405180910390f35b34156101b757fe5b61020b600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803573ffffffffffffffffffffffffffffffffffffffff16906020019091908035906020019091905050610527565b604051808215151515815260200191505060405180910390f35b341561022d57fe5b610235610791565b604051808260ff1660ff16815260200191505060405180910390f35b341561025957fe5b610285600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610796565b6040518082815260200191505060405180910390f35b34156102a357fe5b6102ab6107e0565b60405180806020018281038252838181518152602001915080519060200190808383600083146102fa575b8051825260208311156102fa576020820191506020810190506020830392506102d6565b505050905090810190601f1680156103265780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561033c57fe5b610371600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803590602001909190505061081a565b604051808215151515815260200191505060405180910390f35b341561039357fe5b6103de600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610973565b6040518082815260200191505060405180910390f35b604060405190810160405280600981526020017f54657374546f6b656e000000000000000000000000000000000000000000000081525081565b600081600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925846040518082815260200191505060405180910390a3600190505b92915050565b60025481565b600081600060008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410806105f1575081600160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054105b156105fc5760006000fd5b81600060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254019250508190555081600060008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254039250508190555081600160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825403925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a3600190505b9392505050565b601281565b6000600060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490505b919050565b604060405190810160405280600481526020017f544553540000000000000000000000000000000000000000000000000000000081525081565b600081600060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410156108695760006000fd5b81600060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254039250508190555081600060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a3600190505b92915050565b6000600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490505b929150505600a165627a7a723058205071371ee2a4a1be3c96e77d939cdc26161a256fdd638efc08bd33dfc65d3b850029' ABI = '[{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"type":"function","stateMutability":"view"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_value","type":"uint256"}],"name":"approve","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function","stateMutability":"nonpayable"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function","stateMutability":"view"},{"constant":false,"inputs":[{"name":"_from","type":"address"},{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function","stateMutability":"nonpayable"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint8"}],"payable":false,"type":"function","stateMutability":"view"},{"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function","stateMutability":"view"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"type":"function","stateMutability":"view"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transfer","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function","stateMutability":"nonpayable"},{"constant":true,"inputs":[{"name":"_owner","type":"address"},{"name":"_spender","type":"address"}],"name":"allowance","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function","stateMutability":"view"},{"inputs":[{"name":"_totalSupply","type":"uint256"}],"payable":false,"type":"constructor","stateMutability":"nonpayable"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"address"},{"indexed":true,"name":"to","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"owner","type":"address"},{"indexed":true,"name":"spender","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Approval","type":"event"}]' my_token_contract = w3.eth.contract(abi=ABI, bytecode=bytecode) alice, bob = w3.eth.accounts[0], w3.eth.accounts[1] assert alice == '0x7E5F4552091A69125d5DfCb7b8C2659029395Bdf', alice assert bob == '0x2B5AD5c4795c026514f8317c7a215E218DcCD6cF', bob tx_hash = my_token_contract.constructor(1000000).transact({'from': alice, 'gas': 899000, 'gasPrice': Web3.to_wei(1, 'gwei')}) assert tx_hash == HexBytes('0x49e3da72a95e4074a9eaea7b438c73ca154627d317e58abeae914e3769a15044'), tx_hash txn_receipt = w3.eth.wait_for_transaction_receipt(tx_hash) assert txn_receipt['contractAddress'] == '0xF2E246BB76DF876Cef8b38ae84130F4F55De395b', txn_receipt['contractAddress'] contract_address = txn_receipt['contractAddress'] contract = w3.eth.contract(contract_address, abi=ABI) total_supply = contract.functions.totalSupply().call() decimals = 10 ** 18 assert total_supply == 1000000 * decimals, total_supply tx_hash = contract.functions.transfer(alice, 10).transact({'gas': 899000, 'gasPrice': Web3.to_wei(1, 'gwei')}) tx_receipt = w3.eth.wait_for_transaction_receipt(tx_hash)
create_filter
>>> transfer_filter = my_token_contract.events.Transfer.create_filter(fromBlock="0x0", argument_filters={'from': '0x7E5F4552091A69125d5DfCb7b8C2659029395Bdf'}) >>> transfer_filter.get_new_entries() [AttributeDict({'args': AttributeDict({'from': '0x7E5F4552091A69125d5DfCb7b8C2659029395Bdf', 'to': '0x7E5F4552091A69125d5DfCb7b8C2659029395Bdf', 'value': 10}), 'event': 'Transfer', 'logIndex': 0, 'transactionIndex': 0, 'transactionHash': HexBytes('0x9da859237e7259832b913d51cb128c8d73d1866056f7a41b52003c953e749678'), 'address': '0xF2E246BB76DF876Cef8b38ae84130F4F55De395b', 'blockHash': HexBytes('...'), 'blockNumber': 2})] >>> transfer_filter.get_new_entries() [] >>> tx_hash = contract.functions.transfer(alice, 10).transact({'gas': 899000, 'gasPrice': 1000000000}) >>> tx_receipt = w3.eth.wait_for_transaction_receipt(tx_hash) >>> transfer_filter.get_new_entries() [AttributeDict({'args': AttributeDict({'from': '0x7E5F4552091A69125d5DfCb7b8C2659029395Bdf', 'to': '0x7E5F4552091A69125d5DfCb7b8C2659029395Bdf', 'value': 10}), 'event': 'Transfer', 'logIndex': 0, 'transactionIndex': 0, 'transactionHash': HexBytes('...'), 'address': '0xF2E246BB76DF876Cef8b38ae84130F4F55De395b', 'blockHash': HexBytes('...'), 'blockNumber': 3})] >>> transfer_filter.get_all_entries() [AttributeDict({'args': AttributeDict({'from': '0x7E5F4552091A69125d5DfCb7b8C2659029395Bdf', 'to': '0x7E5F4552091A69125d5DfCb7b8C2659029395Bdf', 'value': 10}), 'event': 'Transfer', 'logIndex': 0, 'transactionIndex': 0, 'transactionHash': HexBytes('...'), 'address': '0xF2E246BB76DF876Cef8b38ae84130F4F55De395b', 'blockHash': HexBytes('...'), 'blockNumber': 2}), AttributeDict({'args': AttributeDict({'from': '0x7E5F4552091A69125d5DfCb7b8C2659029395Bdf', 'to': '0x7E5F4552091A69125d5DfCb7b8C2659029395Bdf', 'value': 10}), 'event': 'Transfer', 'logIndex': 0, 'transactionIndex': 0, 'transactionHash': HexBytes('...'), 'address': '0xF2E246BB76DF876Cef8b38ae84130F4F55De395b', 'blockHash': HexBytes('...'), 'blockNumber': 3})]
The ContractCaller
class provides an API to call functions in a contract. This class is not to be used directly, but instead through Contract.caller
.
There are a number of different ways to invoke the ContractCaller
.
For example:
contractcaller
import json from web3 import Web3 w3 = Web3(Web3.EthereumTesterProvider()) bytecode = "0x606060405261022e806100126000396000f360606040523615610074576000357c01000000000000000000000000000000000000000000000000000000009004806316216f391461007657806361bc221a146100995780637cf5dab0146100bc578063a5f3c23b146100e8578063d09de08a1461011d578063dcf537b11461014057610074565b005b610083600480505061016c565b6040518082815260200191505060405180910390f35b6100a6600480505061017f565b6040518082815260200191505060405180910390f35b6100d26004808035906020019091905050610188565b6040518082815260200191505060405180910390f35b61010760048080359060200190919080359060200190919050506101ea565b6040518082815260200191505060405180910390f35b61012a6004805050610201565b6040518082815260200191505060405180910390f35b6101566004808035906020019091905050610217565b6040518082815260200191505060405180910390f35b6000600d9050805080905061017c565b90565b60006000505481565b6000816000600082828250540192505081905550600060005054905080507f3496c3ede4ec3ab3686712aa1c238593ea6a42df83f98a5ec7df9834cfa577c5816040518082815260200191505060405180910390a18090506101e5565b919050565b6000818301905080508090506101fb565b92915050565b600061020d6001610188565b9050610214565b90565b60006007820290508050809050610229565b91905056" ABI = json.loads('[{"constant":false,"inputs":[],"name":"return13","outputs":[{"name":"result","type":"int256"}],"type":"function"},{"constant":true,"inputs":[],"name":"counter","outputs":[{"name":"","type":"uint256"}],"type":"function"},{"constant":false,"inputs":[{"name":"amt","type":"uint256"}],"name":"increment","outputs":[{"name":"result","type":"uint256"}],"type":"function"},{"constant":false,"inputs":[{"name":"a","type":"int256"},{"name":"b","type":"int256"}],"name":"add","outputs":[{"name":"result","type":"int256"}],"type":"function"},{"constant":false,"inputs":[],"name":"increment","outputs":[{"name":"","type":"uint256"}],"type":"function"},{"constant":false,"inputs":[{"name":"a","type":"int256"}],"name":"multiply7","outputs":[{"name":"result","type":"int256"}],"type":"function"},{"anonymous":false,"inputs":[{"indexed":false,"name":"value","type":"uint256"}],"name":"increased","type":"event"}]') contract = w3.eth.contract(abi=ABI, bytecode=bytecode) deploy_txn = contract.constructor().transact() deploy_receipt = w3.eth.wait_for_transaction_receipt(deploy_txn) address = deploy_receipt.contractAddress
contractcaller
>>> myContract = w3.eth.contract(address=address, abi=ABI) >>> twentyone = myContract.caller.multiply7(3) >>> twentyone 21
It can also be invoked using parentheses:
contractcaller
>>> twentyone = myContract.caller().multiply7(3) >>> twentyone 21
And a transaction dictionary, with or without the transaction
keyword. You can also optionally include a block identifier. For example:
contractcaller
>>> from_address = w3.eth.accounts[1] >>> twentyone = myContract.caller({'from': from_address}).multiply7(3) >>> twentyone 21 >>> twentyone = myContract.caller(transaction={'from': from_address}).multiply7(3) >>> twentyone 21 >>> twentyone = myContract.caller(block_identifier='latest').multiply7(3) >>> twentyone 21
Like :pyContractFunction
, :pyContractCaller
provides methods to interact with contract functions. Positional and keyword arguments supplied to the contract caller subclass will be used to find the contract function by signature, and forwarded to the contract function when applicable.
web3.py accepts struct arguments as dictionaries. This format also supports nested structs. Let's take a look at a quick example. Given the following Solidity contract:
contract Example {
address addr;
struct S1 {
address a1;
address a2;
}
struct S2 {
bytes32 b1;
bytes32 b2;
}
struct X {
S1 s1;
S2 s2;
address[] users;
}
function update(X memory x) public {
addr = x.s1.a2;
}
function retrieve() public view returns (address) {
return addr;
}
}
You can interact with web3.py contract API as follows:
# deploy or lookup the deployed contract, then:
>>> deployed_contract.functions.retrieve().call()
'0x0000000000000000000000000000000000000000'
>>> deployed_contract.functions.update({'s1': ['0x0000000000000000000000000000000000000001', '0x0000000000000000000000000000000000000002'], 's2': [b'0'*32, b'1'*32], 'users': []}).transact()
>>> deployed_contract.functions.retrieve().call()
'0x0000000000000000000000000000000000000002'