多签钱包实现

核心知识点讲解

多签钱包的概念

多签钱包(Multisignature Wallet)是一种需要多个签名才能执行交易的钱包:

  • 安全性:单一私钥丢失不会导致资金损失
  • 防误操作:需要多个授权才能执行交易
  • 权限管理:可以设置不同级别的权限和阈值
  • 透明度:所有交易都在链上可见

多签钱包的工作原理

  1. 创建钱包:设置所有者列表和签名阈值
  2. 提交交易:任何所有者都可以提交交易提案
  3. 签名交易:其他所有者对交易进行签名
  4. 执行交易:当签名数量达到阈值时,交易可以被执行
  5. 管理操作:如添加/移除所有者、修改阈值等

多签钱包的应用场景

  • DAO资金管理:需要多个成员批准才能使用资金
  • 企业资金管理:防止单一员工滥用资金
  • 个人资产保护:防止单一私钥丢失导致资产损失
  • 项目资金管理:团队共同管理项目资金

实用案例分析

基础多签钱包实现

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract MultiSigWallet {
    // 事件
    event Deposit(address indexed sender, uint256 amount);
    event Submit(uint256 indexed txId);
    event Approve(address indexed owner, uint256 indexed txId);
    event Revoke(address indexed owner, uint256 indexed txId);
    event Execute(uint256 indexed txId);
    
    // 所有者
    address[] public owners;
    mapping(address => bool) public isOwner;
    uint256 public required;
    
    // 交易结构
    struct Transaction {
        address to;
        uint256 value;
        bytes data;
        bool executed;
        uint256 approvalCount;
    }
    
    // 交易映射
    Transaction[] public transactions;
    mapping(uint256 => mapping(address => bool)) public approvals;
    
    // 修饰器
    modifier onlyOwner() {
        require(isOwner[msg.sender], "Not owner");
        _;
    }
    
    modifier txExists(uint256 _txId) {
        require(_txId < transactions.length, "Transaction does not exist");
        _;
    }
    
    modifier notExecuted(uint256 _txId) {
        require(!transactions[_txId].executed, "Transaction already executed");
        _;
    }
    
    modifier notApproved(uint256 _txId) {
        require(!approvals[_txId][msg.sender], "Transaction already approved");
        _;
    }
    
    // 构造函数
    constructor(address[] memory _owners, uint256 _required) {
        require(_owners.length > 0, "Owners required");
        require(_required > 0 && _required <= _owners.length, "Invalid required number of owners");
        
        for (uint256 i = 0; i < _owners.length; i++) {
            address owner = _owners[i];
            require(owner != address(0), "Invalid owner");
            require(!isOwner[owner], "Owner not unique");
            
            isOwner[owner] = true;
            owners.push(owner);
        }
        
        required = _required;
    }
    
    // 接收ETH
    receive() external payable {
        emit Deposit(msg.sender, msg.value);
    }
    
    // 提交交易
    function submit(address _to, uint256 _value, bytes calldata _data) external onlyOwner {
        uint256 txId = transactions.length;
        
        transactions.push(Transaction({
            to: _to,
            value: _value,
            data: _data,
            executed: false,
            approvalCount: 0
        }));
        
        emit Submit(txId);
    }
    
    // 批准交易
    function approve(uint256 _txId) external onlyOwner txExists(_txId) notExecuted(_txId) notApproved(_txId) {
        Transaction storage transaction = transactions[_txId];
        transaction.approvalCount += 1;
        approvals[_txId][msg.sender] = true;
        
        emit Approve(msg.sender, _txId);
    }
    
    // 撤销批准
    function revoke(uint256 _txId) external onlyOwner txExists(_txId) notExecuted(_txId) {
        require(approvals[_txId][msg.sender], "Transaction not approved");
        
        Transaction storage transaction = transactions[_txId];
        transaction.approvalCount -= 1;
        approvals[_txId][msg.sender] = false;
        
        emit Revoke(msg.sender, _txId);
    }
    
    // 执行交易
    function execute(uint256 _txId) external onlyOwner txExists(_txId) notExecuted(_txId) {
        Transaction storage transaction = transactions[_txId];
        require(transaction.approvalCount >= required, "Approvals less than required");
        
        transaction.executed = true;
        
        (bool success, ) = transaction.to.call{value: transaction.value}(transaction.data);
        require(success, "Transaction failed");
        
        emit Execute(_txId);
    }
    
    // 获取所有者
    function getOwners() external view returns (address[] memory) {
        return owners;
    }
    
    // 获取交易数量
    function getTransactionCount() external view returns (uint256) {
        return transactions.length;
    }
    
    // 获取交易信息
    function getTransaction(uint256 _txId) external view returns (address to, uint256 value, bytes memory data, bool executed, uint256 approvalCount) {
        Transaction storage transaction = transactions[_txId];
        return (
            transaction.to,
            transaction.value,
            transaction.data,
            transaction.executed,
            transaction.approvalCount
        );
    }
}

