Solidity 代币和金融工具 2| 多签钱包(Multi Sig Wallet)

多签钱包(Multi-Signature Wallet)是一种需要多个私钥持有者共同批准才能执行交易的智能合约。它广泛用于提高资金安全性,避免单点故障(如单个私钥泄露)。在 Solidity 中实现多签钱包,核心思路是:预设一组所有者(owners)和一个阈值(threshold),只有当足够多的所有者确认一笔交易后,该交易才能被执行。

1. 基本原理

  • 所有者(Owners): 有权批准交易的地址列表,通常不可更改(或通过多签本身修改)。
  • 阈值(Threshold): 执行交易所需的最少确认数,通常≤ 所有者数量。
  • 交易(Transaction): 包括i目标地址、发送的以太币数量、调用数据(data)以及一个唯一标识(如交易ID或nonce)。
  • 确认(Confirmations): 所有者调用合约方法对某笔交易表示同意。当确认数达到阈值时,任何人均可触发执行。

2. 核心功能与实现要点

2.1 数据结构

  • transactions 数组存储所有待处理或已执行的交易(包含交易目标地址、发送金额、交易数据和执行状态)。
  • isConfirmed 记录每个地址对每笔交易的确认状态(记录每个地址对每笔交易的确认状态)。
  • numConfirmations 可动态计数,也可通过遍历计算(但遍历消耗gas)。
solidity 复制代码
address[] public owners;
mapping(address => bool) public isOwner;
uint public threshold;

struct Transaction {
    address to;
    uint value;
    bytes data;
    bool executed;
    uint numConfirmations;
}
mapping(uint => mapping(address => bool)) public isConfirmed;
Transaction[] public transactions;

2.2 提交交易

  • 通常只允许所有者提交交易,但也可开放给任何人(需防止垃圾交易)。
solidity 复制代码
function submitTransaction(address _to, uint _value, bytes memory _data) public onlyOwner returns (uint txIndex) {
    txIndex = transactions.length;
    transactions.push(Transaction({
        to: _to,
        value: _value,
        data: _data,
        executed: false,
        numConfirmations: 0
    }));
    emit SubmitTransaction(msg.sender, txIndex, _to, _value, _data);
}

2.3 确认交易

solidity 复制代码
function confirmTransaction(uint _txIndex) public onlyOwner {
    require(_txIndex < transactions.length, "tx does not exist");
    Transaction storage txn = transactions[_txIndex];
    require(!txn.executed, "tx already executed");
    require(!isConfirmed[_txIndex][msg.sender], "tx already confirmed");

    isConfirmed[_txIndex][msg.sender] = true;
    txn.numConfirmations += 1;

    emit ConfirmTransaction(msg.sender, _txIndex);
}

2.4 执行交易

  • 调用 call 可同时发送 ETH 并调用目标合约函数。
  • 注意重入攻击:在状态更改后再进行外部调用,并使用 executed 标志防止重复执行。
solidity 复制代码
function executeTransaction(uint _txIndex) public {
    require(_txIndex < transactions.length, "tx does not exist");
    Transaction storage txn = transactions[_txIndex];
    require(!txn.executed, "tx already executed");
    require(txn.numConfirmations >= threshold, "not enough confirmations");

    txn.executed = true;
    (bool success, ) = txn.to.call{value: txn.value}(txn.data);
    require(success, "tx failed");
    emit ExecuteTransaction(msg.sender, _txIndex);
}

2.5 撤销确认(可选)

solidity 复制代码
function revokeConfirmation(uint _txIndex) public onlyOwner {
    require(_txIndex < transactions.length, "tx does not exist");
    Transaction storage txn = transactions[_txIndex];
    require(!txn.executed, "tx already executed");
    require(isConfirmed[_txIndex][msg.sender], "tx not confirmed");

    isConfirmed[_txIndex][msg.sender] = false;
    txn.numConfirmations -= 1;

    emit RevokeConfirmation(msg.sender, _txIndex);
}

2.6 修改所有者与阈值(高级)

可以通过多签本身来实现,即提交一笔调用 addOwnerremoveOwnerchangeThreshold 的交易,由现有所有者批准后执行。

3. 安全注意事项

  • 重入攻击 :执行交易时使用"检查-生效-交互"模式,先标记 executed = true 再调用外部地址。
  • Gas 限制:交易数组可能很大,避免遍历所有确认;可使用计数器优化。
  • 所有权管理:初始所有者需在构造函数中设定,后续修改需谨慎。
  • 拒绝服务:恶意所有者可无限提交垃圾交易,但可通过限制提交权限或收取费用缓解。
  • 使用事件:所有关键操作(提交、确认、执行、撤销)都应记录事件,便于链下监听。

