虚拟流动性¶
网络与兼容性
| 资源 | 值 |
|---|---|
| API 基础 URL | https://api.sera.cx/api/v1 |
| 链 | 以太坊主网(chainId 1) |
| Sera 合约 | 0xB5C50C5D5f038404F85970b7f5B7259C4AC0E198 |
| Vault 合约 | 0xC7d4Fd2638e6630C8C61329878676b88A8A24D43 |
| SOR 合约 | 0xa7A0cf7cd6f043fCA23f29d8ae5aae6b46e11c18 |
签名原语。 所有交易型变更都是针对 Sera 域的 EIP-712 类型化数据签名。走 permit 路径的充值使用 ERC-2612 Permit 扩展 — USDC、EURC 以及许多现代稳定币支持,但并非所有 ERC-20 都支持;签名前请调用 GET /permit/metadata 检查。API key 管理使用 EIP-712 ManageApiKey 载荷。
已验证客户端。 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 签名载荷接受 EIP-55 校验和地址。
虚拟流动性(Virtual Liquidity, VL)允许您在多个不同交易对上同时挂出限价单,并让这些订单共享同一笔预算。系统冻结的是单个订单中的最大成本,而不是所有订单成本之和,因此更适合做市和多市场报价。
为什么选择虚拟流动性?¶
设想一位做市商希望同时在 EURC/USDC、GBPC/USDC 和 XSGD/USDC 上挂买单。如果没有 VL,每个订单都需要独立锁定抵押品,3 个订单就意味着 3 倍资金占用。使用 VL 时,一笔 USDC 预算即可为这三个订单提供支持。当其中一个订单成交后,其余订单会自动调整以适配剩余预算。
| 方式 | 所需资金 | 风险 |
|---|---|---|
| 3 个独立订单 | 所有订单成本之和 | 每个订单独立锁定 |
| 1 个 VL 批次 | 单个订单中的最大成本 | 共享预算,自动调整 |
它如何运作¶
一个 VL 批次包含:
- 一个 VL 批次包含 2 到 50 个兄弟订单(运行时通过
GET /config的limits.vl_batch获取当前上限) - 所有兄弟订单必须属于不同交易对
- 整个批次必须共享同一个 spent token(实际被花掉的代币)
- 当其中一个订单成交后,其余订单会自动缩量或取消,确保总花费不超过共享预算
flowchart TD
A[提交 VL 批次] --> B[冻结共享预算]
B --> C1[兄弟订单 1: EURC/USDC 买单]
B --> C2[兄弟订单 2: GBPC/USDC 买单]
B --> C3[兄弟订单 3: XSGD/USDC 买单]
C1 -->|成交| D[扣减预算]
D --> E{还有剩余预算吗?}
E -->|有| F[调整兄弟订单 2 和 3]
E -->|没有| G[取消兄弟订单 2 和 3] 共享预算与抵押品¶
VL 的关键在于兄弟订单位于不同的交易对上,因此任一时刻最多只有一个订单可以被撮合。这意味着 Vault 只需要冻结单个订单中的最大成本,而不是所有订单成本之和。
花费代币(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:同方向批次(全部 bid,花费 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。
下单¶
通过 POST /orders/vl/batch 提交所有兄弟订单。每个兄弟订单都携带自己签名后的 order_id / uuid_int / signature — 完整签名流程见 做市商指南。
import time, requests
expiry = int(time.time()) + 86_400
batch = requests.post(
"https://api.sera.cx/api/v1/orders/vl/batch",
json={"orders": [
{
"owner_address": wallet_address,
"side": "bid", "amount": "1000.0", "price": "1.08",
"order_type": "limit",
"from_address": EURC_ADDRESS, "to_address": USDC_ADDRESS,
"order_id": eur_order_id, "uuid_int": eur_uuid_int,
"signature": eur_sig, "expiration": expiry,
},
{
"owner_address": wallet_address,
"side": "bid", "amount": "500.0", "price": "1.27",
"order_type": "limit",
"from_address": GBPC_ADDRESS, "to_address": USDC_ADDRESS,
"order_id": gbp_order_id, "uuid_int": gbp_uuid_int,
"signature": gbp_sig, "expiration": expiry,
},
{
"owner_address": wallet_address,
"side": "bid", "amount": "2000.0", "price": "0.75",
"order_type": "limit",
"from_address": XSGD_ADDRESS, "to_address": USDC_ADDRESS,
"order_id": sgd_order_id, "uuid_int": sgd_uuid_int,
"signature": sgd_sig, "expiration": expiry,
},
]},
timeout=10,
).json()
# batch["order_ids"] — 系统接受的兄弟订单 ID 列表
const expiry = Math.floor(Date.now() / 1000) + 86_400;
const response = await fetch("https://api.sera.cx/api/v1/orders/vl/batch", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
orders: [
{
owner_address: walletAddress,
side: "bid", amount: "1000.0", price: "1.08",
order_type: "limit",
from_address: EURC_ADDRESS, to_address: USDC_ADDRESS,
order_id: eurOrderId, uuid_int: eurUuidInt,
signature: eurSig, expiration: expiry,
},
{
owner_address: walletAddress,
side: "bid", amount: "500.0", price: "1.27",
order_type: "limit",
from_address: GBPC_ADDRESS, to_address: USDC_ADDRESS,
order_id: gbpOrderId, uuid_int: gbpUuidInt,
signature: gbpSig, expiration: expiry,
},
{
owner_address: walletAddress,
side: "bid", amount: "2000.0", price: "0.75",
order_type: "limit",
from_address: XSGD_ADDRESS, to_address: USDC_ADDRESS,
order_id: sgdOrderId, uuid_int: sgdUuidInt,
signature: sgdSig, expiration: expiry,
},
],
}),
});
const batch = await response.json();
// batch.order_ids — 系统接受的兄弟订单 ID 列表
每个兄弟订单都必须带上自己的有效 expiration,并遵守与普通限价单相同的有界未来时间规则。
成交与调整流程¶
当某个兄弟订单成交时,系统自动调整批次中的其余订单:
sequenceDiagram
participant Sera
participant Vault
Sera->>Sera: 兄弟订单 1 成交(消耗 500 USD)
Sera->>Sera: 预算:1500 -> 1000 USD
alt 预算充足
Sera->>Sera: 调整剩余兄弟订单数量以适配 1000 USD
else 预算耗尽
Sera->>Sera: 取消剩余兄弟订单
end
Sera->>Vault: 更新冻结余额 调整示例¶
初始预算:1,500 USD
- 兄弟订单 1(EURC/USDC Bid 1000 @ 1.08)部分成交 500 单位 — 消耗 540 USDC
- 剩余预算:960 USDC
- 兄弟订单 2(GBPC/USDC Bid 500 @ 1.27)被调整:新数量 = floor(960 / 1.27) = 755
- 兄弟订单 3(XSGD/USDC Bid 2000 @ 0.75)被调整:新数量 = floor(960 / 0.75) = 1280
每个兄弟订单独立受限于剩余预算。
取消 VL 批次¶
通过 POST /orders/vl/cancel 取消批次中的所有兄弟订单:
const cancelRes = await fetch("https://api.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)