当前位置:   article > 正文

Solidity——在合约中创建合约_solidity create create2 区别

solidity create create2 区别

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

一、create

  1. // SPDX-License-Identifier: MIT
  2. pragma solidity ^0.8.20;
  3. import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
  4. import "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol";
  5. contract MyToken {
  6. address public factory;//工厂合约地址
  7. address public token1;//代币合约地址1
  8. address public token2;//代币合约地址2
  9. constructor() payable{
  10. factory = msg.sender;
  11. }
  12. function initialize(address _token0, address _token1) external{
  13. require(msg.sender == factory, 'FORBIDDEN');
  14. token1 = _token0;
  15. token2 = _token1;
  16. }
  17. }
  1. // 工厂合约示例
  2. // SPDX-License-Identifier: MIT
  3. pragma solidity ^0.8.20;
  4. import "./MyToken.sol";
  5. contract TokenFactory {
  6. mapping(address => mapping(address => address)) public getPair; // 通过两个代币地址查Pair地址
  7. address[] public allPairs; // 保存所有Pair地址
  8. function create(address token1,address token2) external returns(address pairAddr){
  9. // 创建新合约
  10. MyToken token = new MyToken();
  11. // 调用新合约的initialize方法
  12. token.initialize(token1,token2);
  13. // 更新地址map
  14. pairAddr = address(token);
  15. allPairs.push(pairAddr);
  16. getPair[token1][token2] = pairAddr;
  17. getPair[token2][token1] = pairAddr;
  18. }
  19. function getToken(address token1,address token2) external view returns(address) {
  20. return getPair[token1][token2];
  21. }
  22. function getFactory (address token) external view returns(address) {
  23. return MyToken(token).factory();
  24. }
  25. }

二、create2

计算合约地址的预测值:

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

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

使用 CREATE2 指令创建合约:

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

  1. // SPDX-License-Identifier: SEE LICENSE IN LICENSE
  2. pragma solidity ^0.8.20;
  3. contract Token1{
  4. uint256 public value;
  5. constructor(uint256 _value) {
  6. value = _value;
  7. }
  8. }
  1. // SPDX-License-Identifier: SEE LICENSE IN LICENSE
  2. pragma solidity ^0.8.20;
  3. import "./Token1.sol";
  4. contract TokenFactory1 {
  5. event ContractCreated(address indexed newContract);
  6. /// 使用 create2 创建合约
  7. function createContract(bytes32 _salt,uint _x) external{
  8. Token1 _contract = new Token1{salt: _salt}(_x);
  9. emit ContractCreated(address(_contract));
  10. }
  11. ///计算被部署合约地址
  12. function getContractAddr(bytes32 salt, bytes memory bytecode) external view returns(address){
  13. address newContract = address(
  14. uint160(
  15. uint256(
  16. keccak256(
  17. abi.encodePacked(
  18. bytes1(0xff),// 固定字符串
  19. address(this),// 当前工厂合约地址
  20. salt,// salt值
  21. keccak256(bytecode)// 被部署合约机器码的hash
  22. )
  23. )
  24. )
  25. )
  26. );
  27. return newContract;
  28. }
  29. // 获取被部署合约bytecode,参数_x为被部署合约构造函数的参数
  30. function getBytecode(uint _x) external pure returns(bytes memory) {
  31. bytes memory bytecode = type(Token1).creationCode;
  32. return abi.encodePacked(bytecode, abi.encode(_x));
  33. }
  34. }

三、区别

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

地址生成方式:

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

合约地址可预测性:

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

用途:

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

重复部署:

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

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

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小蓝xlanll/article/detail/629786
推荐阅读
  

闽ICP备14008679号