跳转至

Sera.sol

用于订单撮合、存款和提款的核心结算合约。

主网: 0xB5C50C5D5f038404F85970b7f5B7259C4AC0E198 源代码: src/Sera.sol

常量

string public constant NAME = "Sera";
string public constant VERSION = "1";
uint32 public constant WITHDRAW_DELAY_BLOCKS = 7200;       // ~24 hours
uint32 public constant WITHDRAW_EXPIRATION_BLOCKS = 14400;  // ~48 hours
uint256 public constant MAX_EXPIRATION = 365 days;

数据结构

Order

struct Order {
    address user;                 // Order originator
    uint48 expiration;            // Expiration timestamp
    uint48 feeBps;                // Fee in basis points
    address recipient;            // External recipient (address(0) = vault swap)
    address fromToken;            // Input token
    address toToken;              // Output token
    uint256 fromAmount;           // Input amount
    uint256 toAmount;             // Minimum output amount (price protection)
    uint256 initialDepositAmount; // Wallet funding for SOR legs
    uint256 uuid;                 // Unique identifier for replay protection
}

MatchData

struct MatchData {
    Order order0;          // First order
    bytes signature0;      // EIP-712 signature for order0
    uint256 matchAmount0;  // Amount of order0.fromToken to fill
    Order order1;          // Second order
    bytes signature1;      // EIP-712 signature for order1
    uint256 matchAmount1;  // Amount of order1.fromToken to fill
}

WithdrawIntent

struct WithdrawIntent {
    address user;          // Withdrawing user
    address[] tokens;      // Tokens to withdraw (1-20)
    uint256[] amounts;     // Amounts per token
    address recipient;     // Withdrawal destination
    uint256 deadline;      // Signature deadline
    uint256 uuid;          // Replay protection
}

存款函数

depositFund

将代币从您的钱包存入 Vault。

function depositFund(address _token, address _owner, uint256 _value) public
参数 类型 说明
_token address 要存入的 ERC-20 代币
_owner address 必须为 msg.sender
_value uint256 存入金额

要求:

  • 调用者必须为 _owner
  • 代币必须在白名单中
  • 合约不能处于暂停状态

depositFundWithPermit

使用 ERC-2612 permit 存款(在一笔交易中完成授权 + 存款)。

function depositFundWithPermit(
    address _token,
    address _owner,
    uint256 _permitAmount,
    uint256 _depositAmount,
    uint256 _deadline,
    bytes calldata _sig
) public
参数 类型 说明
_token address ERC-20 代币
_owner address 存款人(必须为 msg.sender
_permitAmount uint256 permit 签名中的金额
_depositAmount uint256 实际存款金额(必须 ≤ _permitAmount
_deadline uint256 Permit 截止时间
_sig bytes ERC-2612 permit 签名(64 或 65 字节)

提款函数

emergencyWithdraw

当 API 不可用时的两步延迟提款。

function emergencyWithdraw(address token, uint256 amount) public

流程:

  1. 第一次调用 — 发起提款请求,记录区块号
  2. 等待 — 必须经过至少 7,200 个区块(约 24 小时)
  3. 第二次调用 — 使用相同参数执行提款

要求:

  • 金额必须 > 0
  • 执行必须在请求后 14,400 个区块(约 48 小时)内完成
  • 执行金额必须与请求金额匹配

事件:

event WithdrawRequested(address indexed user, address indexed token, uint256 amount, uint256 indexed requestBlock);
event Withdraw(address indexed token, address indexed to, uint256 amount);

Note

被冻结的用户可以使用紧急提款。这确保资金始终可以取回。

executeInstantWithdrawDualSig

使用用户和执行者双重签名的即时提款。

function executeInstantWithdrawDualSig(
    WithdrawIntent calldata intent,
    bytes calldata userSignature,
    address executor,
    bytes calldata executorSignature
) external
参数 类型 说明
intent WithdrawIntent 提款参数
userSignature bytes 用户的 EIP-712 WithdrawIntent 签名
executor address 协同签名的执行者地址;必须持有 EXECUTOR_ROLE
executorSignature bytes 执行者的 EIP-712 WithdrawIntent 签名

要求:

  • 截止时间未过期
  • UUID 未被使用过
  • 每次提款 1-20 种代币
  • executor 必须持有 EXECUTOR_ROLE
  • 两个签名都必须有效(EOA 或 ERC-1271)

支持在单笔交易中进行多代币提款。

事件:

event InstantWithdraw(address indexed user, uint256 indexed uuid, address indexed token, uint256 amount, address recipient);

订单撮合

matchOrders

结算已匹配的订单对。由授权的执行者调用。

function matchOrders(MatchData calldata _match, uint256 deadline) external
参数 类型 说明
_match MatchData 两个订单及其签名和成交金额
deadline uint256 Unix 时间戳;过期则交易回退

验证:

  • 代币对称性:order0.fromToken == order1.toToken,反之亦然
  • 不能自我撮合(不同的订单哈希)
  • 不能同币种撮合
  • 两个订单都未过期
  • 两个签名都有效
  • Vault 余额充足
  • 成交金额在订单限额范围内

事件:

event OrderMatched(
    bytes32 indexed orderHash0, address indexed user0, address token0, uint256 amount0, uint256 protocolTake0,
    bytes32 indexed orderHash1, address user1, address token1, uint256 amount1, uint256 protocolTake1
);
event OrderFullyFilled(bytes32 indexed orderHash, address indexed user);

状态变量

mapping(bytes32 => uint256) public filledAmount;  // Partial fill tracking per order hash
mapping(address => mapping(uint256 => bool)) public isUuidExecuted;  // Replay protection
mapping(address => mapping(address => WithdrawRequest)) public withdrawRequests;  // Pending withdrawals

EIP-712 类型哈希

// Order signing
bytes32 constant ORDER_TYPEHASH = keccak256(
    "Order(address user,uint48 expiration,uint48 feeBps,address recipient,address fromToken,address toToken,uint256 fromAmount,uint256 toAmount,uint256 initialDepositAmount,uint256 uuid)"
);

// Withdrawal signing
bytes32 constant WITHDRAW_INTENT_TYPEHASH = keccak256(
    "WithdrawIntent(address user,address[] tokens,uint256[] amounts,address recipient,uint256 deadline,uint256 uuid)"
);

SOR Digest 辅助函数

Sera 同时暴露 getIntentDigest(...),返回 SeraSOR 用于路由兑换 Intent 的 EIP-712 摘要。

管理员函数

函数 角色 说明
setTreasury(address) Admin 设置金库地址
setSlippageShares(...) Admin 配置链上滑点分配参数
batchModifyWhitelistedTokens(...) Admin 白名单/取消白名单代币
setTrustedRouter(address) Admin 设置 SeraSOR 地址
rescueToken(address, address) Admin 救回误发的代币
pause() / unpause() Pauser 紧急暂停/恢复

错误

错误 原因
UserFrozen 用户账户被冻结
AmountBelowMinimum 订单低于代币最低金额
WithdrawNotReady 提款延迟期未满
WithdrawExpired 提款请求已过期
IntentExpired 签名截止时间已过
UuidAlreadyUsed 检测到 UUID 重放
TokenMismatch 订单代币对不匹配
SelfMatch 尝试将订单与自身撮合
OrderExpired 订单过期时间戳已过
OrderFilledAmountExceeded 成交将超过订单剩余金额
InvalidSignature 签名验证失败
InsufficientVaultBalance 用户存款不足