创建合约 #

一、合约创建概述 #

Solidity支持在合约中动态创建新合约:

方式 说明 地址确定性
new 创建新合约 不确定
create2 创建新合约 确定

二、使用new创建合约 #

2.1 基本用法 #

solidity
contract Child {
    uint256 public value;
    
    constructor(uint256 _value) {
        value = _value;
    }
    
    function getValue() public view returns (uint256) {
        return value;
    }
}

contract Factory {
    Child[] public children;
    
    event ChildCreated(address child, uint256 value);
    
    function createChild(uint256 value) public returns (Child) {
        Child child = new Child(value);
        children.push(child);
        emit ChildCreated(address(child), value);
        return child;
    }
    
    function getChildCount() public view returns (uint256) {
        return children.length;
    }
}

2.2 创建并发送ETH #

solidity
contract PayableChild {
    uint256 public value;
    
    constructor(uint256 _value) payable {
        value = _value;
    }
    
    receive() external payable {}
}

contract PayableFactory {
    event ChildCreated(address child, uint256 value, uint256 balance);
    
    function createChildWithValue(uint256 value) public payable returns (PayableChild) {
        PayableChild child = new PayableChild{value: msg.value}(value);
        emit ChildCreated(address(child), value, address(child).balance);
        return child;
    }
}

三、使用create2创建合约 #

3.1 基本概念 #

create2允许预先计算合约地址,地址由以下因素决定:

  • 创建者地址
  • 盐值(salt)
  • 合约字节码

3.2 create2示例 #

solidity
contract DeterministicChild {
    uint256 public value;
    
    constructor(uint256 _value) {
        value = _value;
    }
}

contract DeterministicFactory {
    event ChildCreated(address child, bytes32 salt, uint256 value);
    
    function createChild(
        uint256 value,
        bytes32 salt
    ) public returns (DeterministicChild) {
        DeterministicChild child = new DeterministicChild{salt: salt}(value);
        emit ChildCreated(address(child), salt, value);
        return child;
    }
    
    function computeAddress(
        bytes32 salt,
        bytes memory bytecode
    ) public view returns (address) {
        bytes32 hash = keccak256(
            abi.encodePacked(
                bytes1(0xff),
                address(this),
                salt,
                keccak256(bytecode)
            )
        );
        
        return address(uint160(uint256(hash)));
    }
}

四、实际应用示例 #

4.1 工厂模式 #

solidity
contract Token {
    string public name;
    string public symbol;
    uint256 public totalSupply;
    
    mapping(address => uint256) public balanceOf;
    
    constructor(
        string memory _name,
        string memory _symbol,
        uint256 _supply
    ) {
        name = _name;
        symbol = _symbol;
        totalSupply = _supply;
        balanceOf[msg.sender] = _supply;
    }
}

contract TokenFactory {
    struct TokenInfo {
        address tokenAddress;
        string name;
        string symbol;
        uint256 totalSupply;
        address creator;
    }
    
    TokenInfo[] public tokens;
    
    event TokenCreated(
        address indexed tokenAddress,
        string name,
        string symbol,
        uint256 totalSupply,
        address creator
    );
    
    function createToken(
        string memory name,
        string memory symbol,
        uint256 supply
    ) public returns (Token) {
        Token token = new Token(name, symbol, supply);
        
        tokens.push(TokenInfo({
            tokenAddress: address(token),
            name: name,
            symbol: symbol,
            totalSupply: supply,
            creator: msg.sender
        }));
        
        emit TokenCreated(
            address(token),
            name,
            symbol,
            supply,
            msg.sender
        );
        
        return token;
    }
    
    function getTokenCount() public view returns (uint256) {
        return tokens.length;
    }
}

4.2 钱包工厂 #

solidity
contract Wallet {
    address public owner;
    
    constructor(address _owner) {
        owner = _owner;
    }
    
    modifier onlyOwner() {
        require(msg.sender == owner, "Not owner");
        _;
    }
    
    function withdraw(uint256 amount) public onlyOwner {
        payable(owner).transfer(amount);
    }
    
    function getBalance() public view returns (uint256) {
        return address(this).balance;
    }
    
    receive() external payable {}
}

contract WalletFactory {
    mapping(address => address[]) public userWallets;
    
    event WalletCreated(address indexed owner, address wallet);
    
    function createWallet() public returns (Wallet) {
        Wallet wallet = new Wallet(msg.sender);
        userWallets[msg.sender].push(address(wallet));
        emit WalletCreated(msg.sender, address(wallet));
        return wallet;
    }
    
    function getWallets(address user) public view returns (address[] memory) {
        return userWallets[user];
    }
}

五、总结 #

合约创建要点:

方式 说明 地址
new 动态创建 不确定
create2 确定性创建 可预测

使用建议:

  • 使用工厂模式管理合约
  • create2用于需要预测地址的场景
  • 注意Gas消耗

接下来,让我们学习ABI编码!

最后更新:2026-03-27