此篇文章教你如何在部署合约前就可以确定合约地址
一、合约源码
让我们创建一个工厂合约,它包含两个合约。
- 第一个是Demo合约,其中一个函数可以读取全县所有者的钱包地址。
- 第二个合约是工厂合约,它可以在部署Demo合约前获取其合约地址。
这个合约将使用Solidity文档中所说的CREATE2操作码:加“盐”的合约创建 / create2。
// SPDX-License-Identifier: MITpragma solidity ^0.8.0;contract ContractDemo { address public owner; // Only owners can call transactions marked with this modifier modifier onlyOwner() { require(owner == msg.sender, "Caller is not the owner"); _; } constructor(address _owner) payable { owner = _owner; } function getOwner() public view returns (address) { return owner; } }contract Factory { // Returns the address of the newly deployed contract function deploy( uint _salt ) public payable returns (address) { return address(new ContractDemo{salt: bytes32(_salt)}(msg.sender)); } // 获取待部署合约字节码 function getBytecode() public view returns (bytes memory) { bytes memory bytecode = type(ContractDemo).creationCode; return abi.encodePacked(bytecode, abi.encode(msg.sender)); } /** 获取待部署合约地址 params: _salt: 随机整数,用于预计算地址 */ function getAddress(uint256 _salt) public view returns (address) { // Get a hash concatenating args passed to encodePacked bytes32 hash = keccak256( abi.encodePacked( bytes1(0xff), // 0 address(this), // address of factory contract _salt, // a random salt keccak256(getBytecode()) // the wallet contract bytecode ) ); // Cast last 20 bytes of hash to address return address(uint160(uint256(hash))); }}
二、合约部署
在Remix中选择部署选项,并将要部署的合约切换到 Factory,点击部署:
部署被确认后,选择已部署的合约,我们就可以利用Factory合约获取Demo合约的合约地址了。
getAddress函数返回一个新的Demo实例的预计算的地址。传递一个salt参数,就可返回这个地址。为了简单,我们将使用111作为盐,但它可以是任何uint256值。
让我们把111作为参数传给getAddress函数,并在Remix中执行:
在这个特殊的例子中,预先计算的地址是0x9aBE429F1484622d7511aA9bc2C361EE6967b20b
。
接下来我们部署 Demo 合约,检查它是否正确部署到之前预先计算的地址上。在Remix中,在Factory合约实例中找到Deploy函数,并传递111作为盐。等待交易,并前往区块链浏览器确认它是否正确部署:
在交易细节部分(在区块链浏览器上)选择Internal Txns
标签:
在页面上,我们看到CREATE2函数被我们的工厂合约调用,一个新的Demo合约被创建。点击创建的合约的地址,可以看到与之前预先计算的相同。
笔者整理了常见的一些智能合约并进行分类,如有需要请自取。
点击跳转