高级多签钱包实现

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/access/AccessControl.sol";
import "@openzeppelin/contracts/utils/math/SafeMath.sol";

contract AdvancedMultiSigWallet is AccessControl {
    using SafeMath for uint256;
    
    bytes32 public constant OWNER_ROLE = keccak256("OWNER_ROLE");
    bytes32 public constant PROPOSER_ROLE = keccak256("PROPOSER_ROLE");
    bytes32 public constant EXECUTOR_ROLE = keccak256("EXECUTOR_ROLE");
    
    // 事件
    event Deposit(address indexed sender, uint256 amount);
    event Submit(uint256 indexed txId);
    event Approve(address indexed approver, uint256 indexed txId);
    event Revoke(address indexed revoker, uint256 indexed txId);
    event Execute(uint256 indexed txId);
    event OwnerAdded(address indexed owner);
    event OwnerRemoved(address indexed owner);
    event ThresholdChanged(uint256 oldThreshold, uint256 newThreshold);
    
    // 交易结构
    struct Transaction {
        address to;
        uint256 value;
        bytes data;
        bool executed;
        uint256 approvalCount;
        uint256 creationTime;
        uint256 expirationTime;
    }
    
    // 状态变量
    uint256 public threshold;
    Transaction[] public transactions;
    mapping(uint256 => mapping(address => bool)) public approvals;
    mapping(address => bool) public isOwner;
    address[] public owners;
    
    // 修饰器
    modifier onlyOwner() {
        require(hasRole(OWNER_ROLE, msg.sender), "Not owner");
        _;
    }
    
    modifier txExists(uint256 _txId) {
        require(_txId < transactions.length, "Transaction does not exist");
        _;
    }
    
    modifier notExecuted(uint256 _txId) {
        require(!transactions[_txId].executed, "Transaction already executed");
        _;
    }
    
    modifier notExpired(uint256 _txId) {
        require(block.timestamp <= transactions[_txId].expirationTime, "Transaction expired");
        _;
    }
    
    modifier notApproved(uint256 _txId) {
        require(!approvals[_txId][msg.sender], "Transaction already approved");
        _;
    }
    
    // 构造函数
    constructor(address[] memory _owners, uint256 _threshold, uint256 _defaultExpirationTime) {
        require(_owners.length > 0, "Owners required");
        require(_threshold > 0 && _threshold <= _owners.length, "Invalid threshold");
        
        for (uint256 i = 0; i < _owners.length; i++) {
            address owner = _owners[i];
            require(owner != address(0), "Invalid owner");
            require(!isOwner[owner], "Owner not unique");
            
            _grantRole(OWNER_ROLE, owner);
            _grantRole(PROPOSER_ROLE, owner);
            _grantRole(EXECUTOR_ROLE, owner);
            isOwner[owner] = true;
            owners.push(owner);
        }
        
        threshold = _threshold;
    }
    
    // 接收ETH
    receive() external payable {
        emit Deposit(msg.sender, msg.value);
    }
    
    // 提交交易
    function submit(address _to, uint256 _value, bytes calldata _data, uint256 _expirationTime) external {
        require(hasRole(PROPOSER_ROLE, msg.sender), "Not proposer");
        
        uint256 txId = transactions.length;
        transactions.push(Transaction({
            to: _to,
            value: _value,
            data: _data,
            executed: false,
            approvalCount: 0,
            creationTime: block.timestamp,
            expirationTime: _expirationTime
        }));
        
        emit Submit(txId);
    }
    
    // 批准交易
    function approve(uint256 _txId) external onlyOwner txExists(_txId) notExecuted(_txId) notExpired(_txId) notApproved(_txId) {
        Transaction storage transaction = transactions[_txId];
        transaction.approvalCount = transaction.approvalCount.add(1);
        approvals[_txId][msg.sender] = true;
        
        emit Approve(msg.sender, _txId);
    }
    
    // 撤销批准
    function revoke(uint256 _txId) external onlyOwner txExists(_txId) notExecuted(_txId) notExpired(_txId) {
        require(approvals[_txId][msg.sender], "Transaction not approved");
        
        Transaction storage transaction = transactions[_txId];
        transaction.approvalCount = transaction.approvalCount.sub(1);
        approvals[_txId][msg.sender] = false;
        
        emit Revoke(msg.sender, _txId);
    }
    
    // 执行交易
    function execute(uint256 _txId) external {
        require(hasRole(EXECUTOR_ROLE, msg.sender), "Not executor");
        require(_txId < transactions.length, "Transaction does not exist");
        
        Transaction storage transaction = transactions[_txId];
        require(!transaction.executed, "Transaction already executed");
        require(block.timestamp <= transaction.expirationTime, "Transaction expired");
        require(transaction.approvalCount >= threshold, "Approvals less than required");
        
        transaction.executed = true;
        
        (bool success, ) = transaction.to.call{value: transaction.value}(transaction.data);
        require(success, "Transaction failed");
        
        emit Execute(_txId);
    }
    
    // 添加所有者
    function addOwner(address _owner) external onlyOwner {
        require(_owner != address(0), "Invalid owner");
        require(!isOwner[_owner], "Already an owner");
        
        _grantRole(OWNER_ROLE, _owner);
        _grantRole(PROPOSER_ROLE, _owner);
        _grantRole(EXECUTOR_ROLE, _owner);
        isOwner[_owner] = true;
        owners.push(_owner);
        
        emit OwnerAdded(_owner);
    }
    
    // 移除所有者
    function removeOwner(address _owner) external onlyOwner {
        require(isOwner[_owner], "Not an owner");
        require(owners.length > 1, "Cannot remove last owner");
        require(threshold <= owners.length - 1, "Threshold would be too high");
        
        _revokeRole(OWNER_ROLE, _owner);
        _revokeRole(PROPOSER_ROLE, _owner);
        _revokeRole(EXECUTOR_ROLE, _owner);
        isOwner[_owner] = false;
        
        // 从owners数组中移除
        for (uint256 i = 0; i < owners.length; i++) {
            if (owners[i] == _owner) {
                owners[i] = owners[owners.length - 1];
                owners.pop();
                break;
            }
        }
        
        emit OwnerRemoved(_owner);
    }
    
    // 修改阈值
    function changeThreshold(uint256 _newThreshold) external onlyOwner {
        require(_newThreshold > 0 && _newThreshold <= owners.length, "Invalid threshold");
        
        uint256 oldThreshold = threshold;
        threshold = _newThreshold;
        
        emit ThresholdChanged(oldThreshold, _newThreshold);
    }
    
    // 获取所有者
    function getOwners() external view returns (address[] memory) {
        return owners;
    }
    
    // 获取交易数量
    function getTransactionCount() external view returns (uint256) {
        return transactions.length;
    }
    
    // 获取交易信息
    function getTransaction(uint256 _txId) external view returns (address to, uint256 value, bytes memory data, bool executed, uint256 approvalCount, uint256 creationTime, uint256 expirationTime) {
        Transaction storage transaction = transactions[_txId];
        return (
            transaction.to,
            transaction.value,
            transaction.data,
            transaction.executed,
            transaction.approvalCount,
            transaction.creationTime,
            transaction.expirationTime
        );
    }
}

