理财服务设计文档 (Earn Service Design)
版本:v4.2 最后更新:2026-01-08
本文档详细描述 AXBlade 理财服务的完整后端实现方案,包含智能合约、数据库、API 和后台服务。
一、后端服务设计
1.1 目录结构
src/
├── services/earn/
│ ├── mod.rs # EarnService 主体 (~1050行)
│ ├── models.rs # 数据模型和类型
│ └── settlement.rs # 结算调度器
├── api/
│ ├── handlers/earn.rs # API 处理器
│ └── routes/mod.rs # 路由配置
└── main.rs # 服务初始化
1.2 EarnService 结构
pub struct EarnService {
pool: PgPool,
contract: Option<EarnContract<SignerMiddleware<Provider<Http>, LocalWallet>>>,
provider: Option<Arc<Provider<Http>>>,
signer: Option<LocalWallet>,
contract_address: String,
chain_id: u64,
}
1.3 核心方法
impl EarnService {
// 初始化
pub fn new(pool: PgPool) -> Self;
pub async fn with_contract(pool, rpc_url, contract_address, private_key, chain_id) -> Result<Self>;
// 产品查询 (公开)
pub async fn list_products(&self, status, page, page_size) -> Result<ProductListResponse>;
pub async fn get_product(&self, product_id: &str) -> Result<ProductDetail>;
pub async fn get_historical_performance(&self, limit: i32) -> Result<Vec<HistoricalPerformance>>;
// 用户申购 (需认证)
pub async fn get_user_subscriptions(&self, user_address: &str) -> Result<Vec<UserSubscriptionDetail>>;
pub async fn prepare_subscribe(&self, user_address, product_id, amount) -> Result<PrepareSubscribeResponse>;
// EIP-712 签名 (内部)
fn sign_subscribe(&self, user, product_id, amount, deadline) -> Result<String>;
// 管理操作 (需Admin)
pub async fn create_product(&self, req, creator_address, chain_product_id) -> Result<EarnProduct>;
pub async fn update_product_status(&self, product_id, new_status) -> Result<EarnProduct>;
pub async fn get_product_subscriptions(&self, product_id, query) -> Result<AdminSubscriptionListResponse>;
// 事件处理
pub async fn handle_subscribed_event(&self, event: SubscribedEvent) -> Result<()>;
pub async fn handle_settled_event(&self, event: SettledEvent) -> Result<()>;
pub async fn handle_claimed_event(&self, event: ClaimedEvent) -> Result<()>;
// 事件监听
pub async fn start_event_listener(self: Arc<Self>);
async fn poll_events(&self, from_block: u64) -> Result<u64>;
}
1.4 合约 ABI 绑定
abigen!(
EarnContract,
r#"[
function productCount() external view returns (uint256)
function createProduct(string name, uint256 annualRateBps, uint256 durationDays, uint256 totalQuota, uint256 minAmount, uint256 maxAmountPerUser, uint256 subscribeStartTime, uint256 subscribeEndTime) external returns (uint256)
function openSubscription(uint256 productId) external
function activateProduct(uint256 productId) external
function settleProduct(uint256 productId) external
function subscribe(uint256 productId, uint256 amount, uint256 deadline, bytes signature) external
function claim(uint256 productId) external
function emergencyClaim(uint256 productId) external
function getProductConfig(uint256 productId) external view returns (string name, uint256 annualRateBps, uint256 durationDays, uint256 periodRateBps, uint256 totalQuota, uint256 minAmount, uint256 maxAmountPerUser)
function getProductTiming(uint256 productId) external view returns (uint256 subscribeStartTime, uint256 subscribeEndTime, uint256 settleTime, uint256 actualSettleTime)
function getProductStats(uint256 productId) external view returns (uint256 subscribedAmount, uint256 totalInterestPaid, uint256 participantCount, uint8 status, address creator)
function getSubscription(uint256 productId, address user) external view returns (uint256 amount, uint256 expectedReturn, uint256 actualReturn, uint256 subscribedAt, bool claimed)
function balanceOf(address account, uint256 id) external view returns (uint256)
function domainSeparator() external view returns (bytes32)
event ProductCreated(uint256 indexed productId, string name, uint256 annualRateBps, uint256 durationDays, uint256 totalQuota)
event ProductStatusChanged(uint256 indexed productId, uint8 oldStatus, uint8 newStatus)
event Subscribed(uint256 indexed productId, address indexed user, uint256 amount, uint256 expectedReturn)
event ProductSettled(uint256 indexed productId, uint256 totalPrincipal, uint256 totalInterest)
event Claimed(uint256 indexed productId, address indexed user, uint256 principal, uint256 interest)
]"#
);
1.5 事件监听机制
- 轮询间隔: 12秒
- 批量扫描: 最多1000个区块
- 错误退避: 指数退避,最大5分钟
- 状态持久化:
block_sync_state表 (event_type = 'earn_events')
1.6 结算调度器
// settlement.rs
pub async fn start_settlement_scheduler(service: Arc<EarnService>) {
// 每分钟检查一次
// 1. 申购结束 → 调用 activateProduct
// 2. 到期时间到达 → 调用 settleProduct
}