虚拟流动性¶
虚拟流动性(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 提交所有兄弟订单:
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,必须与签名值一致
uuid_int: eurUuidInt, // 由 executor_id + UUID bits 生成的组合 uint256
signature: eurSig, // EIP-712 Order 签名
expiration: Math.floor(Date.now() / 1000) + 86400
},
{
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: Math.floor(Date.now() / 1000) + 86400
},
{
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: Math.floor(Date.now() / 1000) + 86400
}
]
})
});
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)