ๆฌๆๆกฃๆ่ฟฐไบ Phase 0x0B-a ๅ ้จ่ฝฌ่ดฆๅ่ฝ็ๅฎๆๅทฅไฝใๅฎ็ฐ็ป่ๅ็ซฏๅฐ็ซฏๆต่ฏๆนๆณใ
This document describes the completed work, implementation details, and end-to-end testing methodology for Phase 0x0B-a Internal Transfer feature.
ๅฎ็ฐไบ่ทจ็ณป็ป่ต้ๅ่ฝฌ็ 2-Phase Commit FSM:
โโโโโโโโโโโโโโโโโโโ
โ TransferAPI โ Gateway ๅฑ
โโโโโโโโโโฌโโโโโโโโโ
โ
โโโโโโโโโโผโโโโโโโโโ
โ TransferCoord. โ FSM ๅ่ฐๅจ
โโโโโโโโโโฌโโโโโโโโโ
โ
โโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโ
โ โ โ
โโโโโโโโโโผโโโโโโโโโ โโโโโโโโโผโโโโโโโโ โโโโโโโโโผโโโโโโโโ
โ FundingAdapter โ โ TradingAdapterโ โ TransferDb โ
โ (PostgreSQL) โ โ (UBSCore) โ โ (FSM State) โ
โโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโ
| ๆจกๅ / Module | ๆไปถ / File | ๅ่ฝ / Function |
|---|---|---|
| TransferCoordinator | src/transfer/coordinator.rs |
FSM ็ถๆๆบ้ฉฑๅจ State machine driver |
| FundingAdapter | src/transfer/adapters/funding.rs |
PostgreSQL ่ต้ๆไฝ PostgreSQL balance ops |
| TradingAdapter | src/transfer/adapters/trading.rs |
UBSCore ้้้ไฟก UBSCore channel comm |
| TransferDb | src/transfer/db.rs |
FSM ็ถๆๆไน
ๅ FSM state persistence |
| TransferChannel | src/transfer/channel.rs |
่ทจ็บฟ็จ้ไฟก Cross-thread messaging |
| Endpoint | Method | ๆ่ฟฐ / Description |
|---|---|---|
/api/v1/private/transfer |
POST | ๅๅปบๅ ้จ่ฝฌ่ดฆ |
/api/v1/private/transfer/{req_id} |
GET | ๆฅ่ฏข่ฝฌ่ดฆ็ถๆ |
/api/v1/private/balances/all |
GET | ๆฅ่ฏขๆๆ่ดฆๆทไฝ้ข |
| ่กจ / Table | ็จ้ / Purpose |
|---|---|
fsm_transfers_tb |
FSM ่ฝฌ่ดฆ็ถๆ่ฎฐๅฝ |
transfer_operations_tb |
ๅน็ญๆไฝ่ฟฝ่ธช |
balances_tb |
่ดฆๆทไฝ้ข (Funding/Spot) |
- โ ๅฎๆด็ FSM ๅฎ็ฐ (Init โ SourcePending โ SourceDone โ TargetPending โ Committed)
- โ ๅๅ่ฝฌ่ดฆ้ช่ฏ (Funding โ Spot)
- โ ๅฏๅค็จ E2E ๆต่ฏ่ๆฌ
- โ
/balances/allไฝ้ขๆฅ่ฏข API - โ 232 ไธชๅๅ ๆต่ฏ้่ฟ
# ่ฟ่กๅฎๆด E2E ๆต่ฏ (่ชๅจๅฏๅจ Gateway)
./scripts/test_transfer_e2e.sh่ๆฌไฝ็ฝฎ: scripts/test_transfer_e2e.sh
[1/6] Prerequisites Check
โ PostgreSQL connected (port 5433)
โ Release binary ready
[2/6] Setup Test Data
- Enable CAN_INTERNAL_TRANSFER for USDT
- Create 1000 USDT in Funding for user 1001
- Clear previous transfer records
[3/6] Start Gateway
- Stop existing Gateway (pgrep + kill)
- Start new Gateway with updated config
- Wait for health check
[4/6] Run Transfer Tests
- Funding โ Spot (50 USDT)
- Spot โ Funding (25 USDT)
- Verify both COMMITTED
[5/6] Verify Balance Changes
- Check Funding: 1000 โ 975 (ฮ-25)
- Use /balances/all API
[6/6] Cleanup
- Stop Gateway
import sys
sys.path.append('scripts/lib')
from api_auth import get_test_client
USER_ID = 1001
client = get_test_client(user_id=USER_ID)
headers = {'X-User-ID': str(USER_ID)}
# 1. ๆฅ่ฏขไฝ้ข / Query balances
resp = client.get('/api/v1/private/balances/all', headers=headers)
print(resp.json())
# 2. ๅ่ตท่ฝฌ่ดฆ / Create transfer
resp = client.post('/api/v1/private/transfer',
json_body={
'from': 'funding',
'to': 'spot',
'asset': 'USDT',
'amount': '50'
},
headers=headers)
print(resp.json())
# 3. ๆฅ่ฏข่ฝฌ่ดฆ็ถๆ / Query transfer status
req_id = resp.json()['data']['req_id']
resp = client.get(f'/api/v1/private/transfer/{req_id}', headers=headers)
print(resp.json())# ๆฅ่ฏขไฝ้ข (้่ฆๆญฃ็กฎ็ญพๅ)
curl http://localhost:8080/api/v1/private/balances/all \
-H "X-API-Key: AK_0000000000001001" \
-H "X-Signature: ..." \
-H "X-User-ID: 1001"PGPASSWORD=trading123 psql -h localhost -p 5433 -U trading -d exchange_info_db -c "
SELECT
CASE account_type WHEN 1 THEN 'Spot' WHEN 2 THEN 'Funding' END as account,
(available / 1000000)::text || ' USDT' as balance
FROM balances_tb
WHERE user_id = 1001 AND asset_id = 2
ORDER BY account_type;
"PGPASSWORD=trading123 psql -h localhost -p 5433 -U trading -d exchange_info_db -c "
SELECT req_id, amount, state, created_at
FROM fsm_transfers_tb
WHERE user_id = 1001
ORDER BY created_at DESC LIMIT 5;
"State ๅผๅซไน / State Values:
0: INIT10: SOURCE_PENDING20: SOURCE_DONE30: TARGET_PENDING40: COMMITTED โ-10: FAILED-20: COMPENSATING-30: ROLLED_BACK
้ฎ้ข: create_transfer_fsm ๅช่ฐ็จ coordinator.create()๏ผๆฒกๆ่ฐ็จ coordinator.execute()
ไฟฎๅค: ๆทปๅ execute() ่ฐ็จ
// src/transfer/api.rs
let req_id = coordinator.create(core_req).await?;
let state = coordinator.execute(req_id).await?; // โ Added้ฎ้ข: Decimal.to_string().parse::<u64>() ๅฏน "50000000.00000000" ่ฟๅๅคฑ่ดฅ
ไฟฎๅค: ไฝฟ็จ trunc().to_i64()
// src/transfer/db.rs
let amount_u64 = amount.trunc().to_i64().unwrap_or(0) as u64;statusๅ: INT4 (i32), ไธๆฏ INT2decimalsๅ: INT2 (i16), ไธๆฏ i32
==============================================
Internal Transfer E2E Test (Phase 0x0B-a)
==============================================
[1/6] Checking prerequisites...
โ PostgreSQL connected
โ Release binary ready
[2/6] Setting up test data...
โ Test data initialized (1000 USDT in Funding only for user 1001)
[3/6] Starting Gateway...
โ Gateway ready
[4/6] Running transfer tests with balance verification...
[BEFORE] Getting initial balances...
USDT:funding: 1000.00
[TRANSFER 1] Funding โ Spot (50 USDT)...
โ COMMITTED
[TRANSFER 2] Spot โ Funding (25 USDT)...
โ COMMITTED
[AFTER] Getting final Funding balance...
USDT:funding: 975.00
[VERIFY] Checking Funding balance changes...
โ Funding: 1000.00 โ 975.00 (ฮ-25.00)
Results: 3 passed, 0 failed
[5/6] Final database state...
Funding | 975.0000000000000000 USDT
[6/6] Cleanup...
==============================================
โ
All E2E Transfer Tests PASSED
==============================================
| ๆไปถ / File | ๆ่ฟฐ / Description |
|---|---|
scripts/test_transfer_e2e.sh |
E2E ๆต่ฏ่ๆฌ |
scripts/lib/api_auth.py |
API ่ฎค่ฏๅบ |
src/transfer/api.rs |
่ฝฌ่ดฆ API ๅค็ |
src/transfer/coordinator.rs |
FSM ๅ่ฐๅจ |
src/transfer/adapters/funding.rs |
Funding ้้ ๅจ |
src/transfer/adapters/trading.rs |
Trading ้้ ๅจ |