跳到主要内容

Earn 开发工作流

版本: 1.0 | 用于 Earn 服务开发测试


环境概览

服务器信息

环境域名IP用途
测试环境api.8a27.xyz47.129.237.210Earn 服务开发测试
生产环境api.renance.xyz13.212.6.186主网服务

合约地址 (Arbitrum Sepolia)

合约地址说明
AXBladeEarn v3.10xA40b4b726980C02F6558fcA5C0a52FaA2E5A0864当前使用
Platform USDT0x572E474C3Cf364D085760784F938A1Aa397a8B9b测试 USDT
Treasury0x6538469807e019E05c9ec4Bd158b12afB1DA50F3资金池地址

USDT 精度规范

⚠️ 关键规则: USDT 使用 6 位小数精度,所有金额参数必须使用原始值 (raw value)

实际金额原始值 (raw value)说明
1 USDT10000001 × 10^6
10 USDT1000000010 × 10^6
100 USDT100000000100 × 10^6
1,000 USDT10000000001000 × 10^6
10,000 USDT1000000000010000 × 10^6

示例 - 创建产品参数:

totalQuota=1000000000       # 1000 USDT (不是 1000!)
minAmount=10000000 # 10 USDT (不是 10!)
maxAmountPerUser=1000000000 # 1000 USDT

错误: totalQuota=1000 (这是 0.001 USDT) ✅ 正确: totalQuota=1000000000 (这是 1000 USDT)


本地开发工作流

项目结构

backend/
├── src/
│ └── services/earn/
│ ├── mod.rs # EarnService 主体
│ ├── models.rs # 数据模型
│ └── settlement.rs # 结算调度器
├── migrations/
│ └── 0018_earn_service.sql
└── docs/
├── EARN_SERVICE_DESIGN.md
└── EARN_WORKFLOW.md

开发流程

# 1. 进入项目目录
cd /path/to/AXBlade/backend/backend

# 2. 本地编译检查
cargo check

# 3. 本地测试
cargo test

# 4. 提交代码
git add .
git commit -m "feat(earn): 描述修改内容"
git push origin dev

服务器部署工作流

SSH 连接

# 使用 SSH 密钥连接
ssh -i /path/to/axblade-test-key.pem ubuntu@47.129.237.210

# 或使用 SSH config 别名
ssh axblade-test

部署流程

⚠️ 重要: 必须在服务器上编译!

# 1. SSH 登录服务器
ssh axblade-test

# 2. 进入源码目录
cd /opt/axblade/source

# 3. 拉取最新代码
git pull origin dev

# 4. 在服务器上编译 (约 3-5 分钟)
cargo build --release

# 5. 停止服务
sudo systemctl stop axblade-sepolia

# 6. 复制新二进制
cp target/release/ztdx-backend /opt/axblade/axblade-backend

# 7. 启动服务
sudo systemctl start axblade-sepolia

# 8. 验证服务状态
sudo systemctl status axblade-sepolia
curl http://localhost:8081/health

查看日志

# 实时日志
sudo journalctl -u axblade-sepolia -f

# 最近 100 行
sudo journalctl -u axblade-sepolia -n 100

# 搜索错误
sudo journalctl -u axblade-sepolia | grep -i error

智能合约操作

环境变量配置

export CONTRACT="0xA40b4b726980C02F6558fcA5C0a52FaA2E5A0864"
export USDT="0x572E474C3Cf364D085760784F938A1Aa397a8B9b"
export RPC="https://sepolia-rollup.arbitrum.io/rpc"
export DEPLOYER_KEY="0x..."

创建产品

# 获取区块时间
BLOCK_TIME=$(cast block latest --rpc-url $RPC | grep timestamp | awk '{print $2}')

# 计算时间
SUBSCRIBE_START=$((BLOCK_TIME + 60))
SUBSCRIBE_END=$((BLOCK_TIME + 600))

