跳轉至

虛擬流動性

網路與相容性

資源 值
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 方向:

  1. EURC/USDC bid 1000 @ 1.08 成交 500,消耗 540 USDC。
  2. 剩餘預算為 960 USDC。
  3. GBPC/USDC bid 500 @ 1.27 需要 635 USDC,所以剩餘數量保持 500,不會增加為 755。
  4. XSGD/USDC bid 2000 @ 0.75 縮減為 1280,前提是該數量滿足市場精度和已簽名結算量子。

調整只在需要時減少當前剩餘數量。計算使用代幣 raw 單位和已簽名結算量子,不能一律向下取整為整數個代幣。

取消 VL 批次

透過 POST /orders/vl/cancel 取消批次中的所有同級訂單:

cancel_res = requests.post(
    "https://api.testnet.sera.cx/api/v1/orders/vl/cancel",
    json={
        "owner_address": wallet_address,
        "vl_batch_id":   batch["order_ids"][0],   # 批次的主訂單 ID
        "signature":     cancel_vl_sig,           # EIP-712 CancelVLBatch 簽名
    },
    timeout=10,
)
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 拒絕)

下一步