跳转至

SeraSOR.sol

智能订单路由器支持多段原子兑换。用户签署单个 Intent,执行者通过多个订单撮合进行路由。

主网: 0xa7A0cf7cd6f043fCA23f29d8ae5aae6b46e11c18 源代码: src/SeraSOR.sol

常量

uint256 public constant MAX_ROUTE_LEGS = 20;

数据结构

IntentParams

struct IntentParams {
    address inputToken;            // Initial wallet funding token
    address outputToken;           // Final output token
    uint256 maxInputAmount;        // Max total spend across all legs
    uint256 minOutputAmount;       // Min total output
    address recipient;             // Final output recipient
    uint256 initialDepositAmount;  // Amount to pull from wallet
    uint256 uuid;                  // Replay protection
    uint48 deadline;               // Signature deadline
}

函数

executeIntent

基于 Taker 已签名的 Intent 执行多段原子路由。

function executeIntent(
    MatchData[] calldata matches,
    bytes calldata intentSignature,
    IntentParams calldata intent,
    uint8 uniqueTokenCount,
    uint256 permitDeadline,
    bytes calldata permitSignature
) external
参数 类型 说明
matches MatchData[] 订单撮合对数组(每段一个)
intentSignature bytes Taker 的 EIP-712 Intent 签名
intent IntentParams 已签名的路由参数
uniqueTokenCount uint8 瞬态余额跟踪的优化提示
permitDeadline uint256 ERC-2612 permit 截止时间(不使用 permit 时为 0)
permitSignature bytes ERC-2612 permit 签名(不使用 permit 时为空)

流程:

  1. 验证 Intent 签名并检查 UUID 是否已被使用
  2. 从 Taker 钱包拉取 initialDepositAmount(可选 permit)
  3. 对于每一段:
    • 通过 Sera.settleRoutedLeg() 将 Taker 订单与 Maker 订单撮合
    • 将中间输出保存在瞬态余额中
  4. 验证信封约束:
    • 总输入 ≤ maxInputAmount
    • 总输出 ≥ minOutputAmount
    • 所有中间余额已消耗(无残余)

示例路由:GBP → SGD 通过 USD

Leg 1: GBP → USD (taker sells GBP, receives USD)
Leg 2: USD → SGD (taker sells USD, receives SGD)

USD 在各段之间瞬态持有,永远不会进入 Taker 的 Vault。

要求:

  • ≥1 且 ≤20 段
  • 截止时间未过期
  • UUID 未被使用过
  • 所有段属于同一 Taker
  • 最终段交付到已签名的接收方
  • 所有瞬态余额完全消耗

事件:

event IntentMatched(bytes32 indexed intentHash, address indexed taker, uint256 legCount);
event IntentLegMatched(bytes32 indexed intentHash, uint256 indexed legIndex, bytes32 takerOrderHash, bytes32 makerOrderHash);

EIP-712 类型哈希

bytes32 constant INTENT_TYPEHASH = keccak256(
    "Intent(address inputToken,address outputToken,uint256 maxInputAmount,uint256 minOutputAmount,address recipient,uint256 initialDepositAmount,uint256 uuid,uint48 deadline)"
);

状态变量

mapping(address => mapping(uint256 => bool)) public isIntentUuidUsed;

错误

错误 原因
EmptyRoute 未提供路由段
TooManyLegs 超过 20 段
InvalidRoute 路由验证失败(代币不匹配、接收方错误等)
TransientBalanceNotZero 中间代币未完全消耗
InsufficientOutput 最终输出低于 minOutputAmount
ExcessiveInput 总输入超过 maxInputAmount

回放保护集中在 Sera 中:executeIntent 调用 sera.consumeIntentUuid(taker, uuid),若 UUID 已被消费,将以 UuidAlreadyUsed 回滚。