跳轉至

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 使用者存入金額不足