mcpField
E
example-leaderboard-dapp

example-leaderboard-dapp

github.com/kali-decoder开发18121 次安装1 天前更新
代码仓库

关于 example-leaderboard-dapp

面向 Midnight Network 开发者的隐私排行榜 DApp 技能,生成包含 Compact 合约和 Next.js 界面的项目。它支持匿名或自定义展示分数,并通过零知识证明验证条目归属。

主要功能

  1. 01生成排行榜合约与 Next.js 界面
  2. 02支持匿名、公开和自定义名称
  3. 03提交分数并读取链上状态
  4. 04通过零知识证明验证归属
  5. 05无需连接钱包即可查看排行榜

适用场景

  1. 01构建隐私保护的游戏排行榜
  2. 02提交分数并选择展示身份
  3. 03验证参赛者对条目的所有权
  4. 04允许访客查看排行榜

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/kali-decoder/midnight-skills --skill example-leaderboard-dapp

安装后在 Claude Code 中输入/example-leaderboard-dapp确认已加载。

详细介绍

Midnight Network 排行榜 DApp

一个保护隐私的排行榜,玩家可在链上提交分数,并选择三种显示模式;玩家还可使用 verifyOwnership 证明自己拥有某个条目——这是一个 ZK 电路,可检查 ownerCommitment(secretKey) 是否与存储的 ownerHash 匹配,而不会泄露秘密。

可运行模板: 复制 templates/leaderboard-dapp/,即可获得完整的 Next.js 项目(合约 + UI)。安装 1AM wallet 后,运行 npm install && npm run compact && npm run sync:assets && npm run dev。

此技能会生成:

  • contract/ — Compact 排行榜 + TypeScript witnesses + 编译脚本
  • app/leaderboard/ — Next.js 客户端 UI(点击游戏、隐私模式选择器、排行榜表格)
  • lib/midnight.ts — 钱包会话 + 已修补的索引器 provider(复制自 references/midnight-session.md 或 templates/leaderboard-dapp/lib/midnight.ts)
  • lib/leaderboard.ts — 部署、submitScore、verifyOwnership、账本解码
  • lib/display-name.ts — 将匿名哈希字节解码为生成的名称(“Crimson Tiger”)
  • public/zk/leaderboard/ — 从合约构建同步的 ZK 证明资源

共享参考资料(规范 provider + 故障排查——请勿在提示词中重复):

  • references/midnight-session.md — createConnectedSession、索引器修补、部署/调用辅助函数
  • references/gotchas.md — preprod 部署卡住、GraphQL offset: null、ZK 资源路径
  • references/versions.json — 固定的 @midnight-ntwrk/* 版本

主要参考资料:

  • example-locker-dapp/ / templates/locker-dapp/ — Next.js + 1AM 模式、底层部署/调用
  • example-payment-dapp/ — provider 配置、索引器轮询
  • compact/ — disclose()、witnesses、persistentHash、Map、Counter、assert
  • security/ — 链上公开数据与 witness 数据中的私密数据
  • indexer/ — 无需连接钱包即可读取合约状态

关键架构说明:

  • scores 是公开的 Map<Uint<64>, ScoreEntry> — 任何人都能通过索引器读取
  • localSecretKey witness 会从私有状态返回一个 32 字节的秘密;绝不会在链上公开
  • ownerCommitment(sk) 使用带有域分隔符 "leaderboard:owner:" 的 persistentHash
  • 布尔值 useCustomName 用于选择由 witness 提供的名称,或基于哈希的匿名显示名称
  • verifyOwnership 是仅用于证明的电路——不会写入账本;可用于“证明这是我的分数”
  • 将秘密密钥保存在 localStorage 中,以便在页面刷新后仍可进行所有权证明
  • 使用 createUnprovenDeployTx + submitTxAsync,不要使用 deployContract()(在 preprod 上会卡住)
  • 使用已修补的 queryContractState 封装 indexerPublicDataProvider(这是 GraphQL offset: null 的 bug)
  • 排行榜表格无需连接钱包即可从索引器加载——只有提交/验证需要连接

工作流

帮助用户时,请按以下顺序操作:

  1. 合约 — 编译 leaderboard.compact + witnesses(localSecretKey、getCustomName)
  2. Providers — createConnectedSession(来自 references/midnight-session.md)
  3. 部署 — 底层部署,持久化私有状态 + 合约地址
  4. 读取状态 — 索引器 GraphQL → ContractState.deserialize → ledger() → 解码条目
  5. 提交分数 — submitScore(score, useCustomName),可选择事先调用 setCustomName
  6. 验证所有权 — 使用 verifyOwnership(entryId) 领取奖品或显示“你的”徽章
  7. UI — 点击游戏、隐私模式选择器、带证明按钮的排行榜表格

1) 项目结构

leaderboard-dapp/
├── package.json
├── next.config.mjs
├── lib/
│   ├── isomorphic-ws-fix.mjs
│   ├── midnight.ts                 # session, patched provider, hex helpers
│   ├── leaderboard.ts              # deploy, submitScore, verifyOwnership, decode
│   └── display-name.ts             # anonymous name generator
├── app/
│   ├── layout.tsx
│   └── leaderboard/
│       └── LeaderboardClient.tsx   # game + wallet + leaderboard UI
├── contract/
│   ├── package.json
│   └── src/
│       ├── leaderboard.compact
│       ├── witnesses.ts
│       ├── index.ts
│       └── managed/leaderboard/    # compiler output (gitignored)
├── scripts/
│   └── sync-zk-assets.mjs          # → public/zk/leaderboard/
└── public/zk/leaderboard/          # keys + zkir (gitignored until sync)

2) Compact 合约

contract/src/leaderboard.compact:

struct ScoreEntry {
  score: Uint<64>,
  displayName: Bytes<32>,
  ownerHash: Bytes<32>
}

export ledger scores: Map<Uint<64>, ScoreEntry>;
export ledger nextId: Counter;

witness localSecretKey(): Bytes<32>;
witness getCustomName(): Bytes<32>;

export circuit ownerCommitment(sk: Bytes<32>): Bytes<32> {
  return persistentHash<Vector<2, Bytes<32>>>([pad(32, "leaderboard:owner:"), sk]);
}

export circuit submitScore(score: Uint<64>, useCustomName: Boolean): [] { /* ... */ }
export circuit verifyOwnership(targetEntryId: Uint<64>): [] { /* ... */ }

