# 合约地址预测 **Published by:** [Smithereens](https://paragraph.com/@soyoung/) **Published on:** 2022-04-07 **URL:** https://paragraph.com/@soyoung/3Z9o3yYGBG4DPIpAF4TW ## Content 应用场景: 类似 uniswap 去中心化交易所池子合约计算。Uniswap v2 工厂合约计算 pair 合约地址的利用了该特性。但其中需要注意的点是:当我们使用 type(constract).creationCode 时需要注意合约元数据的变化,编译器版本的不同也有可能影响到字节码的变化,具体文档如下。(自行部署 Uniswap 代码时可能遇到该问题) https://learnblockchain.cn/docs/solidity/metadata.html#encoding-of-the-metadata-hash-in-the-bytecode https://github.com/Uniswap/v2-periphery/blob/master/contracts/libraries/UniswapV2Library.sol https://github.com/Uniswap/v2-core/blob/master/contracts/UniswapV2Factory.sol 解决交易所充值账号问题 如果为每个用户创建一个地址,则私钥的维护是个问题,如果单独的一个合约地址那必须要先先部署(浪费gas)才能看到地址,所以利用地址预测的方式,需要的时候再创建。 示例代码如下: // SPDX-License-Identifier: MIT pragma solidity ^0.8.10; contract Factory { // Returns the address of the newly deployed contract function deploy( address _owner, uint _foo, bytes32 _salt ) public payable returns (address) { // This syntax is a newer way to invoke create2 without assembly, you just need to pass salt // https://docs.soliditylang.org/en/latest/control-structures.html#salted-contract-creations-create2 return address(new TestContract{salt: _salt}(_owner, _foo)); } } // This is the older way of doing it using assembly contract FactoryAssembly { event Deployed(address addr, uint salt); // 1. Get bytecode of contract to be deployed // NOTE: _owner and _foo are arguments of the TestContract's constructor 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. Compute the address of the contract to be deployed // NOTE: _salt is a random number used to create an address function getAddress(bytes memory bytecode, uint _salt) public view returns (address) { bytes32 hash = keccak256( abi.encodePacked(bytes1(0xff), address(this), _salt, keccak256(bytecode)) ); // NOTE: cast last 20 bytes of hash to address return address(uint160(uint(hash))); } // 3. Deploy the contract // NOTE: // Check the event log Deployed which contains the address of the deployed TestContract. // The address in the log should equal the address computed from above. function deploy(bytes memory bytecode, uint _salt) public payable { address addr; /* NOTE: How to call create2 create2(v, p, n, s) create new contract with code at memory p to p + n and send v wei and return the new address where new address = first 20 bytes of keccak256(0xff + address(this) + s + keccak256(mem[p…(p+n))) s = big-endian 256-bit value */ assembly { addr := create2( callvalue(), // wei sent with current call // Actual code starts after skipping the first 32 bytes add(bytecode, 0x20), mload(bytecode), // Load the size of code contained in the first 32 bytes _salt // Salt from function arguments ) if iszero(extcodesize(addr)) { revert(0, 0) } } 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; } } ## Publication Information - [Smithereens](https://paragraph.com/@soyoung/): Publication homepage - [All Posts](https://paragraph.com/@soyoung/): More posts from this publication - [RSS Feed](https://api.paragraph.com/blogs/rss/@soyoung): Subscribe to updates - [Twitter](https://twitter.com/stoneworld1991): Follow on Twitter