A Node.js CLI application demonstrating the Universal FHEVM SDK using the Node.js class adapter (FhevmNode) with real server-side blockchain interactions on Sepolia testnet.
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Node.js Showcase β
β β
β ββββββββββββββββ ββββββββββββββββ ββββββββββββββββ β
β β index.ts β β counter.ts β β voting.ts β β
β β β β β β β β
β β β β β β β β
β β β β β β β β
β β β β β β β β
β ββββββββ¬ββββββββ ββββββββ¬ββββββββ ββββββββ¬ββββββββ β
β β β β β
β β β β β
β β β β β
β βββββββββββββββββββΌβββββββββββββββββββ β
β β β
β βββββββββΌβββββββββ β
β β FhevmNode β β
β β Class Adapterβ β
β β β β
β β ββββββββββββββ β β
β β βinitialize()β β β
β β βencrypt() β β β
β β βdecrypt() β β β
β β βpublicDecryptββ β
β β βcreateContractβ β
β β βexecuteTx() β β β
β β βββββββ¬ββββββββ β β
β βββββββββΌββββββββββ β
β β β
β βββββββββΌβββββββββ β
β β Core SDK β β
β β (fhevm-sdk) β β
β βββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# Navigate to Node.js showcase
cd packages/node-showcase
# Install dependencies
pnpm install
# Run the showcase
pnpm start
# This runs:
# - Counter demo (increment/decrement/decrypt)
# - Voting demo (create session/vote)
# - Ratings demo (submit rating/public decrypt)- β
Node.js Adapter - Uses
FhevmNodeclass adapter - β Real FHEVM operations - Server-side blockchain interactions
- β Multiple demos - Counter, Voting, Ratings
- β EIP-712 decryption - Proper authentication
- β Public decryption - No signature required
- β
Self-relaying decryption - Event-driven pattern with
decryptMultiple(FHEVM 0.9.0) - β Real contract interactions - Sepolia testnet
- β CLI interface - Command-line operations
- β TypeScript support - Full type safety
- Node.js - Server-side JavaScript runtime
- TypeScript - Full type safety
- Ethers.js - Ethereum interactions
- @fhevm-sdk - Universal FHEVM SDK with Node.js adapter
- tsx - TypeScript execution
This showcase demonstrates how to use the Node.js class adapter (FhevmNode) from @fhevm-sdk:
import { FhevmNode } from '../../fhevm-sdk/dist/adapters/node.js';
import { runCounterDemo } from './counter.js';
import { runVotingDemo } from './voting.js';
import { runRatingsDemo } from './ratings.js';
async function main() {
// Initialize FHEVM Node.js instance
const fhevm = new FhevmNode({
rpcUrl: RPC_URL,
privateKey: PRIVATE_KEY,
chainId: CHAIN_ID
});
await fhevm.initialize();
// Run demos
await runCounterDemo(fhevm, config);
await runVotingDemo(fhevm, config);
await runRatingsDemo(fhevm, config);
}import { FhevmNode } from '../../fhevm-sdk/dist/adapters/node.js';
export async function runCounterDemo(fhevm: FhevmNode, config: CounterDemoConfig) {
// Create contract
const contract = fhevm.createContract(contractAddress, CONTRACT_ABI);
// Encrypt increment value (FHEVM 0.9.0)
const encrypted = await fhevm.encrypt(contractAddress, walletAddress, 1);
// Execute increment transaction (uses encryptedData and proof)
await fhevm.executeEncryptedTransaction(contract, 'increment', encrypted);
// Read encrypted count
const countHandle = await contract.getCount();
// Decrypt count (EIP-712)
const decrypted = await fhevm.decrypt(countHandle, contractAddress);
console.log(`Decrypted count: ${decrypted}`);
}import { FhevmNode } from '../../fhevm-sdk/dist/adapters/node.js';
export async function runVotingDemo(fhevm: FhevmNode, config: VotingDemoConfig) {
const contract = fhevm.createContract(VOTING_CONTRACT_ADDRESS, VOTING_CONTRACT_ABI);
// Create session if needed
if (sessionCount === 0) {
await contract.createSession(86400); // 24 hours
}
// Encrypt vote (YES = 1) - FHEVM 0.9.0 format
const encryptedVote = await fhevm.encrypt(VOTING_CONTRACT_ADDRESS, walletAddress, 1);
// Extract encrypted data and proof (new format)
const encryptedData = encryptedVote.encryptedData;
const proof = encryptedVote.proof;
// Vote directly
await contract.vote(sessionId, encryptedData, proof);
// Request tally reveal with self-relaying decryption
if (canRequestTally) {
// Step 1: Request reveal (emits event)
const tx = await contract.requestTallyReveal(sessionId);
const receipt = await tx.wait();
// Step 2: Extract handles from TallyRevealRequested event
const event = receipt.logs.find(log => {
const parsed = contract.interface.parseLog(log);
return parsed?.name === 'TallyRevealRequested';
});
const { yesVotesHandle, noVotesHandle } = contract.interface.parseLog(event).args;
// Step 3: Decrypt multiple handles
const { cleartexts, decryptionProof, values } = await fhevm.decryptMultiple(
VOTING_CONTRACT_ADDRESS,
[yesVotesHandle, noVotesHandle]
);
// Step 4: Submit callback with proof
await contract.resolveTallyCallback(sessionId, cleartexts, decryptionProof);
}
}import { FhevmNode } from '../../fhevm-sdk/dist/adapters/node.js';
export async function runRatingsDemo(fhevm: FhevmNode, config: RatingsDemoConfig) {
const contract = fhevm.createContract(RATINGS_CONTRACT_ADDRESS, RATINGS_CONTRACT_ABI);
// Encrypt rating (5 stars) - FHEVM 0.9.0 format
const encryptedRating = await fhevm.encrypt(RATINGS_CONTRACT_ADDRESS, walletAddress, 5);
// Submit rating (uses encryptedData and proof)
await fhevm.executeEncryptedTransaction(contract, 'submitEncryptedRating', encryptedRating, cardId);
// Get encrypted stats
const stats = await contract.getEncryptedStats(cardId);
// Public decrypt stats (no signature required)
const sum = await fhevm.publicDecrypt(stats.sum);
const count = await fhevm.publicDecrypt(stats.count);
const average = sum / count;
console.log(`Average rating: ${average}`);
}class FhevmNode {
// Initialization
async initialize(): Promise<void>
// Encryption (returns { encryptedData, proof })
async encrypt(contractAddress: string, userAddress: string, value: number): Promise<{
encryptedData: string;
proof: string;
}>
// Decryption
async decrypt(handle: string, contractAddress: string): Promise<number>
async publicDecrypt(handle: string): Promise<number>
async decryptMultiple(
contractAddress: string,
handles: string[]
): Promise<{ cleartexts: string; decryptionProof: string; values: number[] }>
// Contract operations
createContract(address: string, abi: any[]): ethers.Contract
async executeEncryptedTransaction(
contract: ethers.Contract,
methodName: string,
encryptedData: any,
...additionalParams: any[]
): Promise<any>
// Utility
async getAddress(): Promise<string | null>
getConfig(): object
getStatus(): 'ready' | 'idle'
}- Encrypt increment value - Create encrypted input
- Execute increment transaction - Send encrypted transaction
- Read encrypted count - Get encrypted value from contract
- Decrypt count - EIP-712 user decryption
- Decrement workflow - Complete decrement with decryption
- Create voting session - Initialize new session if needed
- Check session status - Validate session is active
- Check vote status - Verify user hasn't voted
- Encrypt vote - Create encrypted YES vote (value 1)
- Submit vote - Send encrypted vote to contract
- Request tally reveal - Trigger event with encrypted handles
- Extract handles from event - Get handles from
TallyRevealRequestedevent - Decrypt multiple handles - Use
decryptMultiplefor self-relaying pattern - Submit callback - Call
resolveTallyCallbackwith proof
- Get rating cards - Read available cards from contract
- Check card exists - Validate card is available
- Check rating status - Verify user hasn't rated
- Encrypt rating - Create encrypted 5-star rating
- Submit rating - Send encrypted rating to contract
- Get encrypted stats - Read sum and count handles
- Public decrypt stats - Decrypt without signature
- Calculate average - Compute average rating
- FHE Counter Contract:
0x1b45fa7b7766fb27A36fBB0cfb02ea904214Cc75 - Ratings Contract:
0x0382053b0eae2A4A45C4A668505E2030913f559e - Voting Contract:
0x4D15cA56c8414CF1bEF42B63B0525aFc3751D2d1 - Network: Sepolia testnet (Chain ID: 11155111)
- FHEVM Version: 0.9.0
- Relayer SDK: 0.3.0-5
- RPC: Configurable via environment variables
The easiest way to explore FHEVM demos is through the interactive CLI wizard:
# Start the interactive explorer
pnpm explorerFeatures:
- π Beautiful interactive menu - Choose which demo to run
- π’ Counter Demo - Increment/decrement operations with prompts
- π³οΈ Voting Demo - Encrypted voting with interactive choices
- β Ratings Demo - Submit ratings with user input
- π Test Mode - Verify your setup before running demos
- π― Run All - Execute all demos in sequence
- π Session Summary - Track all demos you've completed
Interactive Experience:
- Guided step-by-step demos
- User prompts for values (increment amounts, ratings, votes)
- Real-time transaction feedback
- Loading spinners and progress indicators
- Session tracking and summary at the end
Example Session:
π Welcome to FHEVM Explorer!
Universal FHEVM SDK - Interactive Demo Experience
Choose your FHEVM demo:
β― π’ Counter Demo - Increment/Decrement Operations
π³οΈ Voting Demo - Encrypted Voting System
β Ratings Demo - Review Cards with Encrypted Ratings
π Test Mode - Verify Setup Only
π― Run All Demos
β Exit Explorer
Run the showcase as an HTTP server with API endpoints:
# Start the HTTP server
pnpm start
# Server runs on http://localhost:3001
# Available endpoints:
# - GET / - List available endpoints
# - GET /health - Health check
# - GET /config - Get FHEVM configuration
# - POST /counter - Run counter demo
# - POST /voting - Run voting demo
# - POST /ratings - Run ratings demo
# - POST /run-all - Run all demosTest endpoints using PowerShell:
# Run counter demo
Invoke-RestMethod -Uri http://localhost:3001/counter -Method POST
# Run voting demo
Invoke-RestMethod -Uri http://localhost:3001/voting -Method POST
# Get configuration
Invoke-RestMethod -Uri http://localhost:3001/config -Method GETRun all demos sequentially without interaction:
# Run all demos at once
pnpm cli
# Output includes:
# - Counter demo: Increment β Decrement β Decrypt
# - Voting demo: Create session β Vote
# - Ratings demo: Submit rating β Public decrypt stats# Interactive CLI mode (recommended for testing)
pnpm explorer
# HTTP server mode
pnpm start
# Non-interactive CLI mode
pnpm cli
# Development mode (watch HTTP server)
pnpm dev
# Build TypeScript
pnpm buildnode- Node.js runtimeethers- Ethereum interactions@fhevm-sdk- Universal FHEVM SDK with Node.js adaptertypescript- Type safetytsx- TypeScript executiondotenv- Environment variablesexpress- HTTP server (for server mode)inquirer- Interactive prompts (for explorer mode)chalk- Terminal colors (for explorer mode)ora- Loading spinners (for explorer mode)
- β Real blockchain interactions - Live Sepolia testnet
- β Node.js adapter working - Server-side operations
- β Multiple demos - Counter, Voting, Ratings
- β EIP-712 authentication - Proper user decryption
- β Public decryption - No signature required
- β CLI interface - Server-side FHEVM usage
- β Complete workflows - End-to-end operations
Perfect for server-side FHEVM operations! π