隐私设计:

  • 匿名模式(useCustomName = false):displayName = persistentHash(sk) — UI 会将其解码为生成的名称
  • 公开 / 自定义模式(useCustomName = true):displayName = getCustomName() witness — 应用会传入地址或用户名
  • 所有权:每个条目都会存储 ownerHash = ownerCommitment(sk);verifyOwnership 会重新推导并进行比对

编译:

cd contract && npm run compact && cd ..
npm run sync:assets

3) 见证者

contract/src/witnesses.ts:

export type LeaderboardPrivateState = { secretKey: Uint8Array };

export const witnesses = {
  localSecretKey: (ctx) => [ctx.privateState, ctx.privateState.secretKey] as const,
  getCustomName: (ctx) => [ctx.privateState, customName] as const,
};

export const setCustomName = (name: string) => { /* encode to Bytes<32> */ };

使用公开或自定义显示模式时,请在调用 submitScore 之前于 TypeScript 中调用 setCustomName(name)。


4) TypeScript 集成

lib/leaderboard.ts 遵循 locker-dapp 模式:

函数用途
getOrCreateSecretKey()在 localStorage 中持久化 32 字节密钥
deployLeaderboard(session)createUnprovenDeployTx + submitTxAsync
submitScore(session, addr, score, customName?)submitCallTxAsync → submitScore 电路
verifyOwnership(session, addr, entryId)submitCallTxAsync → verifyOwnership 电路
fetchLeaderboardState(queryUrl, addr)轮询索引器 + decodeLeaderboardState

ZK 资源路径:/zk/leaderboard(同步至 public/zk/leaderboard/)。


5) 浏览器 UI

LeaderboardClient.tsx 流程:

  1. 连接 — detectWallet() → wallet.connect('preprod') → createConnectedSession(api, ZK_PATH)
  2. 部署 / 加入 — 部署新合约或粘贴现有的 64 字符十六进制地址
  3. 游戏 — 10 秒点击挑战
  4. 提交 — 选择匿名 / 公开 / 自定义,然后调用 submitScore
  5. 排行榜 — 每 15 秒从索引器自动刷新(读取无需钱包)
  6. 证明 — verifyOwnership(entryId) 在 UI 中将条目标记为你的条目

仅从索引器读取意味着观众无需连接钱包即可查看排行榜。


6) 前置条件

组件版本
Compact 编译器0.31.0
Compact 运行时0.16.0
Ledger8.0.3
midnight-js4.0.4
证明服务8.0.3
docker run -d -p 6300:6300 midnightntwrk/proof-server:8.0.3 -- \
  midnight-proof-server --network preprod

钱包:在 Preprod 上使用 1AM 扩展程序,证明服务为 http://localhost:6300,并从水龙头获取 tNIGHT + tDUST。


7) 兼容性矩阵

从 references/versions.json 固定版本。升级前请对照 docs.midnight.network 支持矩阵进行检查。


8) 生产环境说明

  • 将前端部署到 Vercel/Netlify;在构建步骤中设置 public/zk/leaderboard 资源(npm run sync:assets)
  • 在环境变量或 localStorage 中存储默认合约地址,方便回访玩家使用
  • verifyOwnership 不会修改账本 — 可安全用于重复的“证明这是我的”交互
  • 对于主网,请通过钱包的 getConfiguration() 更新网络 ID、索引器 URL 和证明服务配置

快速命令

cd templates/leaderboard-dapp
npm install
npm run compact
npm run sync:assets
npm run dev

打开 http://localhost:3000 → 连接 1AM → 部署新合约 → 开始游戏 → 提交 → 刷新排行榜。

评论

支持 Markdown