mirror of
https://github.com/openimsdk/open-im-server.git
synced 2026-07-07 21:03:20 +08:00
12 KiB
12 KiB
RedPacket Web3 接入设计文档
本文档描述红包系统在当前 OpenIM 架构中的 Web3 接入设计。内容以当前代码为准,覆盖前端、钱包、API 网关、RPC 服务、MongoDB、EVM/TRON 合约交互与事件回写。
1. 设计目标
业务目标:
- 支持固定红包、拼手气红包、待领取转账
- 支持 EVM 链红包创建、领取签名、事件解析
- 支持 TRON 链配置预留与部分管理交易能力
- 支持用户钱包绑定,领取前强制校验“OpenIM 用户 ID + 钱包地址”的绑定关系
- 通过 API 网关对外提供 HTTP 接口,内部保持标准 OpenIM gRPC 服务形态
安全目标:
- 钱包归属必须先绑定后领取
- claim 授权必须绑定
packetId + claimer + authNonce + randomSeed + deadline - 同一用户、同一钱包对同一红包都不能重复领取
- signer 私钥只用于 claim 授权,不用于合约配置
- 管理类交易与高频签名职责分离
工程目标:
- RPC 服务接入 OpenIM 的配置、服务发现、日志和 MongoDB 体系
- HTTP API 只做参数解析和 RPC 转发
- MongoDB 保存业务状态、签名授权、领取记录和钱包绑定关系
- 链上事件作为最终一致性的依据
2. 当前系统边界
已经实现:
openim-rpc-redpacket标准 RPC 入口/redpacket/*API 网关路由- MongoDB 存储模型和 DAO
- EVM claim digest 获取、裸签名、事件解析
- EVM 钱包绑定验签
- TRON 钱包绑定 challenge 生成
- TRON admin transaction 调用框架
- 创建回写、领取回写、详情查询
仍需补齐:
- EVM admin 写链当前是 mock
- TRON 钱包绑定签名验签未实现
- TRON 交易事件解析未完整实现
- refund API 当前未对外暴露,仅有退款模型与事件预留
- 管理接口未做独立管理员鉴权
- 自动 indexer loop 当前只是配置和代码结构预留,主要回写仍依赖 callback / parse
3. 总体架构
flowchart LR
User[OpenIM 用户] --> App[App / H5 / Web]
App --> Wallet[钱包]
App --> API[openim-api /redpacket]
API --> RPC[openim-rpc-redpacket]
RPC --> DB[(MongoDB)]
RPC --> EVM[EVM RPC Client]
RPC --> TRON[TRON FullNode Client]
Wallet --> Contract[RedPacket Contract]
EVM --> Contract
TRON --> Contract
模块职责:
- App/H5/Web:连接钱包、发起链上交易、调用后端接口、展示红包状态
- 钱包:签名交易、签名绑定 challenge、广播交易
- openim-api:解析 HTTP 请求、注入登录用户上下文、调用 gRPC client
- openim-rpc-redpacket:业务鉴权、签名、存储、链上 receipt 解析
- MongoDB:保存业务状态和审计数据
- RedPacket 合约:维护链上红包状态、验签、防重放、转账结算
- EVM/TRON client:链上读写、事件解析、管理交易预留
4. 核心数据模型
4.1 红包主记录
collection: red_packet
保存内容:
biz_id: 后端业务单号,唯一chain_type:EVM或TRONpacket_id: 链上红包 IDchain_id: 链 IDcontract_address: 合约地址creator_user_id: OpenIM 发红包用户 IDcreator_wallet: 发红包钱包地址group_id: 群红包所属群scope_type:GROUP、DIRECT、PUBLICreceiver_user_id/receiver_user_ids: 转账红包目标用户packet_type:0固定、1拼手气、2转账token: token 地址total_amount/total_shares: 总金额与总份数claimed_amount/claimed_shares: 已领取进度expiry_at: 过期时间tx_hash: 创建交易 hashstatus:PENDING、ACTIVE、COMPLETED、REFUNDED
4.2 领取授权
collection: red_packet_claim_auth
保存每次签名发放:
packet_idclaimerauth_noncerandom_seeddeadlinesignatureusedcreated_at
auth_nonce 建唯一索引,用于防止重复授权 nonce。
4.3 领取记录
collection: red_packet_claim
保存链上领取回写结果:
packet_iduser_idclaimer_walletauth_nonceclaim_tx_hashclaimed_amountblock_numberstatus
重复领取判断同时检查:
packet_id + user_idpacket_id + claimer_wallet
4.4 钱包绑定
collection:
wallet_binding_challengewallet_binding
绑定流程先保存 challenge,验签通过后 upsert active binding。领取签名前必须存在 ACTIVE 绑定。
5. 创建红包流程
sequenceDiagram
autonumber
participant App as App/H5
participant API as openim-api
participant RPC as redpacket RPC
participant DB as MongoDB
participant Wallet as Wallet
participant C as Contract
App->>API: POST /redpacket/create_order
API->>RPC: CreateOrder
RPC->>RPC: 校验登录用户和 scope
RPC->>DB: insert red_packet(PENDING)
RPC-->>App: biz_id
App->>Wallet: 发起 create transaction
Wallet->>C: createFixed/createRandom/createTransfer
C-->>Wallet: tx hash + receipt
App->>App: 解析 PacketCreated.packetId
App->>API: POST /redpacket/created_callback
API->>RPC: CreatedCallback
RPC->>C: 可选解析 receipt 并校验事件
RPC->>DB: update red_packet(ACTIVE)
RPC-->>App: ok
关键规则:
biz_id由后端生成,链上没有该字段packet_id的可信来源是PacketCreated- 业务单先落
PENDING,链上确认后更新为ACTIVE - 如果 EVM client 可用,后端会校验 receipt 事件与业务单参数是否一致
creator_user_id从 token 上下文获取,不能由前端传入
scope 规则:
PUBLIC: 公开红包,不要求group_idGROUP: 群红包,必须传group_idDIRECT: 指定用户红包,必须传receiver_user_id或receiver_user_ids
6. 钱包绑定流程
sequenceDiagram
autonumber
participant App as App/H5
participant Wallet as Wallet
participant API as openim-api
participant RPC as redpacket RPC
participant DB as MongoDB
App->>API: POST /redpacket/wallet_bind/challenge
API->>RPC: IssueWalletBindChallenge
RPC->>DB: insert challenge(PENDING)
RPC-->>App: message + sign_method
App->>Wallet: 对 message 签名
Wallet-->>App: signature
App->>API: POST /redpacket/wallet_bind/confirm
API->>RPC: ConfirmWalletBind
RPC->>RPC: 验签并 recover 钱包地址
RPC->>DB: challenge=VERIFIED, upsert binding(ACTIVE)
RPC-->>App: binding detail
EVM 绑定:
- 使用 SIWE 风格 message
sign_method=personal_sign- 后端使用 Ethereum Signed Message 前缀 recover 地址
- recover 地址必须等于 challenge 的
wallet_address
TRON 绑定:
- 当前仅生成 challenge
sign_method=signMessageV2- confirm 阶段尚未实现验签
安全边界:
- challenge 默认 10 分钟过期
- challenge 只能从
PENDING确认一次 - 领取签名前必须查询到 active binding
7. 领取红包流程
sequenceDiagram
autonumber
participant App as App/H5
participant API as openim-api
participant RPC as redpacket RPC
participant DB as MongoDB
participant C as Contract
participant Wallet as Wallet
App->>API: POST /redpacket/detail
API->>RPC: GetDetail
RPC->>DB: 查询红包和领取记录
RPC-->>App: detail
App->>API: POST /redpacket/issue_claim_sign
API->>RPC: IssueClaimSign
RPC->>DB: 校验红包、绑定、重复领取、scope
RPC->>C: getSignMessage(...)
RPC->>RPC: signer 私钥裸签名
RPC->>DB: insert claim_auth
RPC-->>App: authNonce + randomSeed + deadline + signature
App->>Wallet: claim(...)
Wallet->>C: claim transaction
C-->>Wallet: tx hash + receipt
App->>API: POST /redpacket/claim_result
API->>RPC: ClaimResult
RPC->>C: 可选解析 PacketClaimed
RPC->>DB: 保存 claim,更新领取进度
RPC-->>App: ok
领取前后端校验:
- 登录用户存在
- 红包存在
- 红包状态为
ACTIVE - 红包未过期
- 当前用户绑定了
claimer钱包 - 当前用户未领取
- 当前钱包未领取
- 群红包必须有关联群
- 转账红包必须匹配指定接收用户
claim 签名字段:
packetIdclaimerauthNoncerandomSeeddeadline
前端必须原样把后端返回的参数传给合约 claim(...)。任一字段变化都会导致验签失败。
8. 管理配置流程
管理员接口位于:
/redpacket/admin/*
当前对外接口:
set_signerset_tokenset_expiryset_allow_all_tokensset_native_token_enabledparse_tx_events
设计分权:
- owner / 多签:最高权限
- config admin:低频参数配置
- signer:高频 claim 授权签名
当前实现边界:
- EVM 管理接口是 mock,只返回成功 message
- TRON 管理接口会尝试通过 FullNode 发交易
- API 层未做独立管理员角色校验,生产必须补齐
9. 事件与最终一致性
核心事件:
PacketCreated: 创建成功,获得链上packetIdPacketClaimed: 领取成功,获得真实领取金额PacketRefunded: 退款成功,获得退款目标与金额
当前一致性策略:
- 创建阶段由
created_callback回写,并在 EVM client 可用时解析 receipt 校验 - 领取阶段由
claim_result先保存PENDING,能解析 receipt 时立即确认 - 后续 indexer 可基于
indexer.pollInterval扩展为后台轮询与补偿
幂等建议:
- 以
tx_hash做领取回写幂等 - 以
biz_id做创建业务单幂等 - 以
packet_id + user_id和packet_id + claimer_wallet做重复领取判断 - 事件重复消费时,只允许状态向前推进,不回退已确认状态
10. API 设计摘要
用户侧:
POST /redpacket/create_order: 创建业务单POST /redpacket/created_callback: 创建交易回写POST /redpacket/detail: 查询红包详情POST /redpacket/issue_claim_sign: 领取签名发放POST /redpacket/claim_result: 领取交易回写POST /redpacket/wallet_bind/challenge: 钱包绑定 challengePOST /redpacket/wallet_bind/confirm: 钱包绑定确认POST /redpacket/wallet_bind/detail: 查询当前用户的钱包绑定
管理员侧:
POST /redpacket/admin/set_signerPOST /redpacket/admin/set_tokenPOST /redpacket/admin/set_expiryPOST /redpacket/admin/set_allow_all_tokensPOST /redpacket/admin/set_native_token_enabledPOST /redpacket/admin/parse_tx_events
11. 前端接入建议
创建页:
- 用户选择红包类型、金额、份数、过期时间和链
- 调用
create_order - 钱包发起链上创建交易
- 从 receipt 解析
PacketCreated.packetId - 调用
created_callback - 展示分享页或详情页
领取页:
- 查询
detail - 检查当前钱包是否已绑定
- 未绑定则先走 wallet bind
- 调用
issue_claim_sign - 钱包发起
claim(...) - 调用
claim_result - 刷新
detail
钱包绑定页:
- 获取当前钱包地址和 chain type
- 调用
wallet_bind/challenge - 按
sign_method调钱包签名 - 调用
wallet_bind/confirm - 调用
wallet_bind/detail验证绑定状态
12. 风险与待办
必须尽快处理:
- 修复
protocol/redpacket/redpacket.proto与当前internal/api/internal/rpc使用的 protobuf 类型不一致问题 - 补充管理员接口的 OpenIM 管理员权限校验
- 移除或保护 placeholder signature 降级路径
- EVM admin 从 mock 改为真实交易或明确只允许前端钱包管理
按业务优先级处理:
- 补齐 TRON 绑定验签
- 补齐 TRON 事件解析
- 增加 refund HTTP/RPC 接口
- 增加后台 indexer loop 与事件补偿
- 增加管理员操作审计 collection
上线检查:
- API 网关能发现
redPacketRPC 服务 - MongoDB 索引创建成功
- signer 地址与合约 signer 一致
- EVM RPC 能稳定获取 receipt
- claim 签名在测试链可通过合约验签
- 钱包绑定 recover 地址与实际钱包一致
13. 总结
当前 RedPacket 的核心链路是:
OpenIM 登录身份
-> 钱包绑定
-> 业务鉴权
-> 后端 signer 裸签 claim digest
-> 前端钱包发 claim 交易
-> 链上事件回写 MongoDB
这条链路把“谁是 OpenIM 用户”“谁控制钱包”“谁有资格领取”“链上是否最终成功”分成四层校验,后端只签发授权,不直接替用户领取,从而保持用户资产操作仍由钱包确认。