跳到主要内容

充值与提现 (Deposit & Withdraw)

本文档介绍 AXBlade 平台的充值和提现流程。

合约地址

合约地址网络
AXBladeVault0xFDe43f8e6e082975d246844DEF4fE8E704403d43Arbitrum Sepolia
USDT0x572E474C3Cf364D085760784F938A1Aa397a8B9bArbitrum Sepolia

Chain ID: 421614 RPC: https://sepolia-rollup.arbitrum.io/rpc

API 接口概览

功能方法路径认证
准备充值POST/deposit/prepare
充值历史GET/deposit/history
请求提现POST/withdraw/request
提现历史GET/withdraw/history
提现详情GET/withdraw/:id
取消提现DELETE/withdraw/:id/cancel
确认提现POST/withdraw/:id/confirm

充值流程

流程图

┌──────────┐     ┌──────────┐     ┌──────────┐     ┌──────────┐
│ 客户端 │────▶│ 准备充值 │────▶│ Approve │────▶│ Deposit │
│ │ │ API │ │ USDT │ │ 合约 │
└──────────┘ └──────────┘ └──────────┘ └──────────┘
│ │
▼ ▼
┌──────────┐ ┌──────────┐
│ 链上交易 │ │ 事件监听 │
│ 确认 │ │ 更新余额 │
└──────────┘ └──────────┘

Step 1: 准备充值

端点: POST /api/v1/deposit/prepare

请求体:

{
"token": "USDT",
"amount": "100.00"
}

响应:

{
"contract_address": "0xFDe43f8e6e082975d246844DEF4fE8E704403d43",
"token_address": "0x572E474C3Cf364D085760784F938A1Aa397a8B9b",
"amount": "100.00",
"estimated_gas": 100000
}

Step 2: 授权 USDT

const usdt = new ethers.Contract(tokenAddress, [
'function approve(address,uint256) returns (bool)',
'function allowance(address,address) view returns (uint256)'
], signer);

const amountWei = ethers.parseUnits('100', 6);
const allowance = await usdt.allowance(userAddress, vaultAddress);

if (allowance < amountWei) {
const approveTx = await usdt.approve(vaultAddress, ethers.MaxUint256);
await approveTx.wait();
}

Step 3: 调用合约充值

const vault = new ethers.Contract(vaultAddress, [
'function deposit(uint256,bytes32)'
], signer);

const amountWei = ethers.parseUnits('100', 6);
const referralCode = ethers.ZeroHash; // 无推荐码

const tx = await vault.deposit(amountWei, referralCode);
await tx.wait();

console.log('充值成功!');

提现流程

流程图

┌──────────┐     ┌──────────┐     ┌──────────┐     ┌──────────┐
│ 客户端 │────▶│ 请求提现 │────▶│ 获取签名 │────▶│ 调用合约 │
│ │ │ API │ │ 后端签名 │ │ withdraw │
└──────────┘ └──────────┘ └──────────┘ └──────────┘
│ │ │
▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐
│ 余额检查 │ │ EIP-712 │ │ 签名验证 │
│ PnL验证 │ │ 签名 │ │ 转账USDT │
└──────────┘ └──────────┘ └──────────┘

Step 1: 请求提现

端点: POST /api/v1/withdraw/request

请求体:

{
"token": "USDT",
"amount": "50.00"
}

成功响应:

{
"withdraw_id": "550e8400-e29b-41d4-a716-446655440000",
"token": "0x572e474c3cf364d085760784f938a1aa397a8b9b",
"amount": "50.00",
"backend_signature": "0x1234...abcd",
"nonce": 1,
"expiry": 1703581200,
"vault_address": "0xFDe43f8e6e082975d246844DEF4fE8E704403d43"
}

余额不足响应:

{
"error": "余额不足。请求提现: 50.00, 实际可提: 30.00 (可用: 40.00, 未实现盈亏: -10.00)。原因: 2 个持仓, 未实现亏损 10.00"
}

Step 2: 调用合约提现

const vault = new ethers.Contract(vaultAddress, [
'function withdraw(address,uint256,uint256,uint256,bytes)'
], signer);

const tx = await vault.withdraw(
withdrawResponse.token,
ethers.parseUnits('50', 6),
withdrawResponse.nonce,
withdrawResponse.expiry,
withdrawResponse.backend_signature
);

