虛擬流動性¶
網路與相容性
| 資源 | 值 |
|---|---|
| API 基礎 URL | https://api.testnet.sera.cx/api/v1 |
| 鏈 | Sepolia(chainId 11155111) |
| Sera 合約 | 0x83475A1bD98a8DC2DCd507A747e4DC85da241D6e |
| Vault 合約 | 0x3c7945840bAE0d7e7f3824Ebccef1962629250F0 |
| SOR 合約 | 0x83c1368110B640A729f3810De5FBe94b99aa5668 |
簽名原語。 所有交易型變更都是針對 Sera domain 的 EIP-712 類型化資料簽名。走 permit 路徑的充值使用 ERC-2612 Permit 擴充功能 — USDC、EURC、EURT 以及多數現代穩定幣支援,但並非所有 ERC-20 都支援;簽名前請呼叫 GET /permit/metadata 檢查。API key 管理使用 EIP-712 ManageApiKey payload。
已驗證客戶端。 Python eth_account >= 0.10 + requests;TypeScript ethers v6(signer.signTypedData)。已驗證支援 EIP-712 類型化資料的瀏覽器錢包:MetaMask、Rabby、Frame、Coinbase Wallet、Trust、Rainbow。Safe 多簽透過 EIP-1271 支援(訊息於鏈上驗證,而非透過 ecrecover)。
地址大小寫。 讀取類端點(/balances、/orders、/fills)將 owner_address 視為大小寫敏感 — 請傳入小寫形式。EIP-712 簽名 payload 接受 EIP-55 校驗和地址。
虛擬流動性(Virtual Liquidity, VL)允許您在多個不同交易對上同時掛出限價單,並保證這些訂單的總花費永遠不會超過同一筆共享預算。系統不會為每張訂單各自鎖定資金,而是讓一個 VL 批次共用同一池抵押品,讓您無需倍增資金即可在多個交易對上提供流動性。
下面的交易對標籤和計算採用假設的基礎/報價方向。實際下單必須使用 GET /markets 返回的地址和方向,並相應調整 side、數量與價格;後面的提交示例按返回方向構造請求。
為什麼需要虛擬流動性?¶
假設一位做市商想同時在 EURC/USDC、GBPC/USDC 和 XSGD/USDC 上掛買單。若不使用 VL,每張訂單都需要獨立鎖定抵押品——3 張訂單就需要 3 倍資金。使用 VL 後,只需一筆 USDC 預算即可支撐所有三張訂單。當其中一張成交時,系統會自動調整剩餘訂單以確保不超出預算。
| 方式 | 所需資金 | 風險 |
|---|---|---|
| 3 張獨立訂單 | 所有訂單成本之和 | 每張訂單各自鎖定 |
| 1 個 VL 批次 | 單張訂單的最大成本 | 共享預算,自動調整 |
運作方式¶
一個 VL 批次包含:
- 一筆共享預算 — 以單一「花費代幣」計價的最大花費額度
- 多個同級訂單 — 2 到 50 張限價單,每張必須屬於不同交易對(執行時透過
GET /config的limits.vl_batch取得當前上限) - 自動調整 — 當其中一個同級訂單成交後,其餘訂單會自動縮量或取消以符合剩餘預算
flowchart TD
A[下 VL 批次單] --> B[凍結共享預算]
B --> C1[同級訂單 1: EURC/USDC Bid]
B --> C2[同級訂單 2: GBPC/USDC Bid]
B --> C3[同級訂單 3: XSGD/USDC Bid]
C1 -->|成交| D[從預算中扣除]
D --> E{剩餘預算?}
E -->|是| F[調整同級訂單 2 & 3]
E -->|否| G[取消同級訂單 2 & 3] 共享預算與抵押品¶
共享抵押品依賴撮合引擎在同一預算下覈算消耗,並隨著成交調整兄弟訂單。不同市場本身不會阻止多條腿成交。賬務預留單腿最大成本,並執行共享剩餘預算約束。
花費代幣(fromToken)規則¶
VL 批次中所有同級訂單必須解析為相同的 fromToken——即實際被花掉的 ERC-20 代幣。fromToken 由 side 與交易對定義共同決定,其中 from_address 是基礎代幣、to_address 是報價代幣:
| Side | fromToken(花費) | toToken(收到) | 每次成交成本 |
|---|---|---|---|
| Bid(買入) | to_address(報價代幣) | from_address(基礎代幣) | quantity x fill_price |
| Ask(賣出) | from_address(基礎代幣) | to_address(報價代幣) | quantity |
不會自動修正
系統不會自動翻轉 side 或交換交易對方向來讓各同級訂單的 fromToken 一致。fromToken 會根據提交的 side、from_address 與 to_address 推導;如果推導出的支出代幣不一致,整個批次會直接回傳 422。
範例 1:同側批次(全部為買單,花費 USDC)
- Bid
from_address: EURC,to_address: USDC@ 1.08 — fromToken = USDC - Bid
from_address: GBPC,to_address: USDC@ 1.27 — fromToken = USDC - Bid
from_address: XSGD,to_address: USDC@ 0.75 — fromToken = USDC
凍結金額:1,500 USDC(單張訂單的最大成本),而非 3,215 USDC。
範例 2:混合側批次(皆花費 USDC)
當 USDC 在一個交易對中作為報價幣、在另一個交易對中作為基礎幣時,只要推導出的 fromToken 都是 USDC,您仍然可以將它們放入同一批次:
- Bid
from_address: MYRC,to_address: USDC@ 4.50 — fromToken = USDC - Ask
from_address: USDC,to_address: GBPC@ 0.79 — fromToken = USDC
此批次有效,因為兩張訂單都花費 USDC。
範例 3:無效的混合側批次(fromToken 不一致)
- Ask
from_address: MYRC,to_address: USDC@ 4.50 — fromToken = MYRC - Ask
from_address: GBPC,to_address: USDC@ 1.27 — fromToken = GBPC
即使這兩個市場都以 USDC 計價,但一張同級訂單實際支出 MYRC,另一張實際支出 GBPC。此批次會被拒絕並回傳 422。
下 VL 批次單¶
先加載做市商指南的配置及 VL 幫助函數。該函數逐腿預覽,使用規範消息和共享組 UUID 簽名,在發送前保存完整請求並返回完整響應。選擇批量大小前讀取 GET /config → limits.vl_batch。
下面按兩個市場各自返回的方向,讓兩條腿都支出 USDC。數量單位為 base,價格單位為 quote/base;1000 和 1 僅演示請求流程,應替換為你在這些單位下的目標數量/價格。上方預算示例採用假設的市場方向,不代表實際部署註冊表。
response = requests.get(f"{API}/markets", timeout=10)
response.raise_for_status()
markets = response.json()["markets"]
selected = [m for m in markets if "USDC" in (m["base_symbol"], m["quote_symbol"])][:2]
if len(selected) < 2:
raise RuntimeError("Two distinct active markets spending USDC are required")
expiry = int(time.time()) + 3600
legs = [{
"side": "ask" if m["base_symbol"] == "USDC" else "bid",
"base": {"address": m["base_address"], "decimals": m["base_decimals"]},
"quote": {"address": m["quote_address"], "decimals": m["quote_decimals"]},
"amount": Decimal("1000"), "price": Decimal("1"), "expiration": expiry,
} for m in selected]
batch = place_vl_batch(legs)
print(batch) # Retain outcomes and budget status, not only order_ids.
const marketsResponse = await fetch(`${API}/markets`);
if (!marketsResponse.ok) throw new Error(`markets: ${marketsResponse.status}`);
const selected = (await marketsResponse.json()).markets.filter((m: any) =>
[m.base_symbol, m.quote_symbol].includes("USDC")).slice(0, 2);
if (selected.length < 2) throw new Error("Two distinct active markets spending USDC are required");
const expiry = Math.floor(Date.now() / 1000) + 3600;
const legs = selected.map((m: any) => ({
side: (m.base_symbol === "USDC" ? "ask" : "bid") as "ask" | "bid",
base: { address: m.base_address, decimals: m.base_decimals },
quote: { address: m.quote_address, decimals: m.quote_decimals },
amount: "1000", price: "1", expiration: expiry,
}));
const batch = await placeVlBatch(legs);
console.log(batch); // Retain outcomes and budget status, not only order_ids.
下單結果¶
| 字段 | 解釋 |
|---|---|
order_ids | 已提交身份,僅憑存在不能確認掛單數量或結算 |
amendments | 查看 quantity_semantics:placement_total_quantity 是下單總量,remaining_quantity 是剩餘量;不能把所有 actual_amount 當成當前剩餘掛單量 |
cancelled | 下單期間被移除的訂單及原因 |
fills | 即時撮合證據,remaining 是成交後剩餘量;仍需確認鏈上結算 |
vl_group | status=confirmed 時,max_budget - budget_consumed 是下單時的預算快照,之後的成交仍可改變它 |
預算狀態為 pending、budget_consumed 為 null 或 group 缺失時,不要推斷零消耗或已確認掛單量。結果空數組和舊響應缺字段都不能證明按完整簽名數量掛單。應查詢訂單/成交核對,保留已保存請求;核對後如需重試,使用原 body,不為結果未知的批次生成新 ID。
成交與調整流程¶
當某個同級訂單成交時,系統會自動調整批次中的其餘訂單:
sequenceDiagram
participant Sera
participant Accounting
Sera->>Sera: 同級訂單 1 成交(消耗 500 USD)
Sera->>Sera: 預算:1500 → 1000 USD 剩餘
alt 預算充足
Sera->>Sera: 調整剩餘同級訂單數量以符合 1000 USD
else 預算耗盡
Sera->>Sera: 取消剩餘同級訂單
end
Sera->>Accounting: 更新凍結餘額 調整範例¶
起始預算:1,500 USDC。以下使用假設的 base/quote 方向:
- EURC/USDC bid 1000 @ 1.08 成交 500,消耗 540 USDC。
- 剩餘預算為 960 USDC。
- GBPC/USDC bid 500 @ 1.27 需要 635 USDC,所以剩餘數量保持 500,不會增加為 755。
- XSGD/USDC bid 2000 @ 0.75 縮減為 1280,前提是該數量滿足市場精度和已簽名結算量子。
調整只在需要時減少當前剩餘數量。計算使用代幣 raw 單位和已簽名結算量子,不能一律向下取整為整數個代幣。
取消 VL 批次¶
透過 POST /orders/vl/cancel 取消批次中的所有同級訂單:
const cancelRes = await fetch("https://api.testnet.sera.cx/api/v1/orders/vl/cancel", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
owner_address: walletAddress,
vl_batch_id: batch.order_ids[0], // 批次的主訂單 ID
signature: cancelVlSig, // EIP-712 CancelVLBatch 簽名
}),
});
取消行為:
- 取消單個同級訂單(透過
POST /orders/cancel)— 預算不會解凍(其他同級訂單仍在掛單中) - 取消整個批次(透過
POST /orders/vl/cancel)— 所有同級訂單被取消,剩餘預算解凍 - 所有同級訂單成交或取消 — 當沒有活躍的同級訂單時,任何剩餘預算都會被解凍
驗證規則¶
VL 批次在下單時進行驗證。必須滿足以下限制:
| 規則 | 原因 |
|---|---|
| 所有同級訂單在不同交易對上 | 防止同一個訂單簿上的競爭條件 |
| 所有同級訂單共享同一個花費代幣 | 確保單一預算可以支撐所有訂單 |
| 每批次 2 到 50 個同級訂單 | 透過 GET /config 的 limits.vl_batch 讀取當前值 |
| 每個同級訂單是有效的限價單 | 適用標準訂單驗證 |
有效:
- Bid EURC/USDC + Bid GBPC/USDC + Bid XSGD/USDC(全部 fromToken = USDC)
- Ask USDC/GBPC + Bid MYRC/USDC(方向混合,但 fromToken 都是 USDC)
無效:
- Bid EURC/USDC + Bid EURC/USDC(重複交易對)
- Bid XSGD/USDC + Ask USDC/XSGD(正反向互逆市場)
- Ask MYRC/USDC + Ask GBPC/USDC(fromToken = MYRC vs GBPC —— 不一致,回傳 422 拒絕)