Understand EVM Smart Contract CREATE address

Structure

  • Source Bytecode: combined from the contract source code
  • Constructor Arguments Bytecode (optional): encoded from the constructor • parameter. It’s empty by default constructor()
  • Full Contract Creation Bytecode = concat ( Source Bytecode, Constructor Arguments Bytecode )
  • Calculate the Input Data for contract creation transaction = concat ( Init Code, Full Contract Creation Bytecode )
    • Where Init Code (Optional) = Create code, or function hash, function param

Example

Deploy

There are 2 ways for deployment: Normal CREATE and CREATE2

  • INIT wallet client EOA signer:
const walletClient = createWalletClient({
    account: mnemonicToAccount( "" ),
    chain: mainnnet,
    transport: http(process.env.RPC_URL),
  });

Create contract with Normal CREATE: Create from EOA contract.

  • Deploy transaction from Input Data
    const config = {
      data,
      gas,
      nonce: nonce++,
      chain,
    };
    await walletClient.sendTransaction(config);
  • Calculate the contract address:
address = getContractAddress({
        from: walletClient.account.address,
        nonce: BigInt(nonce - 1),
      });

Create contract with CREATE2: Create a contract from another contract.

  • Deploy transaction from Input Data. The EOA signer will send a transaction to the DETERMINISTIC contract with a creation bytecode, and new contract will be created under DETERMINISTIC (not EOA)
    const config = {
      data,
      gas,
      nonce: nonce++,
      chain,
      to: deterministicDeployer
    };
    await walletClient.sendTransaction(config);
  • Calculate the contract address: address = keccak256(0xFF ++ deployer_address ++ salt ++ keccak256(init_code))[12:]
      const inputData = data.substring(2);
      const salt: Hex = `0x${inputData.substring(0, 64)}`; // 32 bytes = 64 hex characters
      const creationByteCode: Hex = `0x${inputData.substring(64)}`;
      address = getCreate2Address({
        from: deterministicDeployer,
        salt: salt,
        bytecodeHash: keccak256(creationByteCode),
      });

Verify deployment: check if the contract has code

const verifyDeployed = async (addresses: Address[]) => {
    for (const address of addresses) {
      const bytecode = await client.getCode({
        address,
      });
      if (!bytecode || bytecode === '0x') {
        console.log(`CONTRACT ${address} NOT DEPLOYED!!!`);
        // process.exit(1);
      }
    }
  };

Leave a Reply

Your email address will not be published.Required fields are marked *