Documentation Index
Fetch the complete documentation index at: https://mintlify.com/0xchriswilder/journey/llms.txt
Use this file to discover all available pages before exploring further.
Week 2: FHEVM Smart Contract Development
Subtitle: Write, test, and deploy confidential smart contracts Estimated Time: 10 hours of lessons + 5 hours homeworkObjectives
First Contract
Write your first FHEVM smart contract with encrypted state
Design Patterns
Understand FHEVM contract design patterns and best practices
Testing
Test contracts using Hardhat with FHEVM mocks
Deployment
Deploy contracts to Sepolia testnet and verify on explorer
Milestone
Deployed and tested EncryptedCounter contract on Sepolia
Passing Hardhat test suite
Understanding of FHEVM contract patterns
Lessons
Lesson 2.1: Your First FHEVM Contract
Duration: 60 minutesLearning Objectives
Learning Objectives
- Create a Solidity contract that imports and uses FHE types
- Declare encrypted state variables (euint8, euint64)
- Implement functions that accept encrypted inputs
- Use FHE.fromExternal() to handle client-encrypted data
- Apply FHE.allowThis() for decryption permissions
From Plain Counter to Encrypted Counter
From Plain Counter to Encrypted Counter
A Plain Solidity Counter (Review)Converting to an Encrypted Counter
Notice:
count is public — anyone can read it on-chain. What if the count itself is sensitive?Key Differences: Plain vs Encrypted
Key Differences: Plain vs Encrypted
State Visibility
uint8 public count → euint32 private counterThe encrypted version cannot be read by anyone on-chain.Input Handling
Instead of plain uint8 parameters, we accept
externalEuint32 + proof bytesThe client encrypts values before sending.Permissions
After each mutation, call
FHE.allowThis(counter)So the contract can later request decryption.Walking Through the Contract
Walking Through the Contract
ImportsThe
FHE library contains all encrypted operations. euint32 is a 32-bit encrypted integer (stored as a bytes32 handle on-chain). externalEuint32 is for client-supplied encrypted data.ConstructorWe initialize with FHE.asEuint32(0) and FHE.allowThis(counter) so the contract can use that value later.increment() — Three Steps- Turn the client’s encrypted input into something the contract can use:
FHE.fromExternal(encryptedAmount, proof) - Add it to the counter:
FHE.add(counter, amount)— returns a new handle - Call
FHE.allowThis(counter)on the new value
requestReveal()makes the counter eligible for public decryption- Frontend calls
publicDecrypt()in the Relayer SDK resolveReveal()verifies the proof and stores the plaintext result
Common Pitfalls to Avoid
Common Pitfalls to Avoid
Lesson 2.2: Contract Patterns & Architecture
Duration: 45 minutesLearning Objectives
Learning Objectives
- Analyze the SimpleVoting.sol contract line by line
- Identify the session-based pattern for managing FHE state
- Understand the encrypted input → compute → controlled decrypt lifecycle
- Learn best practices for FHEVM contract architecture
SimpleVoting Contract Architecture
SimpleVoting Contract Architecture
FHEVM Design Patterns
FHEVM Design Patterns
Pattern 1: Session-Based State
Group related encrypted values into structs with lifecycle (create → interact → resolve)
Pattern 2: Encrypted Accumulator
Use FHE.add() to build running totals without revealing individual contributions
Pattern 3: FHE.select for Conditionals
Replace if/else on encrypted conditions with select() to choose between encrypted values
Pattern 4: Self-Relaying Reveal (v0.9+)
makePubliclyDecryptable → client decrypts off-chain → submit proof → checkSignatures
Pattern 5: Access-Controlled Decryption
Use require(msg.sender == owner) before allowing decryption requests
Always initialize encrypted state with FHE.asEuintX(0)
Call FHE.allowThis() after every encrypted state mutation
Use events to track encrypted operations (events are public)
Keep decryption requests gated behind access control
Lesson 2.3: Testing & Deployment
Duration: 50 minutesLearning Objectives
Learning Objectives
- Write Hardhat tests for FHEVM contracts using mock mode
- Understand the test lifecycle for encrypted operations
- Deploy an EncryptedCounter to Sepolia testnet
- Verify deployment and interact with the contract on-chain
Testing FHEVM Contracts with Hardhat
Testing FHEVM Contracts with Hardhat
Mock ModeFHEVM contracts can be tested locally using mock mode, which simulates FHE operations without actual encryption. This is much faster than testing on a live network.
Deploying to Sepolia
Deploying to Sepolia
Deployment ScriptDeploy to Sepolia
Make sure your wallet has Sepolia ETH before deploying. Get test ETH from Sepolia Faucet.
Homework: Build a Confidential Counter
Estimated Time: 5 hours Objective: Build, test, and deploy a fully functional EncryptedCounter contract with increment, decrement, and reset capabilities.Requirements
1. EncryptedCounter Contract (30%)
1. EncryptedCounter Contract (30%)
Write an
EncryptedCounter.sol (v0.9+) with:increment(euint32)with encrypted inputdecrement(euint32)with underflow protection using FHE.select()reset()functionrequestReveal()using makePubliclyDecryptableresolveReveal()with checkSignatures
2. Hardhat Tests (30%)
2. Hardhat Tests (30%)
Write at least 3 tests:
- Initial count is 0
- Increment works correctly
- Decrement does not underflow below 0
3. Sepolia Deployment (20%)
3. Sepolia Deployment (20%)
Deploy your contract to Sepolia testnet and submit:
- Contract address
- Transaction hash
4. Design Writeup (20%)
4. Design Writeup (20%)
Write a short (200-word) explanation of:
- Your contract design decisions
- Any challenges you faced
- How you handled underflow protection
Submission
Include files
contracts/EncryptedCounter.soltest/EncryptedCounter.test.tsdeployment.mdwith contract address and TX hashwriteup.mdwith design explanation
Next Steps
Continue to Week 3
Now that you can write and test FHEVM contracts, move on to Week 3 to build a full-stack confidential dApp with React frontend integration.