4. 简化示例代码

以下是一个极简多签钱包的核心合约(省略了事件、修饰器等):

solidity 复制代码
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract MultiSigWallet {
    address[] public owners;
    mapping(address => bool) public isOwner;
    uint public threshold;

    struct Transaction {
        address to;
        uint value;
        bytes data;
        bool executed;
        uint confirmCount;
    }
    Transaction[] public transactions;
    mapping(uint => mapping(address => bool)) public confirmed;

    modifier onlyOwner() {
        require(isOwner[msg.sender], "not owner");
        _;
    }

    constructor(address[] memory _owners, uint _threshold) {
        require(_owners.length > 0, "owners required");
        require(_threshold > 0 && _threshold <= _owners.length, "invalid threshold");
        for (uint i = 0; i < _owners.length; i++) {
            address owner = _owners[i];
            require(owner != address(0) && !isOwner[owner], "invalid owner");
            isOwner[owner] = true;
            owners.push(owner);
        }
        threshold = _threshold;
    }

    function submitTransaction(address _to, uint _value, bytes memory _data) public onlyOwner returns (uint txIndex) {
        txIndex = transactions.length;
        transactions.push(Transaction({
            to: _to,
            value: _value,
            data: _data,
            executed: false,
            confirmCount: 0
        }));
    }

    function confirmTransaction(uint _txIndex) public onlyOwner {
        require(_txIndex < transactions.length, "invalid tx");
        Transaction storage txn = transactions[_txIndex];
        require(!txn.executed, "executed");
        require(!confirmed[_txIndex][msg.sender], "already confirmed");

        confirmed[_txIndex][msg.sender] = true;
        txn.confirmCount += 1;
    }

    function executeTransaction(uint _txIndex) public {
        require(_txIndex < transactions.length, "invalid tx");
        Transaction storage txn = transactions[_txIndex];
        require(!txn.executed, "executed");
        require(txn.confirmCount >= threshold, "not enough confirmations");

        txn.executed = true;
        (bool success, ) = txn.to.call{value: txn.value}(txn.data);
        require(success, "tx failed");
    }

    // 接收 ETH 的函数
    receive() external payable {}
}

5. 现有成熟方案

  • Gnosis Safe:目前最流行的多签钱包,支持模块化、多种链、合约交互,并有完善的UI。其合约经过严格审计,推荐直接使用。
  • 其他实现 :如 OpenZeppelin 也提供 MultisigWallet 合约示例,但已较少维护。

6. 总结

实现多签钱包的核心是管理交易生命周期:提交 → 多方确认 → 达到阈值后执行。关键点在于确保只有所有者可操作,防止重入,并合理设计数据结构以节省 Gas。对于生产环境,建议直接采用经过实战检验的方案(如 Gnosis Safe),避免自行实现时的安全风险。

相关推荐
xinlianyq1 天前
DeFi监管框架落地,美国认定多数代币为大宗商品
大数据·人工智能·区块链
Web3VentureView2 天前
SYNBO深度参与Ethereum on Tour 上海交大站:从高校 Builder 到链上一级市场基础设施
人工智能·web3·区块链·加密货币·synbo
ithadoop3 天前
Solana入门:区块链新手速成指南(第二阶段:开发入门)
rust·web3·区块链·智能合约·solana
Bczheng14 天前
二十.读写交易索引和验证交易
区块链
曦月逸霜4 天前
区块链技术与应用学习笔记(持续更新中)
笔记·学习·区块链
Web3VentureView4 天前
SYNBO维港私享局:在香港Web3嘉年华最后一天,打开链上一级市场的共识现场
人工智能·web3·区块链·加密货币·synbo
TechubNews5 天前
专访新火集团首席经济学家付鹏:解读比特币资产属性、香港楼市与普通人理财建议——Techub News对话实录
人工智能·区块链
王苏安说钢材A5 天前
无锡佳钛合不锈钢有限公司不锈钢焊管厂家
区块链
财迅通Ai5 天前
能源板块强势领涨,汇添富能源ETF(159930.SZ)单日大涨3.41%
区块链·能源·中国神华·陕西煤业
Web3VentureView5 天前
SYNBO亮相香港《前瞻》活动,联手HashKey共筑链上原生一级市场新范式
人工智能·web3·区块链·加密货币·synbo