跳到主要内容

推荐系统 API (Referral)

后端版本: v0.3.0


概述

AXBlade Referral 系统支持推荐码注册、绑定、返佣查询和链上领取功能。

合约地址 (Arbitrum Sepolia Testnet)

合约地址说明
USDT0x572E474C3Cf364D085760784F938A1Aa397a8B9b测试 USDT (6 decimals)
ZTDXVault0xFDe43f8e6e082975d246844DEF4fE8E704403d43充值/提现合约
ReferralStorage0x984BC1C4Aa3995F9B78BA54372a10d3088C249D5推荐码存储合约
ReferralRebate0xaF486e11c824389E4Ab3ced7608ac3Bd43c176B8返佣分发合约

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


1. 链上查询接口 (无需认证)

1.1 获取用户返佣信息

GET /referral/on-chain/user-rebate/:address

响应

{
"address": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266",
"claimed_usd": "0",
"nonce": 0,
"referral_code": "",
"referrer": "0x0000000000000000000000000000000000000000",
"tier_level": 0,
"tier_name": "Bronze"
}

1.2 获取推荐关系信息

GET /referral/on-chain/referral-info/:address

响应

{
"address": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266",
"code": "ALICE2024",
"referrer": "0x70997970c51812dc3a010c7d01b50e0d17dc79c8",
"total_rebate_bps": 1000,
"trader_discount_bps": 500,
"affiliate_reward_bps": 500
}

1.3 获取已领取金额

GET /referral/on-chain/claimed/:address

响应

{
"address": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266",
"claimed_usd": "150.50"
}

2. 推荐码管理 (需要认证)

2.1 创建推荐码

POST /referral/codes
Content-Type: application/json
Authorization: Bearer <jwt_token>

{
"timestamp": 1703577600,
"signature": "0x..."
}

EIP-712 签名结构

const types = {
CreateReferralCode: [
{ name: "wallet", type: "address" },
{ name: "timestamp", type: "uint256" }
]
};

响应

{
"success": true,
"code": "A1B2C3",
"created_at": 1703577600000
}

2.2 绑定推荐码

POST /referral/bind
Content-Type: application/json
Authorization: Bearer <jwt_token>

{
"code": "ALICE2024",
"timestamp": 1703577600,
"signature": "0x..."
}

EIP-712 签名结构

const types = {
BindReferralCode: [
{ name: "wallet", type: "address" },
{ name: "code", type: "string" },
{ name: "timestamp", type: "uint256" }
]
};

2.3 获取推荐仪表板

GET /referral/dashboard
Authorization: Bearer <jwt_token>

响应

{
"code": "A1B2C3",
"total_referrals": 25,
"active_referrals": 18,
"total_earnings": "1250.50",
"pending_earnings": "150.00",
"claimed_earnings": "1100.50",
"tier": {
"level": 2,
"name": "Gold",
"commission_rate": "0.15",
"next_tier_requirement": 50
},
"recent_activity": [
{
"referral_address": "0x1234...",
"event_type": "trade",
"volume": "10000.00",
"commission": "15.00",
"timestamp": 1703577600000
}
]
}

3. 链上领取返佣

3.1 获取领取签名

POST /referral/on-chain/claim-signature
Content-Type: application/json
Authorization: Bearer <jwt_token>

{
"amount": "100.50"
}

响应

{
"amount": "100500000",
"nonce": 0,
"deadline": 1766726997,
"signature": "0x38f1fcf0e7a31bee39a0e941a70f7fec6b6352fc...",
"contract_address": "0xaF486e11c824389E4Ab3ced7608ac3Bd43c176B8"
}

3.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);
return await tx.wait();
}

3.3 完整 claimRebate 流程

# Step 1: 获取 Nonce 并登录
curl -s "http://localhost:8080/api/v1/auth/nonce/0x85bfdfee..."

# Step 2: 获取 Claim Signature
curl -X POST "http://localhost:8080/api/v1/referral/on-chain/claim-signature" \
-H "Authorization: Bearer eyJ..." \
-d '{"amount": "10.0"}'

# Step 3: 调用链上 claimRebate
cast send --rpc-url "https://sepolia-rollup.arbitrum.io/rpc" \
--private-key "0x..." \
"0xaF486e11c824389E4Ab3ced7608ac3Bd43c176B8" \
"claimRebate(uint256,uint256,bytes)" \
"10000000" "1766729875" "0x0eec1999..."

常见错误及解决方案

错误原因解决方案
InvalidSignature()backendSigner 不匹配更新合约 backendSigner
SafeERC20: low-level call failed合约 USDT 余额不足向合约转入 USDT
insufficient funds用户 ETH 不足确保用户有 ETH 支付 Gas
DeadlineExceeded()签名已过期重新获取 claim signature
InvalidNonce()Nonce 不匹配检查链上 nonce

4. 合约直接交互

4.1 注册推荐码 (链上)

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);
const codeBytes32 = ethers.encodeBytes32String(codeString);

const tx = await contract.registerCode(codeBytes32);
await tx.wait();
}

4.2 充值时绑定推荐码

async function depositWithReferral(
signer: ethers.Signer,
amountUsdt: string,
referralCode: string
) {
const vault = new ethers.Contract(VAULT, VAULT_ABI, signer);
const amount = ethers.parseUnits(amountUsdt, 6);

const codeBytes32 = referralCode
? ethers.encodeBytes32String(referralCode)
: ethers.ZeroHash;

const tx = await vault.deposit(amount, codeBytes32);
await tx.wait();
}

5. 层级系统

层级名称总返佣交易者折扣推广者奖励
0Bronze10%5%5%
1Silver12%5%7%
2Gold15%5%10%
3Platinum18%6%12%
4Diamond20%6%14%

6. 错误码

错误码说明
INVALID_ADDRESS无效的钱包地址格式
CHAIN_ERROR链上调用失败
CODE_EXISTS推荐码已存在
ALREADY_BOUND用户已绑定推荐码
INVALID_CODE无效的推荐码
SIGNATURE_INVALID签名验证失败
TIMESTAMP_EXPIRED时间戳过期 (5分钟内有效)

7. 完整示例

React Hook 示例

import { useState, useEffect } from 'react';
import { useAccount } from 'wagmi';

const API_BASE = 'https://api.axblade.io/api/v1';

export function useReferral() {
const { address } = useAccount();
const [rebateInfo, setRebateInfo] = useState(null);
const [loading, setLoading] = useState(false);

const fetchRebateInfo = async () => {
if (!address) return;
setLoading(true);
try {
const res = await fetch(
`${API_BASE}/referral/on-chain/user-rebate/${address}`
);
const data = await res.json();
setRebateInfo(data);
} finally {
setLoading(false);
}
};

useEffect(() => {
fetchRebateInfo();
}, [address]);

return { rebateInfo, loading, refetch: fetchRebateInfo };
}

8. 事件监听

ReferralRebate 事件

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

9. 安全注意事项

  1. 签名有效期: 所有 EIP-712 签名的 timestamp 必须在 5 分钟内
  2. Nonce 管理: 每次领取返佣后 nonce 自动递增,防止重放攻击
  3. 金额验证: 后端会验证领取金额与待领取金额是否匹配
  4. 推荐码唯一性: 每个推荐码只能被一个地址注册
  5. 单次绑定: 用户只能绑定一次推荐码,绑定后不可更改