以太坊合约地址是怎么计算出来的?(附源码实现)

2022-04-08 14:19:17 浏览数 (1)

本文作者: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

0 人点赞