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。
| 參數 | 類型 | 說明 |
|---|---|---|
_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 不可用時的兩步驟延遲提取。
流程:
- 第一次呼叫 — 發起提取請求,記錄區塊號
- 等待 — 至少需要經過 7,200 個區塊(約 24 小時)
- 第二次呼叫 — 使用相同參數執行提取
要求:
- 金額必須 > 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¶
結算已撮合的訂單對。由授權執行者呼叫。
| 參數 | 類型 | 說明 |
|---|---|---|
_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 | 使用者存入金額不足 |