Reputation: 1037
I have a Solidity smart contract ContractFactory
which I am deploying on RSK and developing in Hardhat. ContractFactory
has a deploy
function which produces new Child
smart contracts.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
contract ContractFactory {
event ContractDeployed(address owner, address childContract);
function deploy() public {
Child newContract = new Child(msg.sender);
emit ContractDeployed(msg.sender, address(newContract));
}
}
contract Child {
address owner;
constructor(address _owner) {
owner = _owner;
}
}
Can I know before invoking the deploy
function what address on RSK will a new Child
smart contract receive?
Upvotes: 14
Views: 4148
Reputation: 230
python
you can achieve this like this. You will need the web3.py
or brownie
& rlp
modules installed.#!/usr/bin/python3
from brownie import web3, accounts
import rlp
def get_addr(attacker):
# Convert from hex to bytes. Be sure to drop the leading 0x
sender = bytes.fromhex(attacker.address[2:])
# The nonce is just a number
nonce = attacker.nonce
# Last 20 bytes means the last 40 characters in hexadecimal
contract_address = f"0x{web3.keccak(rlp.encode([sender, nonce])).hex()[-40:]}"
return contract_address
if __name__ == "__main__":
print(get_addr(accounts[0]))
Upvotes: 1
Reputation: 2196
You can go even further and make use of the deterministic deployment technique which exploits CREATE2 specification. Here the address of the future smart contract is a keccak256
hash of the 4 parameters:
0xFF
, a constant that prevents collisions with CREATEkeccak256
of the to-be-deployed contract’s bytecodeNotice that with CREATE2
you can not only predict the deployed smart contract address, but you can actually influence what this address will be by changing the salt
value.
Try adding the following function to your ContractFactory
function deployCreate2(bytes32 _salt) public {
Child newContract = new Child{salt: _salt}(msg.sender);
emit ContractDeployed(msg.sender, address(newContract));
}
With this test you can determine the deployed smart contract address.
it('Should determine the Child address', async () => {
const Child = await ethers.getContractFactory('Child');
const { data: initCode } = Child.getDeployTransaction(deployer.address);
const initCodeHash = ethers.utils.keccak256(initCode);
const salt = ethers.utils.keccak256(0x0);
const childAddress = ethers.utils.getCreate2Address(
factory.address,
salt,
initCodeHash,
);
const deployTx = factory.deployCreate2(salt);
await expect(deployTx)
.to.emit(factory, 'ContractDeployed')
.withArgs(deployer.address, childAddress);
});
Upvotes: 16
Reputation: 379
Yes you can. The deployed smart contract address is a function (keccak256
hash) of 2 parameters:
nonce
which is a transaction count for the deployer address
You can use Ethers.js getTransactionCount
function to find the nonce, and getContractAddress
function to calculate the future smart contract address.Use this test to predict the Child
address:
it('Should predict Child address', async () => {
const nonce = await ethers.provider.getTransactionCount(factory.address);
const anticipatedAddress = ethers.utils.getContractAddress({
from: factory.address,
nonce,
});
const tx = await factory.deploy();
await expect(tx)
.to.emit(factory, 'ContractDeployed')
.withArgs(deployer.address, anticipatedAddress);
});
Upvotes: 13