充值流程
概述
DF 充值由后端监听器追踪 BSC 金库合约(ZtdxSpotVault)的 SpotDeposit 事件,并将余额记入现货钱包。无充值发起 API — 用户直接在链上与金库合约交互,后端异步完成对账。
当监听器确认 SPOT_BSC_CONFIRMATION_DEPTH 个区块(当前为 20)后,即认为充值最终完成,随即为用户增加 spot_balances.available,并向 spot_deposits 插入一条记录。幂等性由 (chain_id, tx_hash, log_index) 唯一键保证——重放同一事件为无操作。
生命周期
用户钱包
│
│ 1. DF.approve(vault, amount)
▼
DF ERC-20 合约 ─────────────────────────────────────────────▶
│
│ 2. ZtdxSpotVault.deposit(token, amount) │
▼ │
ZtdxSpotVault (0x4Fe0b354c5865ee9deb979a99030d757ae47664a) │
│ │
│ 触发 SpotDeposit(account, token, amount) │
▼ │
BSC 区块 N │
│ │
│ ≥ 20 个确认(约 40 秒) │
▼ │
后端监听器(每 2 秒轮询一次) │
│ │
├─ INSERT spot_deposits (status = "confirmed") │
└─ spot_balances.available += amount ◀────────────────────
第一步 — 授权
用户授权金库合约从其钱包中提取 amount 数量的 DF:
DF.approve(vaultAddress, amount);
// vaultAddress = 0x4Fe0b354c5865ee9deb979a99030d757ae47664a
// amount = wei(DF 有 18 位小数,1 DF = 10**18 wei)
第二步 — 充值
用户调用金库的 deposit 函数:
ZtdxSpotVault.deposit(address token, uint256 amount);
// token = 0x8063a43ed88397c1B10DA23dcC60ba1E7A0Bf555(BSC 测试网上的 DF)
// amount = wei
金库接受转账并触发事件:
event SpotDeposit(address indexed account, address indexed token, uint256 amount);
第三步 — 后端入账
监听器每隔 SPOT_BSC_POLL_INTERVAL_MS(2 000 毫秒)轮询一次 BSC。当某个 SpotDeposit 事件累积 SPOT_BSC_CONFIRMATION_DEPTH(20)个区块确认后:
- 向
spot_deposits插入一条status = "confirmed"的记录。 - 将充值用户的
spot_balances.available增加对应的入账金额。
链上组件
| 项目 | 网络 | 值 |
|---|---|---|
| BSC 链 id | BSC 测试网 | 97 |
金库合约(ZtdxSpotVault) | BSC 测试网 | 0x4Fe0b354c5865ee9deb979a99030d757ae47664a |
| DF 代币(ERC-20) | BSC 测试网 | 0x8063a43ed88397c1B10DA23dcC60ba1E7A0Bf555 |
| DF 精度 | — | 18 |
确认深度与延迟
| 参数 | 值 |
|---|---|
SPOT_BSC_CONFIRMATION_DEPTH | 20 个区块 |
| BSC 测试网出块时间 | 约 2 秒 |
| 稳态入账延迟 | 充值交易上链后约 40 秒 |
| 冷启动追块速率 | 约 30 个区块/秒 |
在冷启动阶段(例如服务重启后),监听器以约 30 个区块/秒的速率回放历史区块,直至追上链上最新高度。监听器离线期间发生的充值均会在追块过程中完成入账。
代码示例:监控充值状态
轮询 GET /spot/deposits,直到已知 tx_hash 的充值记录出现且 status = "confirmed"。
import time
import requests
BASE_URL = "https://api-sepolia.p99.world/api/v1"
JWT = "your_jwt_token"
# 链上充值交易的 tx_hash。
EXPECTED_TX = "0xabc123..."
def get_deposits(limit: int = 50) -> list:
r = requests.get(
f"{BASE_URL}/spot/deposits",
headers={"Authorization": f"Bearer {JWT}"},
params={"limit": limit},
timeout=5,
)
r.raise_for_status()
return r.json()
print(f"等待充值 {EXPECTED_TX[:12]}... 确认中...")
for attempt in range(60): # 最多轮询 5 分钟
deposits = get_deposits()
match = next((d for d in deposits if d["tx_hash"] == EXPECTED_TX), None)
if match:
print(
f"充值已 确认!amount={match['amount']} {match['token']} "
f"block={match['block_number']} confirmed_at={match['confirmed_at']}"
)
break
print(f" 第 {attempt + 1}/60 次尝试 — 暂未可见,5 秒后重试...")
time.sleep(5)
else:
print("等待充值确认超时。")
响应中的
confirmed_at时间戳表示后端完成余额入账的时间;block_number表示包含SpotDeposit事件的 BSC 区块号。