Skip to content

Solidity CREATE2 创建合约(Uniswap createPair)

这个技术是 Uniswap 创建交易对 和 GasToken(ChiToken)的技术原理。利用 Solidity 的 CREATE2 创建可计算地址的合约,然后利用这个合约的 selfdestruct 来返还一些 做一些需要 固定地址(计算出地址) 的业务逻辑。

之前的版本还需要使用 create2 操作符来创建合约,现在的版本 0.8.12 都不需要了,发出来记录一下,省的后面用的时候又忘记。

做了一个 示例:可以带 ETH 调用 createChild,来将附带 ETH 存入创建出来的子合约,然后可以调用 claim 方法将存入的 ETH 提取出来。并没有记录所有子合约的合约地址,而是根据计数推算出子合约合约地址进行调用。看下操作记录:

  1. 存入 100 ETH。
  2. 提取前面存入的 100 ETH。
  3. 后面进行了 多次存取 来验证技术实现的对不对。

后记: 开始没有将 Child、Parent 合约拆分到两个文件里面,在 Remix 里面测试时发现计算出的子合约的合约地址是错误的,结果是因为 Remix 里面复制的 bytecode 是整个文件的 bytecode,而不是单个选中的合约的 bytecode,导致 hash 计算错误出现问题。

Child 子合约

用来储存 ETH 资产

// SPDX-License-Identifier: UNLICENSED
pragma solidity >=0.8.0;

contract Child {
    address public owner;

    constructor() payable {
        owner = msg.sender;
    }

    function destruct(address payable to) public {
        assert(owner == msg.sender);
        selfdestruct(to);
    }
}

Parent 控制器

用来部署子合约,调用销毁子合约、计算子合约合约地址

// SPDX-License-Identifier: UNLICENSED
pragma solidity >=0.8.0;

import "./Child.sol";

contract Parent {
    bytes32 public constant CHILD_BYTECODE_KECCAK32 =
        0x3777cc71780224f9113b98623e11e85919892f48d89f0264112bb5be178f2d2e;

    uint256 public nonce;
    uint256 public claimNonce;

    event ChildCreated(address addr);

    function balance() public view returns (uint256) {
        return nonce - claimNonce;
    }

    function claim() public {
        require(claimNonce < nonce, "no remaining balance");
        Child child = Child(computeChild(++claimNonce));
        child.destruct(payable(msg.sender));
    }

    function createChild() public payable {
        assert(msg.value > 0);
        emit ChildCreated(
            address(
                new Child{
                    salt: keccak256(abi.encode(++nonce)),
                    value: msg.value
                }()
            )
        );
    }

    function computeChild(uint256 _nonce) public view returns (address) {
        return
            address(
                uint160(
                    uint256(
                        keccak256(
                            abi.encodePacked(
                                hex"ff",
                                address(this),
                                keccak256(abi.encode(_nonce)),
                                CHILD_BYTECODE_KECCAK32
                            )
                        )
                    )
                )
            );
    }

    function k3ccak256(bytes calldata data) public pure returns (bytes32) {
        return keccak256(data);
    }
}

Comments

Commenting as a guest. A nickname is required; email is optional. Only new comments posted after verifying your email and signing in will appear on your profile. Existing guest comments will not be linked automatically.

Share article

Solidity CREATE2 创建合约(Uniswap createPair)

Email X

View original ↗