本文作者:darren94me[1]
背景
在 Uniswap 源码看到工厂合约 UniswapV2Factory[2]中 createPair 方法,使用了 create2[3],预先知道配对合约地址,参考:https://github.com/Uniswap/v2-core/blob/master/contracts/UniswapV2Factory.sol
在之后路由合约拿配对的合约地址的时候,就不用从工厂合约里取得了,通过 pairFor 方法和 Token 地址获取.参考:https://github.com/Uniswap/v2-periphery/blob/master/contracts/libraries/UniswapV2Library.sol
它是如何实现的呢? 看下面 solidity 源码就可以明白.
实现
代码语言:javascript复制pragma solidity ^0.8;
contract Factory{
event Deployed(address addr,uint256 salt);
// 得到将要部署的合约的bytecode
function getBytecode(address _owner,uint _foo) public pure returns(bytes memory){
bytes memory bytecode= type(TestContract).creationCode;
return abi.encodePacked(bytecode,abi.encode(_owner,_foo));
}
// 2.计算合约的地址
// keccak256(0xff sender.Address salt keccak256(getBytecode))
// 得到最后20bytes
function getAddress(bytes memory bytecode,uint _salt) public view returns(address){
bytes32 hash = keccak256(
abi.encodePacked(
bytes1(0xff),
address(this),
_salt,
keccak256(bytecode)
)
);
return address(uint160(uint256(hash)));
}
// 3 部署合约
function deploy(bytes memory bytecode,uint _salt) public payable{
address addr;
/*
how to call create
create2(v,p,n,s)
v amount of eth to send
p pointer to start of code in memory
n size of code
s salt
*/
assembly {
addr := create2(
// weisent with current call
callvalue(),
add(bytecode,0x20),
mload(bytecode),
_salt
)
}
emit Deployed(addr,_salt);
}
}
contract TestContract{
address public owner;
uint public foo;
constructor(address _owner,uint _foo) payable{
owner =_owner;
foo= _foo;
}
function getBalance() public view returns(uint){
return address(this).balance;
}
}
在 remix 进行部署,先调用 getBytecode 得到 bytecode,然后通过 bytecode 与_salt 随机得到地址.
检验
通过点击 deploy 方法,触发 Deployed 事件,可以看到两者的地址一致.
通过 address 得到 TestContract 合约
参考资料
[1]
darren94me: https://learnblockchain.cn/people/4859
[2]
UniswapV2Factory: https://learnblockchain.cn/article/3604
[3]
create2: https://learnblockchain.cn/2019/06/10/address-compute