Owans
Owans

Reputation: 1037

How to find out in advance the address of the smart contract I am going to deploy?

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

Answers (3)

Saikat Karmakar
Saikat Karmakar

Reputation: 230

  • For 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]))


Sample output

Upvotes: 1

Aleks Shenshin
Aleks Shenshin

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:

  1. 0xFF, a constant that prevents collisions with CREATE
  2. the sender’s own address
  3. salt (an arbitrary 32 bytes long value provided by the sender)
  4. keccak256 of the to-be-deployed contract’s bytecode

Notice 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

Ahsan
Ahsan

Reputation: 379

Yes you can. The deployed smart contract address is a function (keccak256 hash) of 2 parameters:

  1. the deployer address (EAO or another smart contract)
  2. the 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

Related Questions