多签钱包的安全考虑

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract SecureMultiSigWallet {
    // 事件
    event Deposit(address indexed sender, uint256 amount);
    event Submit(uint256 indexed txId);
    event Approve(address indexed owner, uint256 indexed txId);
    event Revoke(address indexed owner, uint256 indexed txId);
    event Execute(uint256 indexed txId);
    event EmergencyPause();
    event EmergencyUnpause();
    
    // 状态变量
    address[] public owners;
    mapping(address => bool) public isOwner;
    uint256 public required;
    bool public paused;
    
    // 交易结构
    struct Transaction {
        address to;
        uint256 value;
        bytes data;
        bool executed;
        uint256 approvalCount;
    }
    
    // 交易映射
    Transaction[] public transactions;
    mapping(uint256 => mapping(address => bool)) public approvals;
    
    // 修饰器
    modifier onlyOwner() {
        require(isOwner[msg.sender], "Not owner");
        _;
    }
    
    modifier notPaused() {
        require(!paused, "Contract paused");
        _;
    }
    
    modifier txExists(uint256 _txId) {
        require(_txId < transactions.length, "Transaction does not exist");
        _;
    }
    
    modifier notExecuted(uint256 _txId) {
        require(!transactions[_txId].executed, "Transaction already executed");
        _;
    }
    
    modifier notApproved(uint256 _txId) {
        require(!approvals[_txId][msg.sender], "Transaction already approved");
        _;
    }
    
    // 构造函数
    constructor(address[] memory _owners, uint256 _required) {
        require(_owners.length > 0, "Owners required");
        require(_required > 0 && _required <= _owners.length, "Invalid required number of owners");
        
        for (uint256 i = 0; i < _owners.length; i++) {
            address owner = _owners[i];
            require(owner != address(0), "Invalid owner");
            require(!isOwner[owner], "Owner not unique");
            
            isOwner[owner] = true;
            owners.push(owner);
        }
        
        required = _required;
    }
    
    // 接收ETH
    receive() external payable {
        emit Deposit(msg.sender, msg.value);
    }
    
    // 紧急暂停
    function emergencyPause() external onlyOwner {
        paused = true;
        emit EmergencyPause();
    }
    
    // 紧急取消暂停
    function emergencyUnpause() external onlyOwner {
        paused = false;
        emit EmergencyUnpause();
    }
    
    // 提交交易
    function submit(address _to, uint256 _value, bytes calldata _data) external onlyOwner notPaused {
        // 防止重入攻击
        require(_to != address(this), "Cannot send to self");
        
        uint256 txId = transactions.length;
        transactions.push(Transaction({
            to: _to,
            value: _value,
            data: _data,
            executed: false,
            approvalCount: 0
        }));
        
        emit Submit(txId);
    }
    
    // 批准交易
    function approve(uint256 _txId) external onlyOwner txExists(_txId) notExecuted(_txId) notApproved(_txId) notPaused {
        Transaction storage transaction = transactions[_txId];
        transaction.approvalCount += 1;
        approvals[_txId][msg.sender] = true;
        
        emit Approve(msg.sender, _txId);
    }
    
    // 撤销批准
    function revoke(uint256 _txId) external onlyOwner txExists(_txId) notExecuted(_txId) notPaused {
        require(approvals[_txId][msg.sender], "Transaction not approved");
        
        Transaction storage transaction = transactions[_txId];
        transaction.approvalCount -= 1;
        approvals[_txId][msg.sender] = false;
        
        emit Revoke(msg.sender, _txId);
    }
    
    // 执行交易
    function execute(uint256 _txId) external onlyOwner txExists(_txId) notExecuted(_txId) notPaused {
        Transaction storage transaction = transactions[_txId];
        require(transaction.approvalCount >= required, "Approvals less than required");
        
        // 防止重入攻击
        transaction.executed = true;
        
        (bool success, ) = transaction.to.call{value: transaction.value}(transaction.data);
        require(success, "Transaction failed");
        
        emit Execute(_txId);
    }
}

