6

I have a contract that creates other contracts. It then pushes these contracts in an array, address[] public newContracts. The only problem is I'm having trouble calling them from python.

factory.json is my abi and the address and web3 seem to connect fine, just can't call the variables correctly.

Thanks for any help

from web3 import Web3
import json
from web3.providers.rpc import HTTPProvider
contractAddress = '0x3c7bec02bd4fa73dce24413d2a13c02e1a91e858'
web3 = Web3(HTTPProvider('https://ropsten.infura.io'))
with open('factory.json', 'r') as abi_definition:
    abi = json.load(abi_definition)
print (web3.eth.blockNumber)


fContract = web3.eth.contract(abi,contractAddress)
print ('Creator',fContract.call().creator)
print ('Contracts',fContract.call().newContracts)
print ('OracleName',fContract.call().oracleName)
0

3 Answers 3

6

Two Issues

  1. Retrieving the creator value

    print ('Creator',fContract.call().creator)

    Use fContract.call().creator() here.

  2. Creating the contract

    fContract = web3.eth.contract(abi,contractAddress)

    Use web3.eth.contract(contractAddress, abi=abi) here.

Why?

  1. Any time you access data in a contract from outside the EVM, you access it using a function. This is true even when you are accessing a public variable. Take a look at the ABI, which sets {"type":"function"} on your public variable.

  2. The arguments (abi, contractAddress) will work in Web3.py v3, but break in v4. The reversed order and abi as a keyword argument will work in both v3 and v4, so it's best to always use the newer syntax: (contractAddress, abi=abi) See the API docs for more.

Where can I read more?

Here are some lightly edited examples from the web3.py Contract call docs, using the newest Web3.py v4 syntax:

# example
In [1]: my_contract.functions.multiply7(3).call()
Out[1]: 21

In [2]: token_contract.functions.myBalance().call({'from': web3.eth.coinbase})
Out[2]: 12345
# the token balance for `web3.eth.coinbase`

The docs also discuss a slightly more succinct access, with a bit more setup. An example for your contract looks like:

from web3.contract import ConciseContract
reader = ConciseContract(fContract)

assert reader.creator()      == fContract.functions.creator().call()
assert reader.newContracts() == fContract.functions.newContracts().call()
assert reader.oracleName()   == fContract.functions.oracleName().call()
1

Try using fContract.creator.call() instead. It should work.

1
  • I was hopeful, but unfortuneately I get:AttributeError: 'Contract' object has no attribute 'creator'
    – thefett
    Commented Jun 18, 2017 at 1:34
1

fcontract.functions.creator().call() seems to work.

1
  • this code doesn't work
    – abhi3700
    Commented Jul 9, 2021 at 11:45

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.