Full-featured Next.js application demonstrating FHEVM SDK integration for confidential environmental monitoring.
This example shows how to use the FHEVM SDK in a production Next.js application with:
- β Client-side FHE encryption
- β Wagmi-like React hooks
- β EIP-712 signed decryption
- β Real-time encrypted dashboard
- β MetaMask integration
- β Sepolia testnet deployment
# From repository root
npm install
# Or from this directory
cd examples/nextjs-pollution-monitor
npm install
# Start development server
npm run devVisit http://localhost:3000
Next.js Application Structure
βββ app/ # App Router (Next.js 13+)
β βββ layout.tsx # Root layout with FHE provider
β βββ page.tsx # Home page
β βββ globals.css # Global styles
β βββ api/ # API Routes
β βββ fhe/ # FHE operations
β β βββ route.ts # Main FHE endpoint
β β βββ encrypt/route.ts # Encryption API
β β βββ decrypt/route.ts # Decryption API
β β βββ compute/route.ts # Homomorphic computation
β βββ keys/route.ts # Key management API
β
βββ components/ # React Components
β βββ ui/ # Base UI components
β β βββ Button.tsx
β β βββ Input.tsx
β β βββ Card.tsx
β βββ fhe/ # FHE functionality
β β βββ FHEProvider.tsx # FHE context provider
β β βββ EncryptionDemo.tsx # Encryption demonstration
β β βββ ComputationDemo.tsx # Computation demonstration
β β βββ KeyManager.tsx # Key management UI
β βββ StationRegistration.tsx
β βββ PollutionReporter.tsx
β βββ Dashboard.tsx
β βββ WalletConnect.tsx
β
βββ lib/ # Library utilities
β βββ fhe/ # FHE integration
β β βββ client.ts # Client-side FHE operations
β β βββ server.ts # Server-side FHE operations
β β βββ keys.ts # Key management
β β βββ types.ts # FHE type definitions
β βββ utils/ # Utility functions
β β βββ security.ts # Security utilities
β β βββ validation.ts # Validation helpers
β βββ contract.ts # Smart contract integration
β
βββ hooks/ # Custom React Hooks
β βββ useFHE.ts # FHE client hook
β βββ useEncryption.ts # Encryption hook
β βββ useComputation.ts # Computation hook
β
βββ types/ # TypeScript definitions
βββ fhe.ts # FHE type definitions
βββ api.ts # API type definitions
import { useFhevmClient, useContract } from 'fhevm-sdk/react';
function StationRegistration() {
const client = useFhevmClient();
const contract = useContract(CONTRACT_ADDRESS, ABI);
const registerStation = async (name: string) => {
const tx = await contract.registerStation(name);
await tx.wait();
};
return (
<button onClick={() => registerStation('Factory North')}>
Register Station
</button>
);
}import { useEncrypt, useFhevmTransaction } from 'fhevm-sdk/react';
function PollutionReporter() {
const { encrypt, isEncrypting } = useEncrypt();
const { send, isLoading } = useFhevmTransaction(contract, 'submitReport');
const submitReport = async (value: number, type: number) => {
// Encrypt the pollution measurement
const encrypted = await encrypt(value, 'uint64');
// Submit encrypted report
await send(encrypted, type, getSeverity(value));
};
return (
<form onSubmit={handleSubmit}>
<input type="number" placeholder="PM2.5 value (ΞΌg/mΒ³)" />
<button disabled={isEncrypting || isLoading}>
{isEncrypting ? 'Encrypting...' : 'Submit Report'}
</button>
</form>
);
}import { useDecrypt } from 'fhevm-sdk/react';
function DecryptValue() {
const { decrypt, isDecrypting } = useDecrypt();
const viewMyReport = async (encryptedData: Uint8Array) => {
try {
// Requires user signature
const decrypted = await decrypt(encryptedData, CONTRACT_ADDRESS);
console.log('Decrypted value:', decrypted);
} catch (error) {
console.error('Decryption failed:', error);
}
};
return (
<button onClick={() => viewMyReport(data)} disabled={isDecrypting}>
{isDecrypting ? 'Decrypting...' : 'View My Data'}
</button>
);
}import { useContract, useBatchDecrypt } from 'fhevm-sdk/react';
function Dashboard() {
const contract = useContract(CONTRACT_ADDRESS, ABI);
const { decryptBatch } = useBatchDecrypt();
const [stats, setStats] = useState(null);
useEffect(() => {
loadStats();
}, []);
const loadStats = async () => {
const [stations, reports] = await contract.getStatistics();
setStats({ stations, reports });
};
return (
<div className="dashboard">
<h2>Environmental Monitoring Dashboard</h2>
<StatsCard label="Total Stations" value={stats?.stations} />
<StatsCard label="Total Reports" value={stats?.reports} />
<RecentReports />
</div>
);
}- Individual pollution measurements (euint64)
- Severity assessments
- Station-specific data
- Station registration (name visible)
- Report timestamps
- Alert status (threshold exceeded yes/no)
- Total statistics
- Station Operators: Can decrypt their own reports
- Verifiers: Can access encrypted data with permission
- Public: Can view aggregated statistics only
Create .env.local:
# Network
NEXT_PUBLIC_NETWORK=sepolia
NEXT_PUBLIC_CHAIN_ID=11155111
NEXT_PUBLIC_RPC_URL=https://rpc.sepolia.org
# Contract
NEXT_PUBLIC_CONTRACT_ADDRESS=0xc61a1997F87156dfC96CA14E66fA9E3A02D36358
# FHEVM Gateway
NEXT_PUBLIC_GATEWAY_URL=https://gateway.zama.ai
# Optional: Analytics
NEXT_PUBLIC_ANALYTICS_ID=app/layout.tsx:
import { FhevmProvider } from 'fhevm-sdk/react';
export default function RootLayout({ children }) {
return (
<html>
<body>
<FhevmProvider
config={{
network: 'sepolia',
contractAddress: process.env.NEXT_PUBLIC_CONTRACT_ADDRESS
}}
>
{children}
</FhevmProvider>
</body>
</html>
);
}Main FHE endpoint providing API status and information.
Response:
{
"status": "ok",
"endpoints": {
"encrypt": "/api/fhe/encrypt",
"decrypt": "/api/fhe/decrypt",
"compute": "/api/fhe/compute"
},
"version": "1.0.0"
}Encrypt values using FHE.
Request:
{
"value": 42,
"type": "uint64"
}Response:
{
"success": true,
"encrypted": {
"type": "uint64",
"value": "42",
"timestamp": 1234567890
},
"message": "Value encrypted successfully"
}Decrypt encrypted data with EIP-712 signature.
Request:
{
"encryptedData": "0x...",
"signature": "0x...",
"contractAddress": "0x..."
}Perform homomorphic computations.
Request:
{
"operation": "add",
"operands": ["0x...", "0x..."]
}Retrieve public key for encryption.
Query Parameters:
contract: Contract address (required)
Initialize and manage FHE client.
const { client, isInitialized, isInitializing, error, initialize } = useFHE();Handle encryption operations.
const { encrypt, isEncrypting, result, error, reset } = useEncryption();
await encrypt(42, 'uint64');Handle homomorphic computations.
const { compute, isComputing, result, error, reset } = useComputation();
await compute('add', [encryptedValue1, encryptedValue2]);Reusable button component with loading states.
<Button variant="primary" size="md" isLoading={false}>
Click Me
</Button>Props:
variant: 'primary' | 'secondary' | 'outline' | 'danger'size: 'sm' | 'md' | 'lg'isLoading: boolean
Input component with label and error handling.
<Input
label="Enter value"
error="Invalid input"
helperText="Helper text"
/>Container component with header and footer.
<Card
title="Card Title"
subtitle="Subtitle"
footer={<Button>Action</Button>}
>
Content
</Card>Context provider for FHE operations.
<FHEProvider contractAddress="0x...">
<App />
</FHEProvider>Interactive encryption demonstration component.
Interactive homomorphic computation demo.
FHE key management interface.
# Unit tests
npm test
# E2E tests
npm run test:e2e
# Component tests
npm run test:components# Install Vercel CLI
npm i -g vercel
# Deploy
vercel --prodAdd in Vercel Dashboard:
NEXT_PUBLIC_CONTRACT_ADDRESSNEXT_PUBLIC_NETWORKNEXT_PUBLIC_RPC_URL
lib/contract.ts:
export const CONTRACT_ABI = [/* ABI from artifacts */];
export const CONTRACT_ADDRESS = '0xc61a1997F87156dfC96CA14E66fA9E3A02D36358';registerStation(name)submitReport(encrypted, type, severity)verifyReport(reportId)getStationDetails(address)getReportDetails(reportId)getStatistics()
See complete examples in:
components/StationRegistration.tsx- Station setupcomponents/PollutionReporter.tsx- Encrypted reportingcomponents/DashboardView.tsx- Data visualizationapp/dashboard/page.tsx- Full page integration
// Check if MetaMask is installed
if (!window.ethereum) {
alert('Please install MetaMask');
}
// Request account access
await window.ethereum.request({ method: 'eth_requestAccounts' });// Ensure client is initialized
const client = useFhevmClient();
// Check if client is ready
if (!client.isInitialized()) {
await client.init();
}// Add/Switch to Sepolia
await window.ethereum.request({
method: 'wallet_addEthereumChain',
params: [{
chainId: '0xaa36a7',
chainName: 'Sepolia',
rpcUrls: ['https://rpc.sepolia.org'],
}],
});Improvements welcome! This example demonstrates FHEVM SDK integration patterns.
MIT License - see LICENSE
Live Demo: https://pollution-monitor.vercel.app
Contract: 0xc61a1997F87156dfC96CA14E66fA9E3A02D36358 (Sepolia)