await tx.wait();
console.log('提现成功!');

Step 3: 确认提现 (可选)

端点: POST /api/v1/withdraw/:id/confirm

{
"tx_hash": "0xabc123..."
}

提现状态

状态说明
pending等待处理
signed已签名,等待用户提交链上交易
submitted用户已提交链上交易
confirmed链上交易已确认
cancelled已取消
failed失败

取消提现

只有 signed 状态的提现可以取消:

端点: DELETE /api/v1/withdraw/:id/cancel


历史记录查询

充值历史

端点: GET /api/v1/deposit/history

响应:

{
"deposits": [
{
"id": "550e8400-e29b-41d4-a716-446655440001",
"token": "USDT",
"amount": "100.00",
"tx_hash": "0xabc123...",
"status": "confirmed",
"created_at": 1703577600
}
]
}

提现历史

端点: GET /api/v1/withdraw/history

响应:

{
"withdrawals": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"token": "USDT",
"amount": "50.00",
"nonce": 1,
"expiry": 1703581200,
"backend_signature": "0x1234...abcd",
"tx_hash": "0xdef456...",
"status": "confirmed",
"created_at": 1703578800
}
]
}

完整代码示例

import { ethers } from 'ethers';

const API_BASE = 'https://api.axblade.io/api/v1';
const VAULT_ADDRESS = '0xFDe43f8e6e082975d246844DEF4fE8E704403d43';
const USDT_ADDRESS = '0x572E474C3Cf364D085760784F938A1Aa397a8B9b';

// 充值
async function deposit(signer: ethers.Signer, token: string, amount: string): Promise<void> {
const userAddress = await signer.getAddress();

// 1. 准备充值
const prepareRes = await fetch(`${API_BASE}/deposit/prepare`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
},
body: JSON.stringify({ token: 'USDT', amount })
});

const { contract_address, token_address } = await prepareRes.json();

// 2. 检查并授权 USDT
const usdt = new ethers.Contract(token_address, [
'function approve(address,uint256) returns (bool)',
'function allowance(address,address) view returns (uint256)'
], signer);

const amountWei = ethers.parseUnits(amount, 6);
const allowance = await usdt.allowance(userAddress, contract_address);

if (allowance < amountWei) {
const approveTx = await usdt.approve(contract_address, ethers.MaxUint256);
await approveTx.wait();
}

// 3. 调用充值
const vault = new ethers.Contract(contract_address, [
'function deposit(uint256,bytes32)'
], signer);

const tx = await vault.deposit(amountWei, ethers.ZeroHash);
await tx.wait();

console.log('充值成功!');
}

// 提现
async function withdraw(signer: ethers.Signer, token: string, amount: string): Promise<void> {
// 1. 请求提现签名
const withdrawRes = await fetch(`${API_BASE}/withdraw/request`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
},
body: JSON.stringify({ token: 'USDT', amount })
});

if (!withdrawRes.ok) {
const error = await withdrawRes.json();
throw new Error(error.error);
}

const {
withdraw_id,
token: tokenAddress,
backend_signature,
nonce,
expiry,
vault_address
} = await withdrawRes.json();

// 2. 调用合约提现
const vault = new ethers.Contract(vault_address, [
'function withdraw(address,uint256,uint256,uint256,bytes)'
], signer);

const amountWei = ethers.parseUnits(amount, 6);
const tx = await vault.withdraw(
tokenAddress,
amountWei,
nonce,
expiry,
backend_signature
);

const receipt = await tx.wait();

// 3. 确认提现
await fetch(`${API_BASE}/withdraw/${withdraw_id}/confirm`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
},
body: JSON.stringify({ tx_hash: receipt.hash })
});

console.log('提现成功!');
}

错误处理

错误说明解决方案
TIMESTAMP_EXPIRED签名时间戳过期重新获取 nonce 并签名
SIGNATURE_INVALID签名验证失败检查签名参数和钱包地址
INSUFFICIENT_BALANCE余额不足检查可用余额
WITHDRAWAL_NOT_FOUND提现记录不存在检查提现 ID
INVALID_STATUS状态不正确只能取消 signed 状态的提现

测试网资源