Skip to content

一文详解solidity中通过CREATE2操作码 #94

@MagicalBridge

Description

@MagicalBridge

基本概念:

CREATE2 是 Solidity 中的一个操作码,用于创建新的智能合约。它是在以太坊的君士坦丁堡硬分叉中引入的。

主要特性:

1、确定性地址: 与标准 CREATE 操作码不同,CREATE2 允许您在实际部署新合约之前计算新合约的地址。

2、基于“加盐”操作: 它使用“盐”(随机值)作为地址计算的一部分,使开发人员可以更好地控制结果地址。

3、可预测的部署: 相同的初始化代码和盐将始终产生相同的地址,无论何时何地部署。

工作原理:

使用 CREATE2 部署的合约的地址计算如下:

address = keccak256(0xff ++ senderAddress ++ salt ++ keccak256(initCode))[12:]

其中:

  • 0xff: 是常量字节,如果表示成10进制就是255。
  • senderAddress:是创建新合约的合约地址。
  • salt:创建者选择的32字节的值
  • initCode:是待创建合约的初始化代码

在solidity中如何使用:

我们看如下代码:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract SimpleContract {
  uint256 public value;

  constructor(uint256 _value) {
    value = _value;
  }
}

contract Factory {
  event Deployed(address addr);

  function deploy(bytes32 salt, uint256 _value) public returns (address) {
    // 合约的字节码
    bytes memory bytecode = abi.encodePacked(
      type(SimpleContract).creationCode,
      abi.encode(_value)
    );

    address addr;
    assembly {
      // 使用 CREATE2 操作码部署合约
      addr := create2(0, add(bytecode, 0x20), mload(bytecode), salt)
      // 检查合约是否部署成功
      if iszero(extcodesize(addr)) {
        revert(0, 0)
      }
    }

    emit Deployed(addr);
    return addr;
  }

  function computeAddress(bytes32 salt, bytes32 bytecodeHash) public view returns (address) {
    return address(uint160(uint256(keccak256(abi.encodePacked(
      bytes1(0xff),
      address(this),
      salt,
      bytecodeHash
    )))));
  }

  function getBytecodeHash(uint256 _value) public pure returns (bytes32) {
    bytes memory bytecode = abi.encodePacked(
      type(SimpleContract).creationCode,
      abi.encode(_value)
    );
    return keccak256(bytecode);
  }
}

代码解释:

SimpleContract: 一个简单的合约,带有一个状态变量 value 和一个构造函数用于初始化这个变量。

Factory: 工厂合约,包含以下几个函数:

deploy: 使用 CREATE2 操作码部署 SimpleContract 合约。

  • salt: 用于生成确定性地址的盐值。
  • _value: 传递给 SimpleContract 构造函数的参数。
  • 使用 assembly 代码调用 CREATE2 操作码,部署合约并检查部署是否成功。

computeAddress: 计算给定盐值和字节码哈希的合约地址。

  • salt: 用于生成确定性地址的盐值。
  • bytecodeHash: 部署合约字节码的哈希值。

getBytecodeHash: 计算 SimpleContract 合约字节码的哈希值。

  • _value: 传递给 SimpleContract 构造函数的参数。

部署和使用步骤

1、部署 Factory 合约: 部署 Factory 合约到以太坊网络上。

2、计算 SimpleContract 合约字节码的哈希值:调用 getBytecodeHash 函数,传递 _value 参数,获取 SimpleContract 的字节码哈希值。

3、计算合约地址: 调用 computeAddress 函数,传递 salt 和前一步获取的 bytecodeHash,计算将要部署的 SimpleContract 合约的地址。

4、部署 SimpleContract 合约: 调用 deploy 函数,传递 salt_value 参数,使用 CREATE2 操作码部署 SimpleContract 合约。

这里有一个细节需要注意:salt需要传递一个bytes32的类型,如果你输入一个int类型,需要转换一下。

通过上述步骤,可以使用 CREATE2 操作码在部署之前计算合约地址,并在部署时确保合约被部署到预期地址。

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions