📦 Code Changes: View Diff
Core Objective: Implement the Funding Layer (Deposit & Withdraw) using a Mock Chain Architecture to validate asset flows without external blockchain dependencies.
We have a high-performance Matching Engine (Phase I) and a Product Layer (Accounts/Auth, Phase II). Now we add the Funding Layer to allow assets to enter and leave the system.
Instead of syncing 500GB of Bitcoin data, we implement a Simulator for Phase 0x11.
- Goal: Validate internal logic (Balance Credit, Risk Check, Idempotency).
- Method:
MockBtcChainandMockEvmChaintraits that simulate RPC calls.
graph LR
User[User] -->|API Request| Gateway
Gateway -->|Risk Check| FundingService
FundingService -->|Command| ME[Matching Engine]
FundingService -.->|Simulated RPC| MockChain[Mock Chain Adapter]
MockChain -.->|Callback| FundingService
| Chapter | Topic | Status |
|---|---|---|
| 0x11 | Deposit & Withdraw (Mock) | ✅ Completed |
| 0x11-a | Real Chain Integration | 🚧 Construction |
The central orchestrator for all funding operations.
- Deposit: Receives "Mock Event", checks idempotency, credits user balance via matching engine.
- Withdraw: Authenticates user, locks funds in engine, simulates broadcast, updates DB.
We abstract blockchain specifics behind a trait:
#[async_trait]
pub trait ChainClient: Send + Sync {
async fn generate_address(&self, user_id: i64) -> Result<String, ChainError>;
async fn broadcast_withdraw(&self, to: &str, amount: &str) -> Result<String, ChainError>;
// ... validation methods
}Key tables added in migrations/010_deposit_withdraw.sql:
deposit_history: Tracks incoming transactions (Key:tx_hash).withdraw_history: Tracks outgoing requests (Key:request_id).user_addresses: MapsUser <-> Asset <-> Address.
- Trigger:
POST /internal/mock/deposit { user_id, asset, amount } - Idempotency: Check if
tx_hashexists indeposit_history. - Engine Execution: Send
OrderAction::Depositto Match Engine. - Result: User Balance increases.
// src/funding/deposit.rs
pub async fn process_deposit(...) {
if db.exists(tx_hash).await? { return Ok(()); }
// Command Engine
engine.execute(Deposit(user_id, asset, amount)).await?;
// Persist
db.insert_deposit(..., "SUCCESS").await?;
}- Request:
POST /api/v1/private/withdraw/apply - Risk Check: 2FA (Future), Whitelist, Balance Check.
- Engine Lock: Send
OrderAction::WithdrawLock(Instant deduction). - Broadcast: Call
mock_chain.broadcast(). - Finalize: Update
withdraw_historywithtx_hash.
We verified this phase using a comprehensive E2E script.
Run the master script to verify the full lifecycle:
./scripts/verify_funding_trading_flow.shScenario Covered:
- Register User A & B.
- Deposit BTC to User A (Mock).
- Transfer internal funds.
- Trade (Buy/Sell) to change balances.
- Withdraw USDT from User B.
- Audit: Check DB consistency.
- Address Validation: Strict Regex for
0x...(ETH) and1/3/bc1...(BTC). - Internal Auth: Mock endpoints protected by
X-Internal-Secret.
Warning
SECURITY ADVISORY: The /internal/mock/deposit endpoint is a major security risk as it allows direct balance manipulation. It is currently protected by a secret but MUST be removed entirely once the Phase 0x11-a Sentinel (blockchain scanner) is fully integrated and stable.
Phase 0x11 establishes the "Financial Highways" of the exchange. By using a Mock Chain, we isolated the complex internal logic (Accounting, Risk, Idempotency) from the external chaos of real blockchains.
Key Achievement:
A complete, idempotent Asset Inflow/Outflow system that is "Blockchain Agnostic".
Next Step:
Phase 0x11-a: Replace the "Mock Adapter" with a "Real Node Sentinel" (Bitcoin Core / Anvil).
📦 代码变更: 查看 Diff
核心目标:实现 资金层 (Funding Layer) (充值与提现),使用 模拟链架构 (Mock Chain) 来验证资金流转,而不依赖外部区块链环境。
我们已经拥有了高性能的 撮合引擎 (Phase I) 和 产品层 (账户/鉴权, Phase II)。 现在我们需要添加 资金层,允许资产进入和离开系统。
在 Phase 0x11 中,我们实现一个 模拟器,而不是直接同步 500GB 的比特币数据。
- 目标: 验证内部逻辑 (余额入账、风控检查、幂等性)。
- 方法:
MockBtcChain和MockEvmChaintrait,模拟 RPC 调用。
graph LR
User[用户] -->|API 请求| Gateway
Gateway -->|风控检查| FundingService
FundingService -->|指令| ME[撮合引擎]
FundingService -.->|模拟 RPC| MockChain[Mock Chain 适配器]
MockChain -.->|回调| FundingService
| 章节 | 主题 | 状态 |
|---|---|---|
| 0x11 | 充值与提现 (Mock) | ✅ 已完成 |
| 0x11-a | 真实链集成 | 🚧 建设中 |
资金操作的核心协调器。
- 充值 (Deposit): 接收 "模拟事件",检查幂等性,通过撮合引擎增加用户余额。
- 提现 (Withdraw): 验证用户,锁定引擎中的资金,模拟广播,更新数据库。
我们将区块链细节抽象在 Trait 之后:
#[async_trait]
pub trait ChainClient: Send + Sync {
async fn generate_address(&self, user_id: i64) -> Result<String, ChainError>;
async fn broadcast_withdraw(&self, to: &str, amount: &str) -> Result<String, ChainError>;
// ... 验证方法
}migrations/010_deposit_withdraw.sql 新增的关键表:
deposit_history: 追踪入金 (Key:tx_hash)。withdraw_history: 追踪出金 (Key:request_id)。user_addresses: 映射User <-> Asset <-> Address。
- 触发:
POST /internal/mock/deposit { user_id, asset, amount } - 幂等性: 检查
deposit_history中是否存在tx_hash。 - 引擎执行: 发送
OrderAction::Deposit给撮合引擎。 - 结果: 用户余额增加。
// src/funding/deposit.rs
pub async fn process_deposit(...) {
if db.exists(tx_hash).await? { return Ok(()); }
// Command Engine
engine.execute(Deposit(user_id, asset, amount)).await?;
// Persist
db.insert_deposit(..., "SUCCESS").await?;
}- 请求:
POST /api/v1/private/withdraw/apply - 风控: 2FA (规划中), 白名单, 余额检查。
- 引擎锁定: 发送
OrderAction::WithdrawLock(瞬间扣除)。 - 广播: 调用
mock_chain.broadcast()。 - 终结: 更新
withdraw_history填充tx_hash。
我们使用全链路 E2E 脚本验证了本阶段功能。
运行主脚本以验证完整生命周期:
./scripts/verify_funding_trading_flow.sh覆盖场景:
- 注册 用户 A & B。
- 充值 BTC 给用户 A (模拟)。
- 划转 资金 (Internal Transfer)。
- 交易 (买/卖) 改变余额。
- 提现 USDT (用户 B)。
- 审计: 检查数据库一致性。
- 地址验证: 针对
0x...(ETH) 和1/3/bc1...(BTC) 的严格正则校验。 - 内部鉴权: Mock 端点受
X-Internal-Secret保护。
Caution
安全警告:/internal/mock/deposit 接口存在重大安全隐患,因为它允许直接修改用户余额。虽然目前增加了 Secret 校验,但在 Phase 0x11-a Sentinel(区块链扫描器)完全集成并稳定后,必须彻底移除此接口。
Phase 0x11 建立了交易所的 "资金高速公路"。 通过使用 Mock Chain,我们将复杂的内部逻辑(会计、风控、幂等性)与外部区块链的混乱隔离开来。
关键成就:
一套完整的、幂等的资产流入/流出系统,且做到 "Blockchain Agnostic" (与具体链解耦)。
下一步:
Phase 0x11-a: 将 "Mock Adapter" 替换为 "Real Node Sentinel" (Bitcoin Core / Anvil)。