跳转至

订单生命周期

网络与兼容性

资源 值
API 基础 URL https://api.testnet.sera.cx/api/v1
链 Sepolia(chainId 11155111)
Sera 合约 0x83475A1bD98a8DC2DCd507A747e4DC85da241D6e
Vault 合约 0x3c7945840bAE0d7e7f3824Ebccef1962629250F0
SOR 合约 0x83c1368110B640A729f3810De5FBe94b99aa5668

签名原语。 所有交易型变更都是针对 Sera 域的 EIP-712 类型化数据签名。走 permit 路径的充值使用 ERC-2612 Permit 扩展 — USDC、EURC、EURT 以及多数现代稳定币支持,但并非所有 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 校验和地址。

本教程将引导您了解 Sera 上限价单的完整生命周期 — 从下单到领取收益。

概述

sequenceDiagram
    participant User
    participant API as Sera API
    participant Chain as Ethereum

    User->>API: POST /orders (signed order)
    API-->>User: order_id
    Note over API: Order is matched<br/>when counterparty found
    API->>Chain: Settlement on-chain
    User->>API: GET /orders/{id}
    API-->>User: Status: settled
    Note over User: Proceeds available<br/>in vault balance

第 1 步:检查服务器时间

在创建签名之前,与服务器时钟同步以避免过期问题:

import requests

time_res = requests.get("https://api.testnet.sera.cx/api/v1/system/time")
server_time = time_res.json()["timestamp"]
print(f"Server time: {server_time}")
const timeRes = await fetch("https://api.testnet.sera.cx/api/v1/system/time");
const { timestamp } = await timeRes.json();
console.log("Server time:", timestamp);

所有已签名订单都必须带 expiration,并且 API 会强制执行 now < expiration <= now + 365 天 - 300 秒。请使用服务器时间,而不是只依赖浏览器或本地系统时钟。

第 2 步:查询可用代币

获取支持的代币列表以找到您需要的合约地址:

tokens = requests.get("https://api.testnet.sera.cx/api/v1/tokens").json()["tokens"]

# 查找 USDC 和 EURC 地址
usdc = next(t for t in tokens if t["symbol"] == "USDC")
eurc = next(t for t in tokens if t["symbol"] == "EURC")
const tokensRes = await fetch("https://api.testnet.sera.cx/api/v1/tokens");
const { tokens } = await tokensRes.json();

// 查找 USDC 和 EURC 地址
const usdc = tokens.find((t: any) => t.symbol === "USDC");
const eurc = tokens.find((t: any) => t.symbol === "EURC");

第 3 步:下限价单

先完成做市商指南的配置和单笔帮助函数,包括市场选择。BASE、QUOTE 来自市场返回值。帮助函数预览并使用规范字段签名,在发送前保存完整请求,出错时停止。以下价格 1 是 quote/base 单位的演示值,请按当前市场选择价格。

placed = place_order("bid", BASE, QUOTE, Decimal("1000"),
                     Decimal("1"), int(time.time()) + 3600)
order_id = placed["order_id"]
const placed = await placeOrder("bid", BASE, QUOTE, "1000", "1",
                                Math.floor(Date.now() / 1000) + 3600);
const orderId = placed.order_id;

第 4 步:监控订单状态

使用您的 API 密钥轮询订单状态:

status = requests.get(
    f"https://api.testnet.sera.cx/api/v1/orders/{order_id}",
    headers={"Authorization": "Bearer YOUR_API_KEY:YOUR_API_SECRET"},
    timeout=10,
).json()
print("Status:", status["status"])
# 外部状态:"pending"、"matched"、"settled"、"cancelled"、"failed"
print("Filled:", status["filled_amount"])
print("Signed uuid_int:", status["uuid_int"])
const statusRes = await fetch(
  `https://api.testnet.sera.cx/api/v1/orders/${orderId}`,
  { headers: { "Authorization": "Bearer YOUR_API_KEY:YOUR_API_SECRET" } },
);
const status = await statusRes.json();
console.log("Status:", status.status);
// 外部状态:"pending"、"matched"、"settled"、"cancelled"、"failed"
console.log("Filled:", status.filled_amount);
console.log("Signed uuid_int:", status.uuid_int);

第 5 步:查看余额

订单结算后,收益会出现在您的 Vault 余额中:

balances = requests.get(
    "https://api.testnet.sera.cx/api/v1/balances",
    params={"owner_address": wallet_address},
    headers={"Authorization": "Bearer YOUR_API_KEY:YOUR_API_SECRET"},
    timeout=10,
).json()["balances"]

for bal in balances:
    print(f"{bal['symbol']}: vault_raw={bal['vault_available']}, "
          f"frozen_raw={bal['vault_frozen']}, decimals={bal['decimals']}")
const balanceRes = await fetch(
  `https://api.testnet.sera.cx/api/v1/balances?owner_address=${walletAddress}`,
  { headers: { "Authorization": "Bearer YOUR_API_KEY:YOUR_API_SECRET" } },
);

const { balances } = await balanceRes.json();
for (const bal of balances) {
  console.log(`${bal.symbol}: vault_raw=${bal.vault_available}, ` +
              `frozen_raw=${bal.vault_frozen}, decimals=${bal.decimals}`);
}

GET /balances 现在返回原始 uint256 十进制字符串。展示给用户前,请结合每一行的 decimals 字段自行转换。

第 6 步:取消订单(可选)

如果您想取消未成交或部分成交的订单:

# Reuse cancel_order from the Market Maker Guide.
cancel_order(order_id, int(status["uuid_int"]))
# Query this order again to confirm its current state.
// Reuse cancelOrder from the Market Maker Guide.
await cancelOrder(orderId, BigInt(status.uuid_int));
// Query this order again to confirm its current state.

Note

下单后有可配置的撤单冷却期(默认 300 秒)。命中冷却返回 429,当前实现没有高频账户豁免。限流也返回 429,应结合响应判断。

第 7 步:提款(可选)

将资金从 Vault 转回钱包,请使用即时提款流程:

  1. 调用 POST /withdraw 获取执行者联签。
  2. 调用 POST /withdraw/build 获取未签名的 executeInstantWithdrawDualSig 交易。
  3. 在本地签名该交易,然后通过 POST /withdraw/send 广播。

API 不可用时,可按请求、等待期、执行窗口及余额规则使用链上紧急提款流程。

虚拟流动性订单

VL 订单的生命周期与标准限价单相同,但共享预算管理。当某个 VL 同胞订单成交时,撮合引擎会自动修改或取消剩余同胞订单,以保持在预算内。

主要区别:

  • 下单 — 使用 POST /orders/vl/batch 代替 POST /orders
  • 取消 — 使用 POST /orders/vl/cancel 取消整个批次,或使用 POST /orders/cancel 取消单个同胞订单
  • 预算跟踪 — 系统在所有同胞订单间跟踪共享的冻结余额;某个同胞的成交会减少其他同胞可用的预算

完整指南请参见 虚拟流动性。

订单状态汇总

状态 含义 可取消?
pending 已提交、挂单中或部分成交 是
matched 所有腿在撮合引擎中已交叉,链上结算进行中 否
settled 已完全成交且链上确认 否
cancelled 已在完全成交前取消 否
failed 被拒绝或结算 revert 通常否;查看 error 与 error_code

pending 可以表示尚未成交、部分成交后仍有剩余数量,或已提交但尚未进入链上结算的订单。前端应结合 filled_amount、remaining_amount、settlement_summary、/fills 以及 settlement_economics 判断用户资金变化。公共 API 不暴露协议价差收入或交易对手转账拆分。