跳到主要内容

链上领取返佣 (On-Chain Claim)

本文档介绍如何通过智能合约领取推荐返佣。

合约信息

合约地址
ReferralRebate0xaF486e11c824389E4Ab3ced7608ac3Bd43c176B8
USDT0x572E474C3Cf364D085760784F938A1Aa397a8B9b

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`);
}

测试网水龙头

相关链接