技术方案 — 单合约 · 无 owner · 双账本
单合约无权限函数,全部参数 immutable;双模式准入(线上无许可 / 线下 issuer ECDSA 验签);链上集熵 keccak 链式累积;押金与奖池双账本分离核算。
Solidity ^0.8.28 + FoundryOpenZeppelin ECDSAPyth Entropy V2Next.js + wagmi + viem

总体架构

┌─────────────────────────┐       ┌──────────────────────────┐
│  前端 (Next.js + wagmi)  │       │  外部依赖                  │
│  /      参与者主页面      │       │  Pyth Entropy V2 (已验证)  │
│  /gather 观众集熵页       │       │  WalletConnect relay      │
│  /host  签发者工具页      │       └───────────┬──────────────┘
│  /create 创建活动(工厂)   │                   │ 异步回调
└───────────┬─────────────┘                   ▼
            │  交易 / 事件读取    ┌─────────────────────────────┐
            └───────────────────▶│  LotteryFactory + Lottery.sol │
                                │  (无 owner, 全 immutable)     │
                                └─────────────────────────────┘

合约状态机

Open ──draw()──▶ Drawing ──entropyCallback──▶ Drawn
                    │
                    └─超时(entropyTimeout)后可再次 draw()(重新缴费)

Open:    register() / submitEntropy() / fundPrizePool()
Drawing: fundPrizePool() 仍可注入(快照在回调时刻定格)
Drawn:   claimDeposit() / claimPrize();fundPrizePool() 拒绝

核心设计要点

双模式准入(ADR 0002)
issuer == 0 → 无许可注册;issuer ≠ 0 → EIP-191 验签,签名 keccak(participant ‖ address(this) ‖ expiry) 绑定合约地址防跨合约重放,expiry 防过期。
链上集熵(ADR 0003)
已注册观众 submitEntropy(e),熵根 = keccak(entropyRoot ‖ e) 链式累积;熵根非零时 draw 强制 userSeed == entropyRoot(现场模式语义)。
双账本不变式
合约余额 == 押金账本(totalDepositsRemaining)+ 奖池账本(prizePoolAvailable)+ 在途请求费。 押金永不分给 winner,奖池永不退还 sponsor,无交叉路径。
开奖与派奖
回调以随机数为种子做部分 Fisher-Yates 洗牌取前 N 名;派奖 = 开奖时刻奖池快照均分(÷ N, wei 级尾差滞留);实际中奖人数 = min(winnerCount, 参与人数)。

Pyth Entropy V2 集成(链上实测已验证)

入口(ERC-1967 代理)0x825c0390f379C631f3Cf11A82a37D20BddF93c07
默认 provider0x6CC14824Ea2918f5De5C2f75A9Da968ad4BD6344
接口代际V2(getFeeV2 / requestV2)
请求费实测≈ 0.128 MON(动态值,draw 时附 5% buffer)
回调entropyCallback(uint64, address, bytes32),SDK 基类自带来源鉴权
随机数 = 验证者熵 + 用户种子共同决定;洗牌确定性可复现,任何人可按同一随机数链下重算名单核验。

安全清单(摘要)

  • 重入:claimDeposit / claimPrize 加 ReentrancyGuard,pull 模式领取
  • 权限:无 owner、无 setter、无 withdraw;全部参数 immutable,部署即固定
  • 回调伪造:SDK IEntropyConsumer 基类保证仅接受 Entropy 合约回调
  • 签名重放:digest 绑定 address(this) + expiry;请求费返还 best-effort,回调永不 revert
  • 资金滞留:pull 模式无时限 claim;Drawn 后 fundPrizePool 拒绝追加

前端工程

  • 6 个入口页:首页(全流程单页)/ 抽奖现场(摇一摇产熵 + 实时熵流)/ 入场管理(本地签名 + 二维码)/ 创建活动(经工厂合约部署 + 链上活动列表)/ 产品设计 / 技术方案
  • 活动上下文:URL ?addr= 优先,回落 NEXT_PUBLIC_LOTTERY_ADDRESS
  • Monad 适配:eth_getLogs 100 块限制 → 集熵历史 95 块分块扫描 + localStorage 增量缓存;活动列表走工厂合约 view 读取(无事件扫描)
  • 钱包:injected(桌面)+ WalletConnect(现场观众手机扫码)
完整技术方案文档
https://github.com/wangzhenxi/monad-blitz/blob/main/docs/tech-design.md
含完整函数签名与 require 清单、Foundry 测试计划、部署参数、与产品文档的偏离登记表。