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

12 KiB
Raw Blame History

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: EVMTRON
  • packet_id: 链上红包 ID
  • chain_id: 链 ID
  • contract_address: 合约地址
  • creator_user_id: OpenIM 发红包用户 ID
  • creator_wallet: 发红包钱包地址
  • group_id: 群红包所属群
  • scope_type: GROUPDIRECTPUBLIC
  • 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: PENDINGACTIVECOMPLETEDREFUNDED

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. 创建红包流程

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_idreceiver_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 签名字段:

  • packetId
  • claimer
  • authNonce
  • randomSeed
  • deadline

前端必须原样把后端返回的参数传给合约 claim(...)。任一字段变化都会导致验签失败。

8. 管理配置流程

管理员接口位于:

/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_idpacket_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 的核心链路是:

OpenIM 登录身份
  -> 钱包绑定
  -> 业务鉴权
  -> 后端 signer 裸签 claim digest
  -> 前端钱包发 claim 交易
  -> 链上事件回写 MongoDB

这条链路把“谁是 OpenIM 用户”“谁控制钱包”“谁有资格领取”“链上是否最终成功”分成四层校验,后端只签发授权,不直接替用户领取,从而保持用户资产操作仍由钱包确认。