You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Solidity中实现需多人授权批准的交易功能?

实现多批准分步交易合约

下面是完全匹配你需求的Solidity合约,核心是分三步完成交易流转,避开普通Escrow的单向批准逻辑:

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

import "@openzeppelin/contracts/security/ReentrancyGuard.sol";

contract MultiApprovalTransaction is ReentrancyGuard {
    // 交易状态枚举:创建完成 → 已存入资金 → 可提取 → 交易完成
    enum TransactionStatus { Created, Deposited, ReadyToWithdraw, Completed }

    // 交易结构体存储核心信息
    struct Transaction {
        address creator;    // Person1,交易发起方
        address approver;   // Person2,资金存入批准方
        uint256 amount;     // 交易金额
        address target;     // 最终收款地址(默认是creator)
        TransactionStatus status;
    }

    mapping(uint256 => Transaction) public transactions;
    uint256 public nextTransactionId;

    // 事件用于追踪交易状态变化
    event TransactionCreated(uint256 indexed txId, address creator, address approver, uint256 amount, address target);
    event DepositApproved(uint256 indexed txId, address approver);
    event WithdrawalApproved(uint256 indexed txId, address creator);
    event FundsWithdrawn(uint256 indexed txId, address target, uint256 amount);

    /**
     * Person1调用创建交易
     * @param _approver Person2的地址
     * @param _amount 交易金额(wei)
     * @param _target 可选的最终收款地址,默认是调用者自己
     */
    function createTransaction(address _approver, uint256 _amount, address _target) external {
        require(_approver != address(0), "Approver address cannot be zero");
        require(_amount > 0, "Amount must be greater than zero");
        address target = _target == address(0) ? msg.sender : _target;

        uint256 txId = nextTransactionId++;
        transactions[txId] = Transaction({
            creator: msg.sender,
            approver: _approver,
            amount: _amount,
            target: target,
            status: TransactionStatus.Created
        });

        emit TransactionCreated(txId, msg.sender, _approver, _amount, target);
    }

    /**
     * Person2调用,存入资金并完成第一阶段批准
     * 必须转入合约的金额与交易设定金额一致
     */
    function depositAndApprove(uint256 _txId) external payable nonReentrant {
        Transaction storage txn = transactions[_txId];
        require(txn.status == TransactionStatus.Created, "Transaction not in created state");
        require(msg.sender == txn.approver, "Only approver can call this");
        require(msg.value == txn.amount, "Deposit amount does not match transaction amount");

        txn.status = TransactionStatus.Deposited;
        emit DepositApproved(_txId, msg.sender);
    }

    /**
     * Person1调用,完成第二阶段批准并触发资金转出
     */
    function approveWithdrawal(uint256 _txId) external nonReentrant {
        Transaction storage txn = transactions[_txId];
        require(txn.status == TransactionStatus.Deposited, "Transaction not deposited");
        require(msg.sender == txn.creator, "Only creator can approve withdrawal");

        txn.status = TransactionStatus.ReadyToWithdraw;
        emit WithdrawalApproved(_txId, msg.sender);

        // 直接将资金转入目标地址
        (bool success, ) = txn.target.call{value: txn.amount}("");
        require(success, "Failed to send funds");

        txn.status = TransactionStatus.Completed;
        emit FundsWithdrawn(_txId, txn.target, txn.amount);
    }

    // 紧急提取:仅当交易异常时,允许approver取回已存入资金(可选)
    function emergencyWithdraw(uint256 _txId) external nonReentrant {
        Transaction storage txn = transactions[_txId];
        require(txn.status == TransactionStatus.Deposited, "Only deposited transactions can be emergency withdrawn");
        require(msg.sender == txn.approver, "Only approver can trigger emergency withdraw");
        
        txn.status = TransactionStatus.Completed;
        (bool success, ) = txn.approver.call{value: txn.amount}("");
        require(success, "Emergency withdrawal failed");
    }
}

核心逻辑说明

  1. 创建交易:Person1调用createTransaction,指定Person2的地址、交易金额,以及可选的最终收款地址(不填则默认自己)。此时交易状态为Created。
  2. 存入并批准:Person2调用depositAndApprove,必须转入与交易金额一致的ETH到合约,成功后交易状态变为Deposited,完成第一阶段批准。
  3. 批准并提取:Person1调用approveWithdrawal,确认后合约自动将资金转入指定的目标地址,交易状态变为Completed,完成第二阶段批准。

关键细节

  • 使用ReentrancyGuard防止重入攻击,确保资金安全。
  • 每个交易有唯一ID,支持多笔交易并行处理。
  • 加入emergencyWithdraw函数,避免Person1长期不批准时,Person2无法取回资金(可根据需求删除)。
  • 所有状态变更都有事件触发,方便链下追踪交易进度。

测试流程示例

  1. Person1调用createTransaction,参数填Person2地址、1 ether(即10^18 wei)、目标地址(可选),得到交易ID 0。
  2. Person2调用depositAndApprove(0),并附带1 ether的ETH转账。
  3. Person1调用approveWithdrawal(0),合约自动将1 ether转到目标地址。

内容的提问来源于stack exchange,提问作者user16354157

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 06:47:41