open-im-server/cmd/openim-rpc/openim-rpc-redpacket/redpacket-web3-integration-design.md
2026-04-30 17:54:22 +08:00

431 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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. 总体架构
```mermaid
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``TRON`
- `packet_id`: 链上红包 ID
- `chain_id`: 链 ID
- `contract_address`: 合约地址
- `creator_user_id`: OpenIM 发红包用户 ID
- `creator_wallet`: 发红包钱包地址
- `group_id`: 群红包所属群
- `scope_type`: `GROUP``DIRECT``PUBLIC`
- `receiver_user_id` / `receiver_user_ids`: 转账红包目标用户
- `packet_type`: `0` 固定、`1` 拼手气、`2` 转账
- `token`: token 地址
- `total_amount` / `total_shares`: 总金额与总份数
- `claimed_amount` / `claimed_shares`: 已领取进度
- `expiry_at`: 过期时间
- `tx_hash`: 创建交易 hash
- `status`: `PENDING``ACTIVE``COMPLETED``REFUNDED`
### 4.2 领取授权
collection: `red_packet_claim_auth`
保存每次签名发放:
- `packet_id`
- `claimer`
- `auth_nonce`
- `random_seed`
- `deadline`
- `signature`
- `used`
- `created_at`
`auth_nonce` 建唯一索引,用于防止重复授权 nonce。
### 4.3 领取记录
collection: `red_packet_claim`
保存链上领取回写结果:
- `packet_id`
- `user_id`
- `claimer_wallet`
- `auth_nonce`
- `claim_tx_hash`
- `claimed_amount`
- `block_number`
- `status`
重复领取判断同时检查:
- `packet_id + user_id`
- `packet_id + claimer_wallet`
### 4.4 钱包绑定
collection:
- `wallet_binding_challenge`
- `wallet_binding`
绑定流程先保存 challenge验签通过后 upsert active binding。领取签名前必须存在 `ACTIVE` 绑定。
## 5. 创建红包流程
```mermaid
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_id`
- `GROUP`: 群红包,必须传 `group_id`
- `DIRECT`: 指定用户红包,必须传 `receiver_user_id``receiver_user_ids`
## 6. 钱包绑定流程
```mermaid
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. 领取红包流程
```mermaid
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 签名字段:
- `packetId`
- `claimer`
- `authNonce`
- `randomSeed`
- `deadline`
前端必须原样把后端返回的参数传给合约 `claim(...)`。任一字段变化都会导致验签失败。
## 8. 管理配置流程
管理员接口位于:
```text
/redpacket/admin/*
```
当前对外接口:
- `set_signer`
- `set_token`
- `set_expiry`
- `set_allow_all_tokens`
- `set_native_token_enabled`
- `parse_tx_events`
设计分权:
- owner / 多签:最高权限
- config admin低频参数配置
- signer高频 claim 授权签名
当前实现边界:
- EVM 管理接口是 mock只返回成功 message
- TRON 管理接口会尝试通过 FullNode 发交易
- API 层未做独立管理员角色校验,生产必须补齐
## 9. 事件与最终一致性
核心事件:
- `PacketCreated`: 创建成功,获得链上 `packetId`
- `PacketClaimed`: 领取成功,获得真实领取金额
- `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`: 钱包绑定 challenge
- `POST /redpacket/wallet_bind/confirm`: 钱包绑定确认
- `POST /redpacket/wallet_bind/detail`: 查询当前用户的钱包绑定
管理员侧:
- `POST /redpacket/admin/set_signer`
- `POST /redpacket/admin/set_token`
- `POST /redpacket/admin/set_expiry`
- `POST /redpacket/admin/set_allow_all_tokens`
- `POST /redpacket/admin/set_native_token_enabled`
- `POST /redpacket/admin/parse_tx_events`
## 11. 前端接入建议
创建页:
1. 用户选择红包类型、金额、份数、过期时间和链
2. 调用 `create_order`
3. 钱包发起链上创建交易
4. 从 receipt 解析 `PacketCreated.packetId`
5. 调用 `created_callback`
6. 展示分享页或详情页
领取页:
1. 查询 `detail`
2. 检查当前钱包是否已绑定
3. 未绑定则先走 wallet bind
4. 调用 `issue_claim_sign`
5. 钱包发起 `claim(...)`
6. 调用 `claim_result`
7. 刷新 `detail`
钱包绑定页:
1. 获取当前钱包地址和 chain type
2. 调用 `wallet_bind/challenge`
3.`sign_method` 调钱包签名
4. 调用 `wallet_bind/confirm`
5. 调用 `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 网关能发现 `redPacket` RPC 服务
- MongoDB 索引创建成功
- signer 地址与合约 signer 一致
- EVM RPC 能稳定获取 receipt
- claim 签名在测试链可通过合约验签
- 钱包绑定 recover 地址与实际钱包一致
## 13. 总结
当前 RedPacket 的核心链路是:
```text
OpenIM 登录身份
-> 钱包绑定
-> 业务鉴权
-> 后端 signer 裸签 claim digest
-> 前端钱包发 claim 交易
-> 链上事件回写 MongoDB
```
这条链路把“谁是 OpenIM 用户”“谁控制钱包”“谁有资格领取”“链上是否最终成功”分成四层校验,后端只签发授权,不直接替用户领取,从而保持用户资产操作仍由钱包确认。