Solidity——在合约中创建合约

以太坊链上,除了用户可以创建智能合约,智能合约同样也可以创建新的智能合约。两种常见的创建合约的方式:

一、create

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

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol";


contract MyToken {
    address public factory;//工厂合约地址
    address public token1;//代币合约地址1
    address public token2;//代币合约地址2

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

    function initialize(address _token0, address _token1) external{
        require(msg.sender == factory, 'FORBIDDEN'); 
        token1 = _token0;
        token2 = _token1;
    }
}
// 工厂合约示例
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "./MyToken.sol";
contract TokenFactory {

    mapping(address => mapping(address => address)) public getPair; // 通过两个代币地址查Pair地址
    address[] public allPairs; // 保存所有Pair地址

    function create(address token1,address token2) external returns(address pairAddr){
        // 创建新合约
        MyToken token = new MyToken();
        // 调用新合约的initialize方法
        token.initialize(token1,token2);
        // 更新地址map
        pairAddr = address(token);
        allPairs.push(pairAddr);
        getPair[token1][token2] = pairAddr;
        getPair[token2][token1] = pairAddr;

    }

    function getToken(address token1,address token2) external view returns(address) {
        return getPair[token1][token2];
    }

    function getFactory (address token) external view returns(address) {
        return MyToken(token).factory();
    }

}

二、create2

计算合约地址的预测值:

使用 keccak256 哈希函数计算合约的初始化代码(包括合约的字节码和构造函数的参数)的哈希值。

从创建者地址(通常是工厂合约的地址)和一个称为 salt 的值中构造创建合约时的合约地址。

使用 CREATE2 指令创建合约:

使用 CREATE2 指令,通过调用一个现有合约的方法(通常是一个工厂合约)来创建新合约。

// SPDX-License-Identifier: SEE LICENSE IN LICENSE
pragma solidity ^0.8.20;

contract Token1{
    uint256 public value;

    constructor(uint256 _value) {
        value = _value;
    }
}
// SPDX-License-Identifier: SEE LICENSE IN LICENSE
pragma solidity ^0.8.20;

import "./Token1.sol";

contract TokenFactory1 {

    event ContractCreated(address indexed newContract);

    /// 使用 create2 创建合约
    function createContract(bytes32 _salt,uint _x) external{
        Token1 _contract = new Token1{salt: _salt}(_x);
        emit ContractCreated(address(_contract));
    }

    ///计算被部署合约地址
    function getContractAddr(bytes32 salt, bytes memory bytecode) external view returns(address){
        address newContract = address(
            uint160(
                uint256(
                    keccak256(
                        abi.encodePacked(
                            bytes1(0xff),// 固定字符串
                            address(this),// 当前工厂合约地址
                            salt,// salt值
                            keccak256(bytecode)// 被部署合约机器码的hash
                        )
                    )
                )
            )
        );
        
        return newContract;
    }

    // 获取被部署合约bytecode,参数_x为被部署合约构造函数的参数
    function getBytecode(uint _x) external pure returns(bytes memory) {
        bytes memory bytecode = type(Token1).creationCode;
        return abi.encodePacked(bytecode, abi.encode(_x));
    }

}

三、区别

在以太坊中,create 和 create2 都是用于创建新合约实例的指令,但它们有一些关键的区别:

地址生成方式:

  • create: 创建的合约地址是基于创建者地址和创建者账户中的 nonce。创建者地址和 nonce 的组合决定了新合约的地址。
  • create2: 创建的合约地址是基于三个输入参数:创建者地址、salt 值和初始化代码的 keccak256 哈希。这样,您可以通过选择不同的 salt 值来创建不同的地址。

合约地址可预测性:

  • create: 合约地址是可预测的,但需要等待上一个创建者账户中的 nonce 增加。
  • create2: 合约地址是在创建时就能够预测的,不受 nonce 的影响。

用途:

  • create: 适用于在合约之间直接通信,无需事先知道合约地址。
  • create2: 适用于在创建合约时预测合约地址,并通过地址存储信息,以便其他合约能够可靠地找到它。

重复部署:

  • create: 如果两个不同的创建者同时尝试使用相同的 nonce 创建合约,它们可能会发生 nonce 竞争,导致一个创建失败。
  • create2: 使用不同的 salt,两个创建者可以同时创建具有相同初始化代码的合约,而不会发生地址冲突。

总体而言,create2 提供了更多的地址生成灵活性和可预测性,特别是对于一些需要在合约中存储地址信息的应用场景。在某些情况下,选择使用 createcreate2 取决于您的具体需求和设计。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

tomggo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值