实践练习

  1. 部署基础多签钱包

    • 部署 MultiSigWallet 合约,设置3个所有者和2个签名阈值
    • 向钱包存款ETH
    • 提交一笔交易
    • 让其他所有者批准交易
    • 执行交易并验证结果
  2. 使用高级多签钱包

    • 部署 AdvancedMultiSigWallet 合约
    • 添加和移除所有者
    • 修改签名阈值
    • 测试交易过期功能
  3. 实现安全多签钱包

    • 部署 SecureMultiSigWallet 合约
    • 测试紧急暂停功能
    • 模拟重入攻击,验证防护措施
  4. 多签钱包集成

    • 将多签钱包与其他智能合约集成
    • 测试复杂交易的执行
    • 验证多签钱包的权限管理

总结

多签钱包是Web3开发中的重要安全工具,它通过要求多个签名来执行交易,提高了资金管理的安全性和透明度。在设计和实现多签钱包时,需要考虑以下因素:

  • 安全性:防止重入攻击、权限控制等安全问题
  • 灵活性:支持添加/移除所有者、修改签名阈值等操作
  • 易用性:提供清晰的交易提交、批准和执行流程
  • 透明度:所有交易和操作都在链上可见

多签钱包的应用场景非常广泛,从个人资产保护到DAO资金管理,都可以看到多签钱包的身影。通过本集的学习,你应该能够理解多签钱包的基本原理和实现方法,为开发安全可靠的Web3应用提供保障。

« 上一篇 预言机集成 下一篇 » 智能合约设计模式