question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Add a way to access and store addresses of deployed contracts.

See original GitHub issue

Overview

Hi,

Chained deployment of contract, where you get the data from a previously deployed contract is different scripts, is currently difficult and error-prone. This is due to the fact that there is no (as far as I understand the docs) way to refer to previously deployed instances (address + contract container) when executing multiple scripts separately.

The only way I found is to copy-paste the address in the scripts. Example :

We have two contracts : tokenContract and managingContract.

1_deploy_token.py

from brownie import tokenContract

def main():
    acct = accounts.load('dev')
    tokenContract.deploy({from:acct})

As a result we get a console print of the deployment address.

Transaction sent: [transaction hash]
  Gas price: 10.0 gwei   Gas limit: 160000   Nonce: 5
  tokenContract.constructor confirmed - Block: 721000   Gas used: 1427907 (90.91%)
  tokenContract deployed at: "0xeD24FC36d5Ee211Ea25A80239Fb8C4Cfd80f12Ee"

The address is seemingly saved since running tokenContract in the console returns : [<tokenContract Contract '0xeD24FC36d5Ee211Ea25A80239Fb8C4Cfd80f12Ee'>]

However the following code returns an error:

print(tokenContract.address)

> File "<console>", line 1, in <module>
AttributeError: 'ContractContainer' object has no attribute 'address'

As a consequence, if we want to run a second script using the deployement address of the first, we need to paste it manually:

2_managing_contract.py

from brownie import tokenContract, managingContract

def main():
    acct = accounts.load('dev')
    managing = managingContract.deploy({from:acct}), "0xeD24FC36d5Ee211Ea25A80239Fb8C4Cfd80f12Ee")

The need to copy-paste address is a source of error, especially in the following cases:

  • Reuse of the script (what does the address belong to ?)
  • Deployment of many contracts in the first script: the risk to paste the wrong address is high.

Besides, there is no easy way to find back the contracts implementation if the terminal/console is shut down. We need then to browse manually through the deployment folder’s jsons - again, a source of potential errors.

Specification

We need :

  1. A getter function for the deployment address of a ContractContainer that is stored in the deployment map. This is the standard way shown in the doc and there’s no way to get the address from the deployed ContractContainer object[1], which is quite confusing since it’s the main info about the instance. Here’s a simple implementation:
from brownie import tokenContract

def main():
    acct = accounts.load('dev')
    tokenContract.deploy({from:acct})
    # Here's the getter function:
    print(tokenContract.address)

> "0xeD24FC36d5Ee211Ea25A80239Fb8C4Cfd80f12Ee"

Since the address is saved in the developement map, we should be able to do this too:

# tokenContract has been deployed in another script run before this
from brownie import tokenContract

def main():
    print(tokenContract.address)

> "0xeD24FC36d5Ee211Ea25A80239Fb8C4Cfd80f12Ee"
  1. We may not want a mismatch between ContractContainer and the deployed ContractContainer.

As a result, we can add to it a method which allows to return an instanciated version of a deployed and saved ContractContainer (As you would get with accounts.load(‘dev’).deploy(tokenContract)). This is how Truffle does it by the way:

# tokenContract has been deployed in another script run before this
from brownie import tokenContract

# Here's the method
token = tokenContract.deployed()
print(token.address)

> "0xeD24FC36d5Ee211Ea25A80239Fb8C4Cfd80f12Ee"
  1. A nice to have would be a global clean command-line function, removing every instance, just like --reset in Truffle.

[1]: Aside from copy-pasting and accessing .address attribute from a contract deployed with account.load('id').deploy(TokenContract) - which isn’t persistent between sessions anyway.

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Comments:5 (2 by maintainers)

github_iconTop GitHub Comments

2reactions
Maxence-Lcommented, Mar 19, 2021

Thanks for your time and reply !

2reactions
iamdefinitelyahumancommented, Mar 19, 2021

The object you are using to deploy is called a ContractContainer. The returned object is a ProjectContract. This returned object is also added within ContractContainer, which is a container that holds all the objects representing specific deployments of that contract. For example:

>>> type(MyContract)
<class 'brownie.network.contract.ContractContainer'>
>>> MyContract
[]  # currently empty

>>> deployment = MyContract.deploy({'from': accounts[0]})
Transaction sent: 0x98e9903d54aba84ec56178611043289e0b6d11877fec6da0e92cbf5a91a36748
  Gas price: 0.0 gwei   Gas limit: 12000000   Nonce: 0
  MyContract.constructor confirmed - Block: 1   Gas used: 438945 (3.66%)
  MyContract deployed at: 0xd495633B90a237de510B4375c442C0469D3C161C

>>> type(deployment)
<class 'brownie.network.contract.ProjectContract'>

>>> MyContract
[<MyContract Contract '0xd495633B90a237de510B4375c442C0469D3C161C'>]  # now contains 1 ProjectContract
>>> MyContract == deployment
False  # the container is not the deployment
>>> MyContract[0] == deployment
True  # the first object within the container IS the deployment

In a production environment, the ProjectContract objects within each ContractContainer object persist between sessions. So you can reference them between scripts by simply importing the container and pointing at index -1 for the most recent deployment.

More generally, you can chain your deployment functions together within a single script so that you don’t have issues with persistence when working in a local development environment:

from brownie import tokenContract, managingContract

def deploy_token():
    acct = accounts.load('dev')
    return acct.deploy(tokenContract)

def deploy_manager():
    acct = accounts.load('dev')
    managing = acct.deploy(managingContract, tokenContract[-1])

def main():
    deploy_token()
    deploy_manager()

If this script is saved as example.py, we can run the deploy_token function via:

brownie run example deploy_token

If you want to remove a deployment artifact in a persistent environment, you can use e.g. del MyContract[0]. Or for a more nuclear option, delete the build/ subdirectory within your project.

Read more comments on GitHub >

github_iconTop Results From Across the Web

What is the right way to store and retrieve a contract address?
Ideally, you will be interacting with the contract thorough out your application. You can store it in database, locally or even hardcode the ......
Read more >
Getting the address of a contract deployed by another contract
1 Store the Address and Return it: Store the address in the contract as an attribute and retrieve it using a normal getter...
Read more >
Deploying and interacting with smart contracts
If you want to learn how to deploy and use contracts on a public blockchain, like the Ethereum testnets, head to our Connecting...
Read more >
How to use old/deployed smart contract in Remix IDE - YouTube
Quick tutorial on how to use already deployed smart contract from Remix IDE. #ethereum #remix #solidityBlog: https://fullstak.pl/Instagram: ...
Read more >
Interact with a deployed contract - Hyperledger Besu
To perform a write operation, send a transaction to update the stored value. As with the get call, you need to use the...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found