技术方案 — 单合约 · 无 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 |
| 默认 provider | 0x6CC14824Ea2918f5De5C2f75A9Da968ad4BD6344 |
| 接口代际 | 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 测试计划、部署参数、与产品文档的偏离登记表。