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

如何在Solidity中用一次性智能合约实现无预部署原子代币交换?

无需预部署合约的Solidity原子代币交换实现方案探讨

问题背景

TokenA与TokenB之间的原子交换最常见的是P2-SC-2P模式:

  • 部署代币交换智能合约
  • Alice将TokenA存入智能合约
  • Bob将TokenB存入智能合约并换取TokenA

希望省略预部署合约的步骤,实现真正的P2P机制:让Alice签署一笔交易,仅当交易传播者向Alice转入Y数量的TokenB时,才向其转出X数量的TokenA。同时提出了用一次性自毁合约的思路,并给出伪代码,询问该方案的技术可行性。


方案可行性分析与修正思路

你的一次性自毁合约思路方向是对的,但伪代码存在几个关键技术问题,需要调整优化:

核心问题修正

  1. 签名逻辑错误
    不能直接在合约构造器里验证完整交易的签名,应该让Alice预先签署一份授权转移TokenA的消息签名,合约通过ecrecover验证签名有效性,确认是Alice授权的转移操作,而非验证完整交易。
  2. 代币授权逻辑错误
    Bob作为买家,必须预先授权合约转移他的TokenB,合约无法主动调用TokenB.approve(该操作只能由代币持有者发起)。
  3. 构造器操作限制
    合约构造器执行时,合约地址尚未完全初始化,部分代币转移操作可能触发异常。建议将交换逻辑放在单独函数中,由Bob触发执行。
  4. 自毁安全性
    必须确保两次代币转移都成功后再执行selfdestruct,避免出现单边转账未完成的情况。

修正后的简化示例代码

pragma solidity ^0.8.0;

import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";

contract OneTimeAtomicSwap {
    using SafeERC20 for IERC20;

    address public immutable seller;
    address public immutable buyer;
    IERC20 public immutable tokenA;
    IERC20 public immutable tokenB;
    uint256 public immutable amountA;
    uint256 public immutable amountB;
    bytes public immutable sellerSignature;

    constructor(
        address _seller,
        address _buyer,
        IERC20 _tokenA,
        IERC20 _tokenB,
        uint256 _amountA,
        uint256 _amountB,
        bytes memory _sellerSignature
    ) {
        seller = _seller;
        buyer = _buyer;
        tokenA = _tokenA;
        tokenB = _tokenB;
        amountA = _amountA;
        amountB = _amountB;
        sellerSignature = _sellerSignature;
    }

    function executeSwap() external {
        require(msg.sender == buyer, "Only buyer can execute");
        
        // 验证卖家的授权签名(签名内容包含合约地址与TokenA转移数量)
        bytes32 message = keccak256(abi.encodePacked(address(this), amountA));
        require(verifySignature(message, sellerSignature, seller), "Invalid seller signature");

        // 转移Bob的TokenB给Alice
        tokenB.safeTransferFrom(buyer, seller, amountB);
        // 转移Alice的TokenA给Bob(需Alice预先授权合约转移TokenA)
        tokenA.safeTransferFrom(seller, buyer, amountA);

        // 交换完成后自毁合约
        selfdestruct(payable(seller));
    }

    function verifySignature(bytes32 message, bytes memory signature, address signer) internal pure returns (bool) {
        bytes32 ethSignedMessage = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", message));
        (bytes32 r, bytes32 s, uint8 v) = splitSignature(signature);
        return ecrecover(ethSignedMessage, v, r, s) == signer;
    }

    function splitSignature(bytes memory sig) internal pure returns (bytes32 r, bytes32 s, uint8 v) {
        require(sig.length == 65, "Invalid signature length");
        assembly {
            r := mload(add(sig, 32))
            s := mload(add(sig, 64))
            v := byte(0, mload(add(sig, 96)))
        }
    }
}

实际执行流程

  1. Alice提前计算即将部署的一次性合约地址(通过创建交易的哈希推导),并签署包含该地址与TokenA转移数量的消息。
  2. Alice生成部署合约的交易模板,将签名、双方地址、代币信息等参数传入构造器。
  3. Bob验证签名有效性后,先授权合约转移自己的TokenB,再广播部署合约+调用executeSwap的合并交易(可通过EIP-1155或批量交易实现)。
  4. 合约执行交换逻辑,完成后立即自毁,链上不会留下永久合约。

补充说明

该方案确实实现了无需预部署合约的原子交换,合约仅在交易执行期间存在,完成后立即销毁。核心注意点是提前准确计算合约地址,确保Alice的签名对应正确的合约,避免中间人篡改风险。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 01:31:21