FHERPG — Privacy‑Preserving On‑Chain Quiz Game with Zama FHE
Overview
- FHERPG is a minimal, production‑minded game where an admin creates multiple‑choice tasks (2–4 options). Exactly one option is correct and stored as an encrypted value using Zama’s FHEVM. Players submit encrypted answers; if correct, the contract updates their encrypted score. Correctness and scoring are computed privately without revealing the correct answer or user scores on‑chain.
- The dApp runs on the Sepolia testnet. The smart contracts enforce admin‑only task management, private answer checking, and encrypted scorekeeping. The frontend connects to Sepolia only and never relies on a local blockchain.
Why FHE for Games
- Preserve secrets on‑chain: The correct answer is never revealed in plaintext to the chain, reducing spoilers, front‑running, and oracle‑leak risks.
- Private player data: Scores remain encrypted; players can opt‑in to client‑side re‑encryption and viewing via the Zama Relayer SDK.
- Verifiable yet private logic: Everyone verifies the same contract logic on‑chain while inputs/outputs remain confidential under FHE.
- Simple UX: Players use familiar wallets; encryption/decryption flows are handled under the hood with concise UI cues.
Core Features
- Admin task creation: Name, description, 2–4 options, 1 encrypted correct answer, reward points.
- Private answer submission: Players submit an encrypted choice; the contract compares it privately with the encrypted correct answer.
- Encrypted scoring: Rewards are added to an encrypted score. Players can request user decryption to view their score client‑side.
- Task lifecycle: Admin can deactivate tasks; users see only active tasks.
- Clean separation: Contract write operations use ethers; reads use viem. The frontend imports no JSON files directly and avoids localStorage.
Architecture Overview
- Smart contracts (Solidity, FHEVM):
contracts/FHERPGGame.solstores tasks, correct answer (encrypted), player completion flags, and encrypted scores; provides view methods that do not rely onmsg.sender. - Hardhat environment: Compile, test (mock FHE locally), deploy to Sepolia, and verify. Includes hardhat‑deploy and TypeChain.
- Zama FHE stack: Uses
@fhevm/soliditytypes and operations for encrypted values,@zama-fhe/relayer-sdkto encrypt inputs client‑side and request user decryption. - Frontend (React + Vite): Wallet with RainbowKit/Wagmi; read via viem; write via ethers. Connects to Sepolia only; uses cookie storage to avoid localStorage. ABI is generated from on‑chain deployments.
Tech Stack
- Contracts and tooling: Solidity 0.8.24, Hardhat, hardhat‑deploy, hardhat‑gas‑reporter, TypeChain, Ethers v6, Viem, Mocha/Chai.
- Zama FHE:
@fhevm/solidity,@fhevm/hardhat-plugin(local mock testing),@zama-fhe/relayer-sdk(frontend encryption + user decrypt flows). - Frontend: React, Vite, TypeScript, Wagmi, RainbowKit. No Tailwind. No JSON imports for ABI. No localStorage (cookie storage is used).
- Package manager: npm.
Repository Structure
contracts/— Solidity contracts (e.g.,contracts/FHERPGGame.sol).deploy/— Hardhat‑deploy scripts (e.g.,deploy/deployGame.ts).tasks/— Hardhat tasks for deploy, create task, submit answer, etc.test/— Contract tests (FHE mock compatible). Skips on real testnets.deployments/sepolia/— Network deployments, including canonical ABI and contract address.game/— Frontend app (React + Vite). Reads via viem, writes via ethers, RainbowKit wallet.docs/— Zama FHE reference materials used during development (for convenience).
Contract: FHERPGGame
- Encrypted types: Uses
euint8for correct answer,euint32for scores; equality and arithmetic via FHE ops. - Views avoid
msg.sender:getTask,getPlayerScore(address),hasPlayerCompleted(address, taskId),isTaskActive(taskId),getActiveTasksCount(). - Admin‑only:
createTask,deactivateTask,changeAdmin. Constructor setsadminto deployer. - Events:
TaskCreated,TaskCompleted,ScoreUpdated. - ACL pattern: New ciphertexts are allowed for the contract and the relevant user via
FHE.allow/FHE.allowThis.
Prerequisites
- Node.js 20+ and npm 7+.
- Sepolia RPC access (e.g., Infura) and a funded deployer wallet.
- Environment variables in a root‑level
.env(see.env.example).MNEMONICorPRIVATE_KEY— deployer credentials (Sepolia funded).INFURA_API_KEY— for Sepolia RPC.ETHERSCAN_API_KEY— optional, for verification.
Install, Build, Test
- Install:
npm ci - Compile:
npm run compile - Lint:
npm run lint - Test (local FHE mock):
npm test- The FHE tests skip on real testnets. Use the mock environment provided by
@fhevm/hardhat-plugin.
- The FHE tests skip on real testnets. Use the mock environment provided by
Deploy to Sepolia
- Configure
.envwithPRIVATE_KEYorMNEMONICandINFURA_API_KEY. - Deploy:
npm run deploy:sepolia - Result: The canonical ABI and address are written to
deployments/sepolia/FHERPGGame.json.
Frontend Integration
- ABI source of truth: Always use
deployments/sepolia/FHERPGGame.json.- Generate a typed ABI module for the frontend:
npm run game:abi. - This writes
game/src/abi.tswithFHERPGGameAbiandFHERPGGameAddressexported.
- Generate a typed ABI module for the frontend:
- WalletConnect project ID: Update
projectIdingame/src/config/wagmi.ts:8to your own ID. - Run the frontend locally (connects to Sepolia, not a local chain):
npm run game:dev- The dev server runs on localhost, but chain traffic targets Sepolia only. The app does not use
localStorage.
- The dev server runs on localhost, but chain traffic targets Sepolia only. The app does not use
Using the App
- Admin flow
- Connect a wallet that is the contract
admin. - Open the Admin tab, fill name, description, 2–4 options, choose the correct one, set reward.
- The app encrypts the correct answer client‑side with the Zama Relayer SDK and submits a transaction via ethers.
- Connect a wallet that is the contract
- Player flow
- Connect a wallet on Sepolia.
- See the active tasks list (read via viem).
- Select a task, pick an option, and submit. The app encrypts your answer and writes via ethers.
- View your encrypted score handle; optionally request user decryption to view your score client‑side.
Hardhat Tasks (Cheatsheet)
- Deploy:
npx hardhat fherpg:deploy --network sepolia - Create task:
npx hardhat fherpg:create-task --address <contract> --name "Question" --description "Explain..." --options "A,B,C" --correct 1 --reward 25 --network sepolia - Get task:
npx hardhat fherpg:get-task --address <contract> --id 0 --network sepolia - Submit answer:
npx hardhat fherpg:submit-answer --address <contract> --taskid 0 --answer 1 --network sepolia - Get score (encrypted handle):
npx hardhat fherpg:get-score --address <contract> --player <0x...> --network sepolia - Get contract info:
npx hardhat fherpg:get-contract-info --address <contract> --network sepolia
Security and Privacy Model
- Private correctness: Correct answer is stored as
euint8and never revealed in plaintext on‑chain. - Encrypted scoring: Scores are
euint32. Only user‑driven decryption flows reveal values client‑side. - Access control: Admin‑only for task lifecycle. Ciphertexts are allowed to the contract and relevant user via
FHE.allow. - View methods: Do not rely on
msg.senderand accept explicit parameters, preventing implicit address usage in views. - Frontend constraints honored: No Tailwind; no JSON imports for ABI; Sepolia chain only; no localStorage (cookie storage is used).
Known Limitations
- On‑chain decryption is not possible; user decryption requires the Relayer SDK flow and user signature.
- Gas cost depends on FHE operations and task list size; task enumeration is O(n) across active tasks.
- Frontend requires a working WalletConnect Project ID and network access to Sepolia.
Roadmap
- Indexing and caching
- The Graph or custom indexer for efficient task discovery and history.
- Gameplay upgrades
- Time‑limited tasks, categories, difficulty levels, dynamic rewards, streak bonuses.
- Governance and roles
- Multi‑admin or RBAC, pausing/emergency controls, allowlists for creators.
- UX enhancements
- Notifications, history views, richer decryption status, mobile‑first polish.
- Multi‑network support
- Expand beyond Sepolia once compatible FHEVM infrastructure is available.
- Audits and hardening
- Formalize ACL reviews, fuzzing, property tests, and gas optimization passes.
Troubleshooting
- ABI/address mismatch
- Re‑deploy (
npm run deploy:sepolia) and regenerate frontend ABI (npm run game:abi).
- Re‑deploy (
- WalletConnect issues
- Ensure
game/src/config/wagmi.ts:8has a validprojectIdand that your wallet supports Sepolia.
- Ensure
- Tests skipped
- FHE tests skip on real testnets; they run on the local mock from
@fhevm/hardhat-plugin.
- FHE tests skip on real testnets; they run on the local mock from
License
- BSD‑3‑Clause‑Clear (see
LICENSE).