CryptoCards is a blockchain-based NFT card battle game built on Ethereum Sepolia testnet, leveraging Zama's Fully Homomorphic Encryption (FHE) technology to create truly private and secure game mechanics. Battle monsters, collect encrypted soldier cards, and experience the first generation of privacy-preserving blockchain gaming where card attributes remain confidential on-chain.
CryptoCards reimagines traditional NFT gaming by introducing encrypted card attributes that only the owner can decrypt and view. This groundbreaking approach solves a fundamental problem in blockchain gaming: on-chain privacy. Unlike conventional NFT games where all attributes are publicly visible, CryptoCards uses Zama's FHEVM (Fully Homomorphic Encryption Virtual Machine) to keep card stats encrypted on the blockchain, making gameplay truly fair and strategic.
- 🔐 True Privacy: Card attributes (level & attack power) are encrypted using FHE and stored on-chain
- 👁️ Selective Disclosure: Only card owners can decrypt and view their card's true stats
- ⚔️ Fair Combat: Opponents cannot inspect your cards, creating genuine strategy and surprise
- 🎮 Immersive Gameplay: Battle monsters, earn encrypted loot, and collect powerful soldier cards
- 🛡️ Cryptographic Security: Built on Zama's cutting-edge FHE technology for unbreakable encryption
- Each card is a unique ERC721 token with two encrypted attributes:
- Level (LV): Rarity and progression indicator (1-10)
- Attack Power: Combat strength (50-349)
- Attributes are encrypted using Zama's FHE library and remain private on-chain
- Only the card owner can decrypt and view these stats using client-side decryption
- Dynamic monster generation with randomized attributes:
- HP: Health points (50-200)
- Defense: Protective rating (5-25)
- Types: Goblin, Skeleton, Orc, Slime, Bandit, Wolf
- Battle mechanics:
- Players attack monsters to earn card drops
- Victory grants encrypted loot (level + attack) minted as new NFT cards
- Pseudo-random loot generation ensures fair distribution
- Encrypted Minting: New cards are minted with encrypted stats that never expose plaintext values
- Secure Updates: Level-up and attack modifications maintain encryption throughout
- Access Control: FHE ACL (Access Control List) ensures only authorized users can decrypt
- Transfer Safety: Card transfers automatically update ACL permissions to new owners
- Battle Arena: Interactive monster combat with visual feedback
- My Cards: Personal card collection viewer with decryption functionality
- Wallet Integration: Seamless RainbowKit connection for multiple wallet providers
- Real-time Updates: Live transaction status and blockchain event monitoring
// Core Features:
- ERC721 standard with enumerable extension
- Zama FHE integration for encrypted attributes
- Encrypted level (euint32) and attack (euint32) storage
- Owner-only decryption permissions via ACL
- Secure transfer with automatic permission updatesKey Functions:
mintCard(inputLevel, inputAttack, inputProof): Mint new card with encrypted statsgetEncryptedLevel(tokenId): Retrieve encrypted level handlegetEncryptedAttack(tokenId): Retrieve encrypted attack handlelevelUp(tokenId): Increment card level (encrypted operation)updateAttack(tokenId, inputAttack, inputProof): Update attack powertokensOfOwner(owner): List all cards owned by address
- Demonstrates basic FHE operations (add, subtract)
- Example contract for understanding Zama FHE patterns
Technology Stack:
- Framework: React 19.1.1 with TypeScript
- Build Tool: Vite 7.1.6
- Web3 Libraries:
ethers@6.15.0(contract writes/transactions)viem@2.37.6(contract reads)wagmi@2.17.0(React hooks for Ethereum)
- Wallet: RainbowKit 2.2.8 (multi-wallet support)
- Encryption: Zama Relayer SDK 0.2.0 (FHE client operations)
Component Structure:
ui/src/
├── components/
│ ├── AttackMonster.tsx # Monster battle interface
│ ├── MyCards.tsx # Card collection viewer
│ ├── CardsApp.tsx # Main app container
│ └── Header.tsx # Navigation header
├── config/
│ ├── contracts.ts # Contract ABI & address
│ └── wagmi.ts # Wagmi/RainbowKit config
├── hooks/
│ ├── useZamaInstance.ts # FHE instance initialization
│ └── useEthersSigner.ts # Ethers v6 signer adapter
└── styles/ # CSS styling (no Tailwind)
- Network: Ethereum Sepolia Testnet (Chain ID: 11155111)
- Hardhat Framework: Contract development, testing & deployment
- Deployment Pipeline:
- Local testing on Hardhat network
- Deployment to Sepolia via Infura RPC
- Contract verification on Etherscan
- FHE Integration: Zama FHEVM plugin with Sepolia configuration
| Technology | Version | Purpose |
|---|---|---|
| Solidity | 0.8.27 | Smart contract language |
| Hardhat | 2.26.0 | Development framework |
| @fhevm/solidity | 0.8.0 | Zama FHE library |
| OpenZeppelin | 5.4.0 | ERC721 & security standards |
| @zama-fhe/oracle-solidity | 0.1.0 | FHE oracle integration |
| TypeChain | 8.3.2 | TypeScript contract bindings |
| Technology | Version | Purpose |
|---|---|---|
| React | 19.1.1 | UI framework |
| TypeScript | 5.8.3 | Type safety |
| Vite | 7.1.6 | Build tool & dev server |
| Ethers.js | 6.15.0 | Ethereum interactions (write) |
| Viem | 2.37.6 | Ethereum interactions (read) |
| Wagmi | 2.17.0 | React hooks for Ethereum |
| RainbowKit | 2.2.8 | Wallet connection UI |
| @zama-fhe/relayer-sdk | 0.2.0 | Client-side FHE operations |
| Technology | Version | Purpose |
|---|---|---|
| Mocha | 11.7.1 | Test framework |
| Chai | 4.5.0 | Assertion library |
| Hardhat Gas Reporter | 2.3.0 | Gas optimization |
| Solidity Coverage | 0.8.16 | Code coverage analysis |
| ESLint | 8.57.1 | Code linting |
| Prettier | 3.6.2 | Code formatting |
Ensure you have the following installed:
- Node.js: Version 20 or higher
- npm: Version 7.0.0 or higher
- Git: For cloning the repository
- Metamask: Or any Web3-compatible wallet
-
Clone the Repository
git clone https://github.com/yourusername/CryptoCards.git cd CryptoCards -
Install Root Dependencies
npm install
-
Install Frontend Dependencies
cd ui npm install cd ..
-
Configure Environment Variables
Create a
.envfile in the root directory:# Required for deployment PRIVATE_KEY=your_sepolia_wallet_private_key INFURA_API_KEY=your_infura_api_key # Optional for contract verification ETHERSCAN_API_KEY=your_etherscan_api_key
Security Warning: Never commit your
.envfile to version control!
npm run compileThis generates TypeScript bindings in the types/ directory and compiles contracts to artifacts/.
npm run testExecutes the test suite on a local Hardhat network with FHE support.
# Terminal 1: Start local node
npx hardhat node
# Terminal 2: Deploy contracts
npx hardhat deploy --network localhost# Deploy contracts
npm run deploy:sepolia
# Or use the full deployment script
npm run deploy:sepolia:fullThe deployment script will:
- Deploy
SoldierCardscontract to Sepolia - Save deployment info to
deployments/sepolia/ - Generate ABI for frontend integration
After deployment, copy the contract address and ABI:
# Contract address is in: deployments/sepolia/SoldierCards.json
# ABI is in: artifacts/contracts/SoldierCards.sol/SoldierCards.jsonUpdate ui/src/config/contracts.ts:
export const CONTRACT_ADDRESS = '0xYourDeployedContractAddress';
export const CONTRACT_ABI = [...]; // Copy ABI from artifactscd ui
npm run devThe application will be available at http://localhost:5173
cd ui
npm run buildProduction files will be output to ui/dist/.
-
Get Sepolia ETH:
- Visit Sepolia Faucet
- Request test ETH for your wallet
-
Connect Wallet:
- Open the app in your browser
- Click "Connect Wallet"
- Select Sepolia network in Metamask
-
Battle Monsters:
- Navigate to "Battle Arena"
- Click "Attack Monster"
- Sign the transaction to mint encrypted card
-
View Your Cards:
- Go to "My Cards"
- Click "Decrypt" to view encrypted attributes
- Sign decryption permission request
sequenceDiagram
participant User
participant Frontend
participant ZamaRelayer
participant Contract
User->>Frontend: Attack Monster (win)
Frontend->>Frontend: Generate loot (level, attack)
Frontend->>ZamaRelayer: Encrypt(level, attack)
ZamaRelayer-->>Frontend: encryptedHandles + proof
Frontend->>Contract: mintCard(handles, proof)
Contract->>Contract: FHE.fromExternal() - verify proof
Contract->>Contract: Store encrypted euint32 values
Contract->>Contract: Set ACL permissions for owner
Contract-->>Frontend: Transaction success
Frontend-->>User: Card minted!
sequenceDiagram
participant User
participant Frontend
participant ZamaRelayer
participant Contract
User->>Frontend: Click "Decrypt" on card
Frontend->>Frontend: Generate keypair
Frontend->>User: Request signature (EIP-712)
User-->>Frontend: Sign permission
Frontend->>ZamaRelayer: userDecrypt(handles, keypair, signature)
ZamaRelayer->>Contract: Verify ACL permissions
Contract-->>ZamaRelayer: Encrypted data
ZamaRelayer->>ZamaRelayer: Decrypt with user keypair
ZamaRelayer-->>Frontend: Plaintext values
Frontend-->>User: Display level & attack
- On-Chain Privacy: Card attributes are never exposed in plaintext on the blockchain
- Client-Side Decryption: Only the owner's browser can decrypt using signed permissions
- Cryptographic Proof: All encrypted inputs require zero-knowledge proofs for verification
- Access Control: FHE ACL ensures only authorized addresses can decrypt
- Transfer Safety: Permissions automatically update when cards are transferred
| Monster | HP Range | Defense Range | Emoji |
|---|---|---|---|
| Goblin | 50-200 | 5-25 | 👹 |
| Skeleton | 50-200 | 5-25 | 💀 |
| Orc | 50-200 | 5-25 | 🧌 |
| Slime | 50-200 | 5-25 | 🟢 |
| Bandit | 50-200 | 5-25 | 🏴☠️ |
| Wolf | 50-200 | 5-25 | 🐺 |
| Level | Rarity | Emoji | Color Theme |
|---|---|---|---|
| 8-10 | Legendary | 💎 | Purple/Gold |
| 6-7 | Epic | 🏆 | Magenta |
| 4-5 | Rare | ⭐ | Blue |
| 2-3 | Uncommon | 🛡️ | Green |
| 1 | Common | 🃏 | Gray |
- Level: Randomly generated (1-10) based on monster seed
- Attack: Randomly generated (50-349) based on monster seed
- All randomness is deterministic using PRNG with time-based seeding
CryptoCards/
├── contracts/ # Solidity smart contracts
│ ├── SoldierCards.sol # Main game contract
│ └── FHECounter.sol # FHE reference example
├── deploy/ # Deployment scripts
│ └── deploy.ts # Hardhat-deploy script
├── tasks/ # Hardhat custom tasks
│ ├── accounts.ts # Account management
│ ├── FHECounter.ts # Counter contract tasks
│ └── SoldierCards.ts # Card contract tasks
├── test/ # Contract test suites
│ ├── FHECounter.ts # Counter tests
│ └── SoldierCards.ts # Card contract tests
├── ui/ # Frontend application
│ ├── src/
│ │ ├── components/ # React components
│ │ ├── config/ # Contract config & Wagmi setup
│ │ ├── hooks/ # Custom React hooks
│ │ └── styles/ # CSS styling
│ ├── public/ # Static assets
│ └── dist/ # Production build output
├── artifacts/ # Compiled contract artifacts
├── deployments/ # Deployment records (by network)
├── types/ # TypeChain generated types
├── hardhat.config.ts # Hardhat configuration
├── package.json # Root dependencies & scripts
└── README.md # This file
npm run compile # Compile smart contracts
npm run test # Run contract tests (local)
npm run test:sepolia # Run contract tests on Sepolia
npm run deploy:sepolia # Deploy to Sepolia testnet
npm run lint # Run linting (Solidity + TypeScript)
npm run clean # Clean build artifacts
npm run coverage # Generate test coverage reportnpm run dev # Start development server
npm run build # Build for production
npm run preview # Preview production build
npm run lint # Lint frontend code// contracts/SoldierCards.sol
function newFeature(uint256 tokenId, externalEuint32 input, bytes calldata proof) external {
require(ownerOf(tokenId) == msg.sender, "Not owner");
euint32 encrypted = FHE.fromExternal(input, proof);
// Your logic here...
FHE.allowThis(encrypted);
FHE.allow(encrypted, msg.sender);
}// test/SoldierCards.ts
it("should execute new feature", async function () {
const { contract, signer } = await setupFixture();
const input = await encryptInput(value);
await contract.newFeature(tokenId, input.handles[0], input.inputProof);
// Assertions...
});// ui/src/components/YourComponent.tsx
const handleNewFeature = async () => {
const enc = await instance
.createEncryptedInput(CONTRACT_ADDRESS, address)
.add32(yourValue)
.encrypt();
const contract = new Contract(CONTRACT_ADDRESS, CONTRACT_ABI, signer);
const tx = await contract.newFeature(tokenId, enc.handles[0], enc.inputProof);
await tx.wait();
};npm run compile
npm run test
npm run deploy:sepolia
cd ui && npm run devContract Debugging:
- Use
console.log()in Hardhat tests (import fromhardhat/console.sol) - Check gas usage:
npm run testwith gas reporter enabled - Verify on Etherscan:
npx hardhat verify --network sepolia <address>
Frontend Debugging:
- Open browser DevTools console for logs
- All components include extensive
console.log()statements - Use Metamask activity tab to inspect transaction details
- Check Zama relayer status at initialization
Common Issues:
- Transaction reverts: Ensure wallet has enough Sepolia ETH
- Decryption fails: Check that you're the card owner and have signed permissions
- Contract read errors: Verify contract address in
ui/src/config/contracts.ts - FHE initialization slow: Normal - Zama instance takes 10-15 seconds to initialize
- Access Control: All sensitive functions require
ownerOf()validation - Reentrancy Protection: Inherits OpenZeppelin's battle-tested implementations
- Integer Overflow: Using Solidity 0.8+ built-in overflow checks
- Input Validation: All encrypted inputs require cryptographic proofs
- ACL Management: FHE permissions strictly managed via Zama's ACL system
- Private Key Safety: Never expose private keys in frontend code
- Signature Verification: All decryption requests require EIP-712 signatures
- XSS Prevention: React's built-in XSS protection
- Secure RPC: Using Infura for reliable and secure RPC connections
- On-Chain Confidentiality: Card stats are never exposed in contract storage or events
- Decryption Authorization: Only card owner can generate valid decryption signatures
- Transfer Privacy: New owners automatically receive decryption permissions
- Zero-Knowledge Proofs: All encrypted inputs verified without revealing plaintext
- Gas Costs: FHE operations are more expensive than standard arithmetic
- Decryption Time: Client-side decryption takes 5-10 seconds per operation
- Network Dependency: Requires Zama relayer service for FHE operations
- Testnet Only: Current deployment is on Sepolia (not production mainnet)
- Network: Ethereum Sepolia
- Chain ID: 11155111
- RPC URL:
https://sepolia.infura.io/v3/YOUR_KEY - Block Explorer: Sepolia Etherscan
- Faucet: Sepolia Faucet
After deployment, contract addresses are saved in:
deployments/sepolia/SoldierCards.json
View your deployed contract on Etherscan:
https://sepolia.etherscan.io/address/<YOUR_CONTRACT_ADDRESS>
- PvP Battle System: Player vs. player encrypted card battles
- Card Trading: Peer-to-peer encrypted card marketplace
- Leaderboards: Encrypted ranking system with privacy-preserving scores
- Card Evolution: Multi-card fusion for enhanced stats
- Achievement System: Unlock special rewards for milestones
- Guild System: Create teams with shared encrypted resources
- Tournament Mode: Competitive gameplay with encrypted brackets
- Card Attributes Expansion: Add defense, speed, and special abilities
- Dynamic NFT Rendering: On-chain SVG generation based on encrypted stats
- Cross-Chain Support: Deploy to additional EVM chains with FHE support
- Mobile App: React Native mobile client
- Game API: Public API for third-party integrations
- DAO Governance: Community-driven game balance decisions
- Mainnet Deployment: Production launch on Ethereum mainnet
- Token Economics: Introduce utility token for enhanced gameplay
- Multi-Game Universe: Expand to other FHE-powered game genres
- AI-Powered NPCs: Encrypted AI opponents with unpredictable strategies
- Virtual Reality: VR-compatible battle arena
- Professional Esports: Competitive gaming tournaments with prize pools
We welcome contributions from the community! Here's how you can help:
- Report Bugs: Open issues on GitHub with detailed reproduction steps
- Suggest Features: Share your ideas in GitHub Discussions
- Submit Pull Requests: Fix bugs or implement new features
- Improve Documentation: Help clarify instructions or add examples
- Test on Different Networks: Verify compatibility across environments
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Make your changes with clear commit messages
- Write tests for new functionality
- Ensure all tests pass (
npm run test) - Submit a pull request with detailed description
- Solidity: Follow Solidity Style Guide
- TypeScript/React: Use ESLint and Prettier configurations provided
- Comments: Write clear, concise comments explaining complex logic
- Commits: Use conventional commit format (e.g.,
feat:,fix:,docs:)
- Zama FHEVM Docs: https://docs.zama.ai/fhevm
- Hardhat Documentation: https://hardhat.org/docs
- OpenZeppelin Contracts: https://docs.openzeppelin.com/contracts
- Wagmi Documentation: https://wagmi.sh/
- RainbowKit Docs: https://www.rainbowkit.com/
- Solidity by Example: https://solidity-by-example.org/
- Ethereum Development Tutorial: https://ethereum.org/en/developers/tutorials/
- React Documentation: https://react.dev/
- FHE Introduction: https://www.zama.ai/post/what-is-fully-homomorphic-encryption-fhe
- Zama Discord: https://discord.gg/zama
- Ethereum Stack Exchange: https://ethereum.stackexchange.com/
This project is licensed under the BSD-3-Clause-Clear License.
Key terms:
- ✅ Commercial use allowed
- ✅ Modification allowed
- ✅ Distribution allowed
- ✅ Private use allowed
- ❌ No patent grant
⚠️ Liability and warranty excluded
See the LICENSE file for full details.
- Zama Team: For pioneering Fully Homomorphic Encryption technology and providing the FHEVM framework
- OpenZeppelin: For battle-tested smart contract libraries
- Hardhat Team: For the excellent development environment
- RainbowKit: For seamless wallet connection UX
- Ethereum Community: For building the decentralized infrastructure that makes this possible
- GitHub Issues: Report bugs or request features
- GitHub Discussions: Community Q&A and ideas
- Email: your.email@example.com
- Twitter: @YourTwitterHandle
Built with ❤️ using Zama's FHE technology
Experience the future of blockchain gaming - where privacy meets playability.
Traditional blockchain games face a fundamental transparency paradox:
- No Strategic Depth: All NFT attributes are publicly visible on-chain, eliminating surprise and strategy
- Predictable Outcomes: Players can inspect opponents' cards before battles, removing competitive tension
- Exploitable Mechanics: Bots and scripts can optimize strategies by analyzing all public game state
- Privacy Concerns: Players cannot keep their valuable assets and strategies confidential
CryptoCards leverages Fully Homomorphic Encryption (FHE) to enable:
- Hidden Information Gameplay: Card stats remain encrypted on-chain, visible only to owners
- True Competition: Opponents cannot inspect your cards, restoring strategic depth
- Privacy-Preserving Ownership: Prove ownership without revealing asset details
- Future-Proof Security: Cryptographic guarantees that outlast traditional security measures
- First-of-its-Kind: Among the first NFT games using production FHE on Ethereum
- Decentralized Privacy: No trusted third parties required for encryption/decryption
- Composable Security: Built on audited libraries (OpenZeppelin, Zama FHEVM)
- Scalable Design: Architecture supports complex game mechanics while maintaining encryption
- One-click wallet connection via RainbowKit
- Automatic network switching to Sepolia
- Clear error messages and transaction feedback
- Clean, modern design with glass-morphism aesthetics
- Responsive layout for desktop and mobile
- Real-time transaction status updates
- Visual feedback for all user actions
- Instant monster generation with variety
- Satisfying battle animations and feedback
- Exciting loot reveals after victories
- Growing card collection to showcase progress
- Blockchain transaction links in UI
- Debug information for developers
- Clear encryption/decryption status
- Gas estimation before transactions
Ready to start playing? Follow the Getting Started guide above!
Questions or issues? Check our FAQ section or open an issue.
Want to contribute? See our Contributing Guidelines to get involved!