Hi,
I want to check a contract was deployed or not on a specific network. Is there any way to do this? I've tried Contract.deployed() but don't know it works well.
The deployed is more for contracts deployed using a ContractFactory. If you did use a contract factory, then deployed is very reliable, since it knows the transaction hash that deployed it, and checks the transaction receipt for success.
If you have the transaction hash of a contract deployment, you can get the receipt. If the receipt status is success, the deployment was good.
Thanks, @ricmoo! I want to check if the contract address exists on the network, since the contract could be deployed already on the network using other Truffle Framework or something else. So I am just using not ContractFactory but Contract. I have no transaction hash for the deployment. Can I check the address in this situation?
If you use deployed on a Contract, it simply uses getCode then, which will return true if there is code at the address. This can be unreliable in a few cases:
For most cases though, it should be reliable to use the .deployed, or just use getCode directly on the address.
Hmm. do you mean that we don't have any effective way to confirm that a contract exists or not on a network? I guess that we can't check a contract is usable or not in the second and the third cases even though we use deployed() with proper transaction hash.
I have never experimented with what really happens when you deploy a contract with 0 bytes of init code (I'll be experimenting with that this weekend, as part of ETHCapeTown).
I do not believe there is any way to use the JSON-RPC API to determine for certain whether an address is a deployed contract or not, but if it is a contract you deployed, you likely are not deploying zero-byte contracts, so you should be safe to use the provider.getCode(address) method.
You can detect the second case in some cases, if you know a block between the deployment and the self-destruct blocks, since deployed takes in a n optional parameter of what blockTag to use; however, this also is not reliable on many backends. For example, Etherscan ignores blockTag for getCode, so the EtherscanProvider will detect this and throw an error.
Thank you for the detailed answer! It's very informative!
For clarification, using Contract.deployed() seems to throw in case there's nothing there (4.0.47), and getCode is a method in Provider, not Contract. I think contract's bytecode can be very interesting, and if you're holding a Contract, first place you'd look is Contract's methods, something like bytecode, getByteCode(), or just code or getCode(). I can open a new feature request if that makes more sense :)
So instead of
if (await contract.provider.getCode(contract.address) === "0x") { ... }
it would be cool to be able to do
if (await contract.getCode() === "0x") { ... }
Most helpful comment
I have never experimented with what really happens when you deploy a contract with 0 bytes of init code (I'll be experimenting with that this weekend, as part of ETHCapeTown).
I do not believe there is any way to use the JSON-RPC API to determine for certain whether an address is a deployed contract or not, but if it is a contract you deployed, you likely are not deploying zero-byte contracts, so you should be safe to use the
provider.getCode(address)method.You can detect the second case in some cases, if you know a block between the deployment and the self-destruct blocks, since
deployedtakes in a n optional parameter of what blockTag to use; however, this also is not reliable on many backends. For example, Etherscan ignores blockTag forgetCode, so the EtherscanProvider will detect this and throw an error.