Add a way to access and store addresses of deployed contracts.
See original GitHub issueOverview
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 :
- 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"
- 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"
- 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:
- Created 3 years ago
- Comments:5 (2 by maintainers)
Top GitHub Comments
Thanks for your time and reply !
The object you are using to deploy is called a
ContractContainer
. The returned object is aProjectContract
. This returned object is also added withinContractContainer
, which is a container that holds all the objects representing specific deployments of that contract. For example:In a production environment, the
ProjectContract
objects within eachContractContainer
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:
If this script is saved as
example.py
, we can run thedeploy_token
function via: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 thebuild/
subdirectory within your project.