欢迎订阅专栏 :3分钟Solidity--智能合约--Web3区块链技术必学
如需获取本内容的最新版本,请参见 Cyfrin.io 上的 Precompute Contract 地址与 Create2(代码示例)
合约地址可以在合约部署前通过create2预先计算出来
scss
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;
contract Factory {
// 返回新部署合约的地址
function deploy(address _owner, uint256 _foo, bytes32 _salt)
public
payable
returns (address)
{
// 这种语法是一种无需汇编即可调用 create2 的新方法,你只需要传递 salt 参数。
// https://docs.soliditylang.org/en/latest/control-structures.html#salted-contract-creations-create2
return address(new TestContract{salt: _salt}(_owner, _foo));
}
}
// 这是使用汇编语言的旧方法
contract FactoryAssembly {
event Deployed(address addr, uint256 salt);
// 1. 获取待部署合约的字节码
// 注意:_owner 和 _foo 是 TestContract 构造函数的参数
function getBytecode(address _owner, uint256 _foo)
public
pure
returns (bytes memory)
{
bytes memory bytecode = type(TestContract).creationCode;
return abi.encodePacked(bytecode, abi.encode(_owner, _foo));
}
// 2. 计算要部署的合约地址
//注意:_salt是一个随机数,用于生成地址。
function getAddress(bytes memory bytecode, uint256 _salt)
public
view
returns (address)
{
bytes32 hash = keccak256(
abi.encodePacked(
bytes1(0xff), address(this), _salt, keccak256(bytecode)
)
);
// 注意:将哈希的最后20个字节转换为地址
return address(uint160(uint256(hash)));
}
// 3. 部署合约
// 注意:
// 检查事件日志 Deployed,其中包含已部署的 TestContract 的地址。
// 日志中的地址应与上述计算的地址一致。
function deploy(bytes memory bytecode, uint256 _salt) public payable {
address addr;
/*
注意:如何调用create2
create2(v, p, n, s)
在内存位置p到p + n处创建新合约代码
并发送v wei
返回新地址
其中新地址 = keccak256(0xff + address(this) + s + keccak256(mem[p...(p+n)))的前20字节
s = 大端序256位值
*/
assembly {
addr :=
create2(
callvalue(), // 当前调用中发送的wei
// 跳过前32字节后开始实际代码
add(bytecode, 0x20),
mload(bytecode), // 加载前32字节中包含的代码大小
_salt // 来自函数参数的盐
)
if iszero(extcodesize(addr)) { revert(0, 0) }
}
emit Deployed(addr, _salt);
}
}
contract TestContract {
address public owner;
uint256 public foo;
constructor(address _owner, uint256 _foo) payable {
owner = _owner;
foo = _foo;
}
function getBalance() public view returns (uint256) {
return address(this).balance;
}
}
Remix Lite 尝试一下