如何在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"); } }
核心逻辑说明
- 创建交易:Person1调用
createTransaction,指定Person2的地址、交易金额,以及可选的最终收款地址(不填则默认自己)。此时交易状态为Created。 - 存入并批准:Person2调用
depositAndApprove,必须转入与交易金额一致的ETH到合约,成功后交易状态变为Deposited,完成第一阶段批准。 - 批准并提取:Person1调用
approveWithdrawal,确认后合约自动将资金转入指定的目标地址,交易状态变为Completed,完成第二阶段批准。
关键细节
- 使用
ReentrancyGuard防止重入攻击,确保资金安全。 - 每个交易有唯一ID,支持多笔交易并行处理。
- 加入
emergencyWithdraw函数,避免Person1长期不批准时,Person2无法取回资金(可根据需求删除)。 - 所有状态变更都有事件触发,方便链下追踪交易进度。
测试流程示例
- Person1调用
createTransaction,参数填Person2地址、1 ether(即10^18 wei)、目标地址(可选),得到交易ID0。 - Person2调用
depositAndApprove(0),并附带1 ether的ETH转账。 - Person1调用
approveWithdrawal(0),合约自动将1 ether转到目标地址。
内容的提问来源于stack exchange,提问作者user16354157
相关产品推荐
相关产品推荐

