链上领取返佣 (On-Chain Claim)
本文档介绍如何通过智能合约领取推荐返佣。
合约信息
| 合约 | 地址 |
|---|---|
| ReferralRebate | 0xaF486e11c824389E4Ab3ced7608ac3Bd43c176B8 |
| USDT | 0x572E474C3Cf364D085760784F938A1Aa397a8B9b |
Chain ID: 421614 (Arbitrum Sepolia)
领取流程
┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
│ 查询余额 │────▶│ 获取签名 │────▶│ 调用合约 │────▶│ 领取成功 │
│ dashboard │ │claim-sig │ │claimRebate│ │ │
└──────────┘ └──────────┘ └──────────┘ └──────────┘
合约 ABI
[
{
"name": "claimRebate",
"type": "function",
"inputs": [
{"name": "amount", "type": "uint256"},
{"name": "deadline", "type": "uint256"},
{"name": "signature", "type": "bytes"}
],
"outputs": [],
"stateMutability": "nonpayable"
}
]
完整领取流程
Step 1: 获取领取签名
const API_BASE = 'https://api.axblade.io/api/v1';
async function getClaimSignature(jwtToken: string, amountUsdt: string) {
const response = await fetch(`${API_BASE}/referral/on-chain/claim-signature`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${jwtToken}`
},
body: JSON.stringify({ amount: amountUsdt })
});
return response.json();
}
响应示例:
{
"amount": "10000000",
"nonce": 0,
"deadline": 1766729875,
"signature": "0x0eec1999f8915c02a0376f395d1adc529d5db009...",
"contract_address": "0xaF486e11c824389E4Ab3ced7608ac3Bd43c176B8"
}
Step 2: 调用合约领取
import { ethers } from 'ethers';
const REBATE_CONTRACT = '0xaF486e11c824389E4Ab3ced7608ac3Bd43c176B8';
const REBATE_ABI = [
'function claimRebate(uint256 amount, uint256 deadline, bytes signature) external'
];
async function claimRebate(
signer: ethers.Signer,
amount: bigint,
deadline: number,
signature: string
) {
const contract = new ethers.Contract(REBATE_CONTRACT, REBATE_ABI, signer);
const tx = await contract.claimRebate(amount, deadline, signature);
const receipt = await tx.wait();
console.log('Claim successful:', receipt.hash);
return receipt;
}
Step 3: 完整示例
import { ethers } from 'ethers';
const API_BASE = 'https://api.axblade.io/api/v1';
const REBATE_CONTRACT = '0xaF486e11c824389E4Ab3ced7608ac3Bd43c176B8';
async function claimRebateFlow(
signer: ethers.Signer,
jwtToken: string,
amountUsdt: string
) {
// 1. 获取 claim signature
const claimResponse = await fetch(`${API_BASE}/referral/on-chain/claim-signature`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${jwtToken}`
},
body: JSON.stringify({ amount: amountUsdt })
});
const { amount, deadline, signature } = await claimResponse.json();
// 2. 调用合约
const contract = new ethers.Contract(
REBATE_CONTRACT,
['function claimRebate(uint256 amount, uint256 deadline, bytes signature) external'],
signer
);
const tx = await contract.claimRebate(amount, deadline, signature);
const receipt = await tx.wait();
console.log('✅ Claim successful!');
console.log('Transaction:', receipt.hash);
console.log('Amount:', ethers.formatUnits(amount, 6), 'USDT');
return receipt;
}
使用 Cast (Foundry) 命令行
cast send --rpc-url "https://sepolia-rollup.arbitrum.io/rpc" \
--private-key "0x..." \
"0xaF486e11c824389E4Ab3ced7608ac3Bd43c176B8" \
"claimRebate(uint256,uint256,bytes)" \
"10000000" "1766729875" "0x0eec1999f8915c02a0376f395d1adc529d5db009..."
验证结果
# 查询用户 USDT 余额
cast call --rpc-url "https://sepolia-rollup.arbitrum.io/rpc" \
"0x572E474C3Cf364D085760784F938A1Aa397a8B9b" \
"balanceOf(address)(uint256)" \
"0xYourAddress"
# 查询合约剩余 USDT 余额
cast call --rpc-url "https://sepolia-rollup.arbitrum.io/rpc" \
"0x572E474C3Cf364D085760784F938A1Aa397a8B9b" \
"balanceOf(address)(uint256)" \
"0xaF486e11c824389E4Ab3ced7608ac3Bd43c176B8"
事件监听
event RebateClaimed(address indexed user, uint256 amount, uint256 nonce);
event RebateBatchSynced(uint256 indexed batchId, uint256 totalAmount, uint256 userCount);
监听示例:
const contract = new ethers.Contract(REBATE_CONTRACT, REBATE_ABI, provider);
contract.on('RebateClaimed', (user, amount, nonce, event) => {
console.log(`User ${user} claimed ${ethers.formatUnits(amount, 6)} USDT`);
console.log(`Nonce: ${nonce}`);
});
常见错误及解决方案
| 错误 | 原因 | 解决方案 |
|---|---|---|
InvalidSignature() | backendSigner 不匹配 | 联系管理员更新合约配置 |
SafeERC20: low-level call failed | 合约 USDT 余额不足 | 等待合约补充资金 |
insufficient funds for transfer | 用户 ETH 不足 | 确保用户有 ETH 支付 Gas |
DeadlineExceeded() | 签名已过期 | 重新获取 claim signature |
InvalidNonce() | Nonce 不匹配 | 检查链上 nonce 与请求是否一致 |
充值时绑定推荐码
在 AXBladeVault 充值时可以同时绑定推荐码。
const VAULT = '0xFDe43f8e6e082975d246844DEF4fE8E704403d43';
const USDT = '0x572E474C3Cf364D085760784F938A1Aa397a8B9b';
const VAULT_ABI = [
'function deposit(uint256 amount, bytes32 referralCode) external'
];
const ERC20_ABI = [
'function approve(address spender, uint256 amount) external returns (bool)'
];
async function depositWithReferral(
signer: ethers.Signer,
amountUsdt: string,
referralCode: string
) {
const usdt = new ethers.Contract(USDT, ERC20_ABI, signer);
const vault = new ethers.Contract(VAULT, VAULT_ABI, signer);
// 转换金额 (6 decimals)
const amount = ethers.parseUnits(amountUsdt, 6);
// 转换推荐码 (无推荐码则使用 ZeroHash)
const codeBytes32 = referralCode
? ethers.encodeBytes32String(referralCode)
: ethers.ZeroHash;
// 1. 授权
const approveTx = await usdt.approve(VAULT, amount);
await approveTx.wait();
// 2. 充值
const depositTx = await vault.deposit(amount, codeBytes32);
await depositTx.wait();
console.log('Deposit with referral successful');
}
链上注册推荐码
用户也可以直接在链上注册推荐码。
const STORAGE_CONTRACT = '0x984BC1C4Aa3995F9B78BA54372a10d3088C249D5';
const STORAGE_ABI = [
'function registerCode(bytes32 code) external',
'function codeOwners(bytes32 code) view returns (address)'
];
async function registerReferralCode(signer: ethers.Signer, codeString: string) {
const contract = new ethers.Contract(STORAGE_CONTRACT, STORAGE_ABI, signer);
// 转换为 bytes32 (最多 31 字符)
const codeBytes32 = ethers.encodeBytes32String(codeString);
// 检查是否已被注册
const owner = await contract.codeOwners(codeBytes32);
if (owner !== ethers.ZeroAddress) {
throw new Error('Code already registered');
}
const tx = await contract.registerCode(codeBytes32);
await tx.wait();
console.log(`Code ${codeString} registered successfully`);
}
测试网水龙头
- Arbitrum Sepolia ETH: https://faucet.arbitrum.io/
- 测试 USDT: 联系管理员获取
相关链接
- Arbiscan (Sepolia): https://sepolia.arbiscan.io/
- Vault 合约: https://sepolia.arbiscan.io/address/0xFDe43f8e6e082975d246844DEF4fE8E704403d43
- ReferralRebate 合约: https://sepolia.arbiscan.io/address/0xaF486e11c824389E4Ab3ced7608ac3Bd43c176B8