# 创建产品 (v3.1)
cast send $CONTRACT \
"createProduct(uint256,string,uint256,uint256,uint256,uint256,uint256,uint256,uint256)" \
2200 \ # productId
"Test Product - 500% APY" \ # name
50000 \ # maxAnnualRateBps (500%)
300 \ # durationSeconds (5分钟)
1000000000 \ # totalQuota: 1000 USDT
10000000 \ # minAmount: 10 USDT
1000000000 \ # maxAmountPerUser: 1000 USDT
$SUBSCRIBE_START \
$SUBSCRIBE_END \
--private-key $DEPLOYER_KEY \
--rpc-url $RPC

产品操作

# 开启申购
cast send $CONTRACT "openSubscription(uint256)" $PRODUCT_ID \
--private-key $DEPLOYER_KEY --rpc-url $RPC

# 激活产品
cast send $CONTRACT "activateProduct(uint256)" $PRODUCT_ID \
--private-key $DEPLOYER_KEY --rpc-url $RPC

# 取出本金
cast send $CONTRACT "withdrawPrincipal(uint256)" $PRODUCT_ID \
--private-key $DEPLOYER_KEY --rpc-url $RPC

# 存入返还
cast send $CONTRACT "depositReturns(uint256,uint256)" $PRODUCT_ID $ACTUAL_INTEREST \
--private-key $DEPLOYER_KEY --rpc-url $RPC

# 结算产品
cast send $CONTRACT "settleProduct(uint256)" $PRODUCT_ID \
--private-key $DEPLOYER_KEY --rpc-url $RPC

查询状态

# 产品状态
# 返回: (subscribedAmount, totalInterestPaid, participantCount, status)
# status: 0=Created, 1=Subscribing, 2=Active, 3=Settled, 4=Cancelled
cast call $CONTRACT "getProductStats(uint256)(uint256,uint256,uint256,uint8)" $PRODUCT_ID --rpc-url $RPC

产品生命周期

状态流转图

┌─────────────────────────────────────────────────────────────────┐
│ 产品生命周期 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ createProduct() openSubscription() activateProduct() │
│ ↓ ↓ ↓ │
│ [Created] ────────→ [Subscribing] ────────→ [Active] │
│ (0) (1) (2) │
│ │ │ │
│ 用户 subscribe() withdrawPrincipal() │
│ │ │
│ depositReturns() │
│ │ │
│ settleProduct() │
│ ↓ │
│ [Settled] │
│ (3) │
│ │ │
│ 用户 claim() │
│ │
└─────────────────────────────────────────────────────────────────┘

完整操作流程

步骤操作执行者前置条件
1createProduct()Admin-
2添加产品到数据库Admin步骤1完成
3openSubscription()Operatortimestamp >= subscribeStart
4用户 subscribe()User状态 = Subscribing
5activateProduct()Operatortimestamp >= subscribeEnd
6withdrawPrincipal() (可选)Operator状态 = Active
7depositReturns()OperatorprincipalWithdrawn = true
8settleProduct()Operatortimestamp >= settleTime
9用户 claim()User状态 = Settled

API 测试

公开端点

# 健康检查
curl https://api.8a27.xyz/health

# 产品列表
curl https://api.8a27.xyz/api/v1/earn/products | jq

# 产品详情
curl https://api.8a27.xyz/api/v1/earn/products/2110 | jq

# EIP-712 Domain
curl https://api.8a27.xyz/api/v1/earn/domain | jq

管理端点

ADMIN_KEY="your-admin-key"

# 创建产品 (数据库)
curl -X POST \
-H "X-API-Key: $ADMIN_KEY" \
-H "Content-Type: application/json" \
-d '{...}' \
"https://api.8a27.xyz/api/v1/admin/earn/products" | jq

常见错误

错误原因解决方案
金额显示 0.001 USDT未使用原始值参见 USDT 精度规范
"Not subscribing"链上状态不是 Subscribing调用 openSubscription()
"FailedInnerCall"Treasury USDT allowance 不足Treasury approve USDT
"Text file busy"服务运行时复制二进制先停止服务