Production-ready FHEVM SDK for building privacy-preserving decentralized applications
A comprehensive SDK and template collection for integrating Zama's fhEVM technology into your blockchain applications. This project provides framework-agnostic core utilities, React hooks, and complete examples demonstrating privacy-preserving smart contract interactions.
This repository contains:
- Universal FHEVM SDK (
packages/fhevm-sdk): A reusable, framework-agnostic SDK for FHE encryption/decryption - Example Templates: Next.js demonstrations with complete SDK integration
- Smart Contracts: Example FHE-enabled contracts
- Complete Documentation: Everything you need to get started
Live Demo: https://private-rental-matching.vercel.app/
Demo Videos: Available in repository root (demo1.mp4, demo2.mp4, demo3.mp4)
- Node.js >= 18.0.0
- npm or yarn
- MetaMask wallet
- Sepolia testnet ETH
# Clone the repository
git clone <your-repository-url>
cd fhevm-react-template
# Install all packages from root
npm install# Compile Solidity contracts
npm run compile
# Deploy to Sepolia testnet
npm run deploy
# ABI is automatically generated in artifacts/# Start Next.js demo (recommended)
npm run dev:nextjs
# Or navigate to the example directory
cd examples/nextjs-demo
npm install
npm run devVisit http://localhost:3000 to see the application running!
fhevm-react-template/
βββ packages/
β βββ fhevm-sdk/ # Universal SDK Package
β βββ src/
β β βββ core/ # Framework-agnostic core
β β β βββ client.ts # Main SDK client
β β β βββ index.ts
β β βββ react/ # React hooks and adapters
β β β βββ hooks/
β β β β βββ useFhevm.ts
β β β β βββ useEncrypt.ts
β β β β βββ useDecrypt.ts
β β β βββ provider.tsx
β β β βββ index.ts
β β βββ adapters/ # Framework adapters
β β β βββ vue.ts # Vue 3 composables
β β β βββ index.ts
β β βββ utils/ # Utility functions
β β β βββ encryption.ts # Encryption utilities
β β β βββ decryption.ts # Decryption utilities
β β β βββ index.ts
β β βββ types/ # TypeScript definitions
β βββ package.json
β βββ tsconfig.json
β βββ README.md
β
βββ examples/
β βββ nextjs-demo/ # Next.js 14 demonstration
β β βββ src/
β β β βββ app/ # App Router (Next.js 14)
β β β β βββ layout.tsx # Root layout
β β β β βββ page.tsx # Main demo page
β β β β βββ providers.tsx # FHEVM Provider setup
β β β β βββ api/ # API routes
β β β β βββ fhe/
β β β β β βββ route.ts # FHE operations route
β β β β β βββ encrypt/route.ts # Encryption endpoint
β β β β β βββ decrypt/route.ts # Decryption endpoint
β β β β β βββ compute/route.ts # Computation endpoint
β β β β βββ keys/route.ts # Key management
β β β βββ components/ # React components
β β β β βββ ui/ # Base UI components
β β β β β βββ Button.tsx
β β β β β βββ Input.tsx
β β β β β βββ Card.tsx
β β β β βββ fhe/ # FHE feature components
β β β β β βββ FHEProvider.tsx
β β β β β βββ EncryptionDemo.tsx
β β β β β βββ ComputationDemo.tsx
β β β β β βββ KeyManager.tsx
β β β β βββ examples/ # Use case examples
β β β β βββ BankingExample.tsx
β β β β βββ MedicalExample.tsx
β β β βββ lib/ # Utility libraries
β β β β βββ fhe/ # FHE integration
β β β β β βββ client.ts # Client-side FHE
β β β β β βββ server.ts # Server-side FHE
β β β β β βββ keys.ts # Key management
β β β β β βββ types.ts # Type definitions
β β β β βββ utils/ # Utility functions
β β β β βββ security.ts # Security utilities
β β β β βββ validation.ts # Validation utilities
β β β βββ hooks/ # Custom hooks
β β β β βββ useFHE.ts
β β β β βββ useEncryption.ts
β β β β βββ useComputation.ts
β β β βββ types/ # TypeScript types
β β β β βββ fhe.ts
β β β β βββ api.ts
β β β βββ styles/ # Style files
β β β βββ globals.css
β β βββ package.json
β β βββ README.md
β βββ rental-matching-react/ # React rental platform
β β βββ src/
β β β βββ components/ # React components
β β β β βββ WalletInfo.tsx # Wallet connection UI
β β β β βββ CreateListing.tsx # Create listing form
β β β β βββ CreateRequest.tsx # Create request form
β β β β βββ CreateMatch.tsx # Match creation
β β β β βββ Statistics.tsx # Platform stats
β β β β βββ UserActivity.tsx # User's listings/requests
β β β β βββ StatusBar.tsx # Status messages
β β β βββ hooks/ # Custom React hooks
β β β β βββ useWallet.ts # Wallet connection hook
β β β β βββ useContract.ts # Contract interaction hook
β β β βββ lib/ # Utility libraries
β β β β βββ contract.ts # Contract ABI and types
β β β βββ App.tsx # Main app component
β β β βββ main.tsx # Entry point
β β β βββ index.css # Global styles
β β β βββ vite-env.d.ts # Type declarations
β β βββ index.html # HTML template
β β βββ vite.config.ts # Vite configuration
β β βββ tsconfig.json # TypeScript config
β β βββ package.json # Dependencies
β β βββ README.md # Project documentation
β βββ RentalMatching/ # HTML rental platform
β βββ README.md # Examples documentation
β
βββ contracts/ # Example FHE contracts
β βββ PrivateRentalMatching.sol
β βββ README.md
β
βββ scripts/ # Deployment scripts
β βββ deploy.ts
β βββ README.md
β
βββ test/ # Contract tests
β βββ PrivateRentalMatching.test.ts
β
βββ hardhat.config.ts # Hardhat configuration
βββ package.json # Root package.json
βββ README.md # This file
βββ BOUNTY_SUBMISSION.md # Bounty submission details
βββ SETUP_GUIDE.md # Detailed setup guide
- Framework-Agnostic Core: Use with React, Vue, Angular, or vanilla JS
- Type-Safe: Full TypeScript support with comprehensive types
- Modular API: Import only what you need
- Wagmi-like Design: Familiar hook patterns for React developers
- Zero Dependencies: Core has no external dependencies
- Easy Encryption: Simple encrypt helper functions
- Batch Operations: Encrypt multiple values at once
- User Decryption: EIP-712 signature-based decryption
- Public Decryption: No-signature decryption for public data
- Automatic Verification: Built-in ciphertext validation
- React Hooks:
useFhevm(),useEncrypt(),useDecrypt() - Ready Components: Copy-paste encryption/decryption components
- Error Handling: Graceful error messages and retry logic
- Loading States: Built-in loading indicators
- IntelliSense: Full autocomplete support
- Tested: Comprehensive test suite
- Documented: JSDoc comments on all public APIs
- Deployed: Live demo on Vercel
- Optimized: Tree-shakeable for minimal bundle size
# Install the SDK package
npm install @fhevm/sdk
# Or use it from the workspace
npm install @fhevm/sdk@workspace:*import { initFhevm } from '@fhevm/sdk/core';
// Initialize the FHEVM SDK
const fhevm = await initFhevm({
network: 'sepolia',
gatewayUrl: 'https://gateway.zama.ai',
debug: false,
});
// Encrypt a value
const encrypted = await fhevm.encrypt(1234, 'euint32');
console.log('Ciphertext:', encrypted.ciphertext);
console.log('Type:', encrypted.type);
// Public decrypt (no signature required)
const decrypted = await fhevm.publicDecrypt(encrypted.ciphertext, 'euint32');
console.log('Decrypted value:', decrypted.value);The SDK provides powerful React hooks for seamless integration:
'use client';
import { useFhevm, useEncrypt, useDecrypt } from '@fhevm/sdk/react';
import { useState } from 'react';
function EncryptionExample() {
const { isInitialized, isInitializing } = useFhevm();
const { encrypt, isEncrypting, result: encryptResult } = useEncrypt();
const { publicDecrypt, isDecrypting, result: decryptResult } = useDecrypt();
const [value, setValue] = useState('42');
const handleEncrypt = async () => {
try {
await encrypt(Number(value), 'euint32');
} catch (error) {
console.error('Encryption failed:', error);
}
};
const handleDecrypt = async () => {
if (!encryptResult) return;
try {
await publicDecrypt(encryptResult.ciphertext, 'euint32');
} catch (error) {
console.error('Decryption failed:', error);
}
};
if (isInitializing) return <div>Initializing FHEVM SDK...</div>;
if (!isInitialized) return <div>Failed to initialize SDK</div>;
return (
<div>
<input
type="number"
value={value}
onChange={(e) => setValue(e.target.value)}
placeholder="Enter a number"
/>
<button onClick={handleEncrypt} disabled={isEncrypting}>
{isEncrypting ? 'Encrypting...' : 'Encrypt Value'}
</button>
{encryptResult && (
<div>
<p>Encrypted: {encryptResult.ciphertext}</p>
<button onClick={handleDecrypt} disabled={isDecrypting}>
{isDecrypting ? 'Decrypting...' : 'Decrypt'}
</button>
</div>
)}
{decryptResult && (
<div>
<p>Decrypted value: {decryptResult.value.toString()}</p>
</div>
)}
</div>
);
}Wrap your application with the FhevmProvider:
'use client';
import { ReactNode } from 'react';
import { FhevmProvider } from '@fhevm/sdk/react';
export function Providers({ children }: { children: ReactNode }) {
return (
<FhevmProvider
config={{
network: 'sepolia',
gatewayUrl: 'https://gateway.zama.ai',
debug: true,
}}
>
{children}
</FhevmProvider>
);
}
// In your root layout or app component
function App() {
return (
<Providers>
<EncryptionExample />
</Providers>
);
}For production Next.js 14 applications with FHEVM SDK, use this recommended structure:
src/
βββ app/ # Next.js App Router
β βββ layout.tsx # Root layout with providers
β βββ page.tsx # Home page
β βββ globals.css # Global styles
β βββ api/ # API routes
β βββ fhe/
β β βββ route.ts # FHE operations
β β βββ encrypt/route.ts # Encryption endpoint
β β βββ decrypt/route.ts # Decryption endpoint
β β βββ compute/route.ts # Computation endpoint
β βββ keys/route.ts # Key management
β
βββ components/ # React components
β βββ ui/ # Base UI components
β β βββ Button.tsx
β β βββ Input.tsx
β β βββ Card.tsx
β βββ fhe/ # FHE feature components
β β βββ FHEProvider.tsx # FHE context provider
β β βββ EncryptionDemo.tsx # Encryption demo
β β βββ ComputationDemo.tsx # Computation demo
β β βββ KeyManager.tsx # Key manager
β βββ examples/ # Use case examples
β βββ BankingExample.tsx # Financial use case
β βββ MedicalExample.tsx # Healthcare use case
β
βββ lib/ # Utility libraries
β βββ fhe/ # FHE integration
β β βββ client.ts # Client-side FHE
β β βββ server.ts # Server-side FHE
β β βββ keys.ts # Key management
β β βββ types.ts # Type definitions
β βββ utils/ # Utility functions
β βββ security.ts # Security utilities
β βββ validation.ts # Validation utilities
β
βββ hooks/ # Custom hooks
β βββ useFHE.ts # FHE operations hook
β βββ useEncryption.ts # Encryption hook
β βββ useComputation.ts # Computation hook
β
βββ types/ # TypeScript types
β βββ fhe.ts # FHE-related types
β βββ api.ts # API type definitions
β
βββ styles/ # Style files
βββ globals.css
1. Root Layout (src/app/layout.tsx)
import { Providers } from './providers';
import '../styles/globals.css';
export const metadata = {
title: 'FHEVM Application',
description: 'Privacy-preserving application using FHEVM',
};
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en">
<body>
<Providers>{children}</Providers>
</body>
</html>
);
}2. Providers Setup (src/app/providers.tsx)
'use client';
import { ReactNode } from 'react';
import { FhevmProvider } from '@fhevm/sdk/react';
export function Providers({ children }: { children: ReactNode }) {
return (
<FhevmProvider
config={{
network: 'sepolia',
gatewayUrl: 'https://gateway.zama.ai',
debug: process.env.NODE_ENV === 'development',
}}
>
{children}
</FhevmProvider>
);
}3. Client-Side FHE Library (src/lib/fhe/client.ts)
import { initFhevm } from '@fhevm/sdk/core';
import type { FhevmClient, EncryptedValue } from '@fhevm/sdk/types';
let fhevmInstance: FhevmClient | null = null;
export async function getFhevmClient(): Promise<FhevmClient> {
if (!fhevmInstance) {
fhevmInstance = await initFhevm({
network: 'sepolia',
gatewayUrl: process.env.NEXT_PUBLIC_GATEWAY_URL || 'https://gateway.zama.ai',
debug: process.env.NODE_ENV === 'development',
});
}
return fhevmInstance;
}
export async function encryptValue(
value: number,
type: 'euint8' | 'euint16' | 'euint32' = 'euint32'
): Promise<EncryptedValue> {
const client = await getFhevmClient();
return client.encrypt(value, type);
}
export async function decryptValue(
ciphertext: string,
type: string
): Promise<bigint> {
const client = await getFhevmClient();
const result = await client.publicDecrypt(ciphertext, type);
return result.value;
}4. Custom FHE Hook (src/hooks/useFHE.ts)
'use client';
import { useState, useCallback } from 'react';
import { encryptValue, decryptValue } from '@/lib/fhe/client';
import { useFhevm } from '@fhevm/sdk/react';
export function useFHE() {
const { isInitialized, isInitializing } = useFhevm();
const [isProcessing, setIsProcessing] = useState(false);
const [error, setError] = useState<Error | null>(null);
const encrypt = useCallback(async (value: number, type: 'euint8' | 'euint16' | 'euint32' = 'euint32') => {
setIsProcessing(true);
setError(null);
try {
const result = await encryptValue(value, type);
return result;
} catch (err) {
const error = err instanceof Error ? err : new Error('Encryption failed');
setError(error);
throw error;
} finally {
setIsProcessing(false);
}
}, []);
const decrypt = useCallback(async (ciphertext: string, type: string) => {
setIsProcessing(true);
setError(null);
try {
const result = await decryptValue(ciphertext, type);
return result;
} catch (err) {
const error = err instanceof Error ? err : new Error('Decryption failed');
setError(error);
throw error;
} finally {
setIsProcessing(false);
}
}, []);
return {
encrypt,
decrypt,
isProcessing,
isInitialized,
isInitializing,
error,
};
}5. Encryption Component (src/components/fhe/EncryptionDemo.tsx)
'use client';
import { useState } from 'react';
import { useEncrypt, useDecrypt } from '@fhevm/sdk/react';
export function EncryptionDemo() {
const [value, setValue] = useState('42');
const [type, setType] = useState<'euint8' | 'euint16' | 'euint32'>('euint32');
const { encrypt, isEncrypting, result: encryptResult, error: encryptError } = useEncrypt();
const { publicDecrypt, isDecrypting, result: decryptResult, error: decryptError } = useDecrypt();
const handleEncrypt = async () => {
try {
await encrypt(Number(value), type);
} catch (error) {
console.error('Encryption failed:', error);
}
};
const handleDecrypt = async () => {
if (!encryptResult) return;
try {
await publicDecrypt(encryptResult.ciphertext, type);
} catch (error) {
console.error('Decryption failed:', error);
}
};
return (
<div className="space-y-6 p-6 bg-white rounded-lg shadow-lg">
<h2 className="text-2xl font-bold">FHE Encryption Demo</h2>
<div className="space-y-4">
<div>
<label className="block text-sm font-medium mb-2">
Value to Encrypt
</label>
<input
type="number"
value={value}
onChange={(e) => setValue(e.target.value)}
className="w-full px-4 py-2 border rounded-lg"
placeholder="Enter a number"
/>
</div>
<div>
<label className="block text-sm font-medium mb-2">
FHE Type
</label>
<select
value={type}
onChange={(e) => setType(e.target.value as any)}
className="w-full px-4 py-2 border rounded-lg"
>
<option value="euint8">euint8 (0-255)</option>
<option value="euint16">euint16 (0-65535)</option>
<option value="euint32">euint32</option>
</select>
</div>
<button
onClick={handleEncrypt}
disabled={isEncrypting}
className="w-full px-6 py-3 bg-blue-600 text-white rounded-lg hover:bg-blue-700 disabled:opacity-50"
>
{isEncrypting ? 'Encrypting...' : 'Encrypt Value'}
</button>
{encryptError && (
<div className="p-4 bg-red-100 border border-red-300 rounded-lg">
<p className="text-red-700">Error: {encryptError.message}</p>
</div>
)}
{encryptResult && (
<div className="p-4 bg-green-100 border border-green-300 rounded-lg">
<h3 className="font-semibold mb-2">Encrypted Result:</h3>
<p className="break-all font-mono text-sm">{encryptResult.ciphertext}</p>
<p className="mt-2 text-sm">Type: {encryptResult.type}</p>
<button
onClick={handleDecrypt}
disabled={isDecrypting}
className="mt-4 px-6 py-2 bg-purple-600 text-white rounded-lg hover:bg-purple-700 disabled:opacity-50"
>
{isDecrypting ? 'Decrypting...' : 'Decrypt'}
</button>
</div>
)}
{decryptResult && (
<div className="p-4 bg-purple-100 border border-purple-300 rounded-lg">
<h3 className="font-semibold mb-2">Decrypted Result:</h3>
<p className="text-2xl font-bold">{decryptResult.value.toString()}</p>
</div>
)}
</div>
</div>
);
}6. API Route for Encryption (src/app/api/fhe/encrypt/route.ts)
import { NextRequest, NextResponse } from 'next/server';
import { initFhevm } from '@fhevm/sdk/core';
export async function POST(request: NextRequest) {
try {
const { value, type } = await request.json();
if (typeof value !== 'number' || !type) {
return NextResponse.json(
{ error: 'Invalid input' },
{ status: 400 }
);
}
const fhevm = await initFhevm({
network: 'sepolia',
gatewayUrl: process.env.GATEWAY_URL || 'https://gateway.zama.ai',
});
const encrypted = await fhevm.encrypt(value, type);
return NextResponse.json({
success: true,
data: encrypted,
});
} catch (error) {
console.error('Encryption error:', error);
return NextResponse.json(
{ error: 'Encryption failed' },
{ status: 500 }
);
}
}7. Main Page (src/app/page.tsx)
'use client';
import { EncryptionDemo } from '@/components/fhe/EncryptionDemo';
import { useFhevm } from '@fhevm/sdk/react';
export default function Home() {
const { isInitialized, isInitializing } = useFhevm();
if (isInitializing) {
return (
<div className="min-h-screen flex items-center justify-center">
<div className="text-xl">Initializing FHEVM SDK...</div>
</div>
);
}
if (!isInitialized) {
return (
<div className="min-h-screen flex items-center justify-center">
<div className="text-xl text-red-600">Failed to initialize FHEVM SDK</div>
</div>
);
}
return (
<main className="min-h-screen p-8 bg-gradient-to-br from-blue-50 to-indigo-100">
<div className="max-w-4xl mx-auto">
<h1 className="text-4xl font-bold text-center mb-8">
FHEVM Application
</h1>
<EncryptionDemo />
</div>
</main>
);
}Create a .env.local file:
NEXT_PUBLIC_GATEWAY_URL=https://gateway.zama.ai
NEXT_PUBLIC_NETWORK=sepolia
GATEWAY_URL=https://gateway.zama.aiDecryption API (src/app/api/fhe/decrypt/route.ts)
import { NextRequest, NextResponse } from 'next/server';
import { initFhevm } from '@fhevm/sdk/core';
export async function POST(request: NextRequest) {
try {
const { ciphertext, type, signature, contractAddress } = await request.json();
if (!ciphertext || !type) {
return NextResponse.json(
{ error: 'Missing required fields' },
{ status: 400 }
);
}
const fhevm = await initFhevm({
network: 'sepolia',
gatewayUrl: process.env.GATEWAY_URL || 'https://gateway.zama.ai',
});
let result;
if (signature && contractAddress) {
// User decryption with EIP-712 signature
result = await fhevm.userDecrypt(ciphertext, type, signature, contractAddress);
} else {
// Public decryption
result = await fhevm.publicDecrypt(ciphertext, type);
}
return NextResponse.json({
success: true,
data: {
value: result.value.toString(),
type: result.type,
},
});
} catch (error) {
console.error('Decryption error:', error);
return NextResponse.json(
{ error: 'Decryption failed' },
{ status: 500 }
);
}
}Computation API (src/app/api/fhe/compute/route.ts)
import { NextRequest, NextResponse } from 'next/server';
import { initFhevm } from '@fhevm/sdk/core';
export async function POST(request: NextRequest) {
try {
const { operation, operands, types } = await request.json();
if (!operation || !operands || !types) {
return NextResponse.json(
{ error: 'Missing required fields' },
{ status: 400 }
);
}
const fhevm = await initFhevm({
network: 'sepolia',
gatewayUrl: process.env.GATEWAY_URL || 'https://gateway.zama.ai',
});
// Encrypt operands
const encryptedOperands = await Promise.all(
operands.map((value: number, index: number) =>
fhevm.encrypt(value, types[index])
)
);
return NextResponse.json({
success: true,
data: {
operation,
encryptedOperands: encryptedOperands.map(op => ({
ciphertext: op.ciphertext,
type: op.type,
})),
},
});
} catch (error) {
console.error('Computation error:', error);
return NextResponse.json(
{ error: 'Computation failed' },
{ status: 500 }
);
}
}Key Manager Component (src/components/fhe/KeyManager.tsx)
'use client';
import { useState } from 'react';
import { useFhevm } from '@fhevm/sdk/react';
export function KeyManager() {
const { fhevm, isInitialized } = useFhevm();
const [publicKey, setPublicKey] = useState<string | null>(null);
const [loading, setLoading] = useState(false);
const handleGetPublicKey = async () => {
if (!fhevm) return;
setLoading(true);
try {
// Get the public key from FHEVM instance
const key = await fhevm.getPublicKey();
setPublicKey(key);
} catch (error) {
console.error('Failed to get public key:', error);
} finally {
setLoading(false);
}
};
if (!isInitialized) {
return <div>FHEVM not initialized</div>;
}
return (
<div className="p-6 bg-white rounded-lg shadow-lg">
<h2 className="text-2xl font-bold mb-4">Key Management</h2>
<button
onClick={handleGetPublicKey}
disabled={loading}
className="px-6 py-3 bg-green-600 text-white rounded-lg hover:bg-green-700 disabled:opacity-50"
>
{loading ? 'Loading...' : 'Get Public Key'}
</button>
{publicKey && (
<div className="mt-4 p-4 bg-gray-100 rounded-lg">
<h3 className="font-semibold mb-2">Public Key:</h3>
<p className="break-all font-mono text-sm">{publicKey}</p>
</div>
)}
</div>
);
}Computation Demo Component (src/components/fhe/ComputationDemo.tsx)
'use client';
import { useState } from 'react';
import { useEncrypt } from '@fhevm/sdk/react';
export function ComputationDemo() {
const [value1, setValue1] = useState('10');
const [value2, setValue2] = useState('20');
const [operation, setOperation] = useState<'add' | 'sub' | 'mul'>('add');
const { encrypt, isEncrypting } = useEncrypt();
const [results, setResults] = useState<any>(null);
const handleCompute = async () => {
try {
// Encrypt both values
const encrypted1 = await encrypt(Number(value1), 'euint32');
const encrypted2 = await encrypt(Number(value2), 'euint32');
setResults({
operation,
operand1: encrypted1,
operand2: encrypted2,
});
} catch (error) {
console.error('Computation failed:', error);
}
};
return (
<div className="space-y-6 p-6 bg-white rounded-lg shadow-lg">
<h2 className="text-2xl font-bold">FHE Computation Demo</h2>
<div className="space-y-4">
<div className="grid grid-cols-2 gap-4">
<div>
<label className="block text-sm font-medium mb-2">
First Value
</label>
<input
type="number"
value={value1}
onChange={(e) => setValue1(e.target.value)}
className="w-full px-4 py-2 border rounded-lg"
/>
</div>
<div>
<label className="block text-sm font-medium mb-2">
Second Value
</label>
<input
type="number"
value={value2}
onChange={(e) => setValue2(e.target.value)}
className="w-full px-4 py-2 border rounded-lg"
/>
</div>
</div>
<div>
<label className="block text-sm font-medium mb-2">
Operation
</label>
<select
value={operation}
onChange={(e) => setOperation(e.target.value as any)}
className="w-full px-4 py-2 border rounded-lg"
>
<option value="add">Addition (+)</option>
<option value="sub">Subtraction (-)</option>
<option value="mul">Multiplication (Γ)</option>
</select>
</div>
<button
onClick={handleCompute}
disabled={isEncrypting}
className="w-full px-6 py-3 bg-indigo-600 text-white rounded-lg hover:bg-indigo-700 disabled:opacity-50"
>
{isEncrypting ? 'Computing...' : 'Encrypt and Compute'}
</button>
{results && (
<div className="p-4 bg-indigo-100 border border-indigo-300 rounded-lg">
<h3 className="font-semibold mb-2">Encrypted Operands:</h3>
<div className="space-y-2 text-sm">
<p>
<strong>Operation:</strong> {results.operation}
</p>
<p className="break-all">
<strong>Operand 1:</strong> {results.operand1?.ciphertext}
</p>
<p className="break-all">
<strong>Operand 2:</strong> {results.operand2?.ciphertext}
</p>
</div>
</div>
)}
</div>
</div>
);
}Banking Example Component (src/components/examples/BankingExample.tsx)
'use client';
import { useState } from 'react';
import { useEncrypt, useDecrypt } from '@fhevm/sdk/react';
export function BankingExample() {
const [balance, setBalance] = useState('1000');
const [amount, setAmount] = useState('100');
const { encrypt, isEncrypting, result: encryptedBalance } = useEncrypt();
const { publicDecrypt, result: decryptedBalance } = useDecrypt();
const handleEncryptBalance = async () => {
await encrypt(Number(balance), 'euint32');
};
const handleCheckBalance = async () => {
if (encryptedBalance) {
await publicDecrypt(encryptedBalance.ciphertext, 'euint32');
}
};
return (
<div className="p-6 bg-white rounded-lg shadow-lg">
<h2 className="text-2xl font-bold mb-4">
π¦ Private Banking Example
</h2>
<p className="text-gray-600 mb-6">
Encrypt account balance and perform private transactions
</p>
<div className="space-y-4">
<div>
<label className="block text-sm font-medium mb-2">
Account Balance
</label>
<input
type="number"
value={balance}
onChange={(e) => setBalance(e.target.value)}
className="w-full px-4 py-2 border rounded-lg"
/>
</div>
<button
onClick={handleEncryptBalance}
disabled={isEncrypting}
className="w-full px-6 py-3 bg-green-600 text-white rounded-lg hover:bg-green-700 disabled:opacity-50"
>
{isEncrypting ? 'Encrypting...' : 'Encrypt Balance'}
</button>
{encryptedBalance && (
<div className="p-4 bg-green-100 border border-green-300 rounded-lg">
<p className="text-sm font-medium mb-2">Encrypted Balance:</p>
<p className="break-all font-mono text-xs">
{encryptedBalance.ciphertext}
</p>
<button
onClick={handleCheckBalance}
className="mt-3 px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700"
>
Check Balance
</button>
</div>
)}
{decryptedBalance && (
<div className="p-4 bg-blue-100 border border-blue-300 rounded-lg">
<p className="text-sm font-medium">Current Balance:</p>
<p className="text-2xl font-bold">${decryptedBalance.value.toString()}</p>
</div>
)}
</div>
</div>
);
}export interface EncryptedValue {
ciphertext: string;
type: string;
timestamp: number;
}
export interface DecryptedValue {
value: bigint;
type: string;
timestamp: number;
}
export interface FhevmConfig {
network: 'sepolia' | 'mainnet';
gatewayUrl: string;
debug?: boolean;
}
export interface ComputationRequest {
operation: 'add' | 'sub' | 'mul' | 'div';
operands: number[];
types: string[];
}
export interface ComputationResult {
operation: string;
encryptedOperands: EncryptedValue[];
result?: EncryptedValue;
}{
"name": "fhevm-nextjs-app",
"version": "1.0.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint"
},
"dependencies": {
"@fhevm/sdk": "^1.0.0",
"next": "^14.2.0",
"react": "^18.3.0",
"react-dom": "^18.3.0"
},
"devDependencies": {
"@types/node": "^20.0.0",
"@types/react": "^18.3.0",
"@types/react-dom": "^18.3.0",
"typescript": "^5.3.0",
"autoprefixer": "^10.4.0",
"postcss": "^8.4.0",
"tailwindcss": "^3.4.0"
}
}<script setup lang="ts">
import { ref, onMounted } from 'vue';
import { initFhevm } from '@fhevm/sdk/core';
const fhevm = ref(null);
const encrypted = ref(null);
const decrypted = ref(null);
const isEncrypting = ref(false);
const isDecrypting = ref(false);
const inputValue = ref(42);
onMounted(async () => {
fhevm.value = await initFhevm({
network: 'sepolia',
gatewayUrl: 'https://gateway.zama.ai',
});
});
async function encryptValue() {
isEncrypting.value = true;
try {
encrypted.value = await fhevm.value.encrypt(inputValue.value, 'euint32');
} finally {
isEncrypting.value = false;
}
}
async function decryptValue() {
if (!encrypted.value) return;
isDecrypting.value = true;
try {
decrypted.value = await fhevm.value.publicDecrypt(
encrypted.value.ciphertext,
'euint32'
);
} finally {
isDecrypting.value = false;
}
}
</script>
<template>
<div>
<input v-model.number="inputValue" type="number" />
<button @click="encryptValue" :disabled="isEncrypting">
{{ isEncrypting ? 'Encrypting...' : 'Encrypt' }}
</button>
<div v-if="encrypted">
<p>Encrypted: {{ encrypted.ciphertext }}</p>
<button @click="decryptValue" :disabled="isDecrypting">
{{ isDecrypting ? 'Decrypting...' : 'Decrypt' }}
</button>
</div>
<div v-if="decrypted">
<p>Decrypted: {{ decrypted.value }}</p>
</div>
</div>
</template>import { initFhevm } from '@fhevm/sdk/core';
async function main() {
// Initialize SDK
const fhevm = await initFhevm({
network: 'sepolia',
gatewayUrl: 'https://gateway.zama.ai',
});
// Encrypt a value
const encrypted = await fhevm.encrypt(1234, 'euint32');
console.log('Encrypted:', encrypted.ciphertext);
// Public decrypt (for testing/backend scenarios)
const decrypted = await fhevm.publicDecrypt(
encrypted.ciphertext,
'euint32'
);
console.log('Decrypted:', decrypted.value);
}
main().catch(console.error);// Initialize
const fhevm = await initFhevm(config: FhevmConfig): Promise<FhevmClient>
// Configuration
interface FhevmConfig {
network: 'sepolia' | 'mainnet';
gatewayUrl: string;
debug?: boolean;
}
// Encryption
const result = await fhevm.encrypt(
value: number | bigint,
type: 'euint8' | 'euint16' | 'euint32' | 'euint64' | 'euint128'
): Promise<EncryptedValue>
// Public Decryption (no signature)
const decrypted = await fhevm.publicDecrypt(
ciphertext: string,
type: string
): Promise<DecryptedValue>
// User Decryption (with EIP-712 signature)
const decrypted = await fhevm.userDecrypt(
ciphertext: string,
type: string,
signature: string,
contractAddress: string
): Promise<DecryptedValue>// Provider
<FhevmProvider config={config}>
{children}
</FhevmProvider>
// Initialization Hook
const {
isInitialized: boolean,
isInitializing: boolean,
error: Error | null,
fhevm: FhevmClient | null
} = useFhevm()
// Encryption Hook
const {
encrypt: (value: number, type: string) => Promise<void>,
isEncrypting: boolean,
result: EncryptedValue | null,
error: Error | null,
reset: () => void
} = useEncrypt()
// Decryption Hook
const {
publicDecrypt: (ciphertext: string, type: string) => Promise<void>,
userDecrypt: (ciphertext: string, type: string, signature: string) => Promise<void>,
isDecrypting: boolean,
result: DecryptedValue | null,
error: Error | null,
reset: () => void
} = useDecrypt()interface EncryptedValue {
ciphertext: string; // Hex-encoded encrypted data
type: string; // FHE type (euint8, euint16, etc.)
timestamp: number; // Encryption timestamp
}
interface DecryptedValue {
value: bigint; // Decrypted value
type: string; // FHE type
timestamp: number; // Decryption timestamp
}All examples are located in the examples/ directory and demonstrate different ways to integrate the FHEVM SDK.
A complete Next.js 14 application showcasing the FHEVM SDK with App Router:
Features:
- Full FHEVM SDK integration with React hooks
- Interactive encryption/decryption UI
- Support for multiple FHE types (euint8, euint16, euint32)
- Real-time state management with loading indicators
- Beautiful gradient UI with Tailwind CSS
- TypeScript support with full type safety
- Complete API routes for server-side operations
- Reusable FHE components and custom hooks
- Banking and medical use case examples
Running the Example:
# From the root directory
npm install
npm run dev:nextjs
# Or from the example directory
cd examples/nextjs-demo
npm install
npm run devVisit http://localhost:3000 to see the demo in action.
Key Files:
src/app/providers.tsx- FhevmProvider setupsrc/app/page.tsx- Main component using SDK hookssrc/app/api/fhe/- API routes for encryption/decryptionsrc/components/fhe/- Reusable FHE componentssrc/lib/fhe/- FHE utility functionssrc/hooks/- Custom React hooks
A production-ready privacy-preserving rental matching platform built with vanilla HTML/JS:
Features:
- Anonymous property listings with encrypted data
- Encrypted matching algorithm
- User and public decryption workflows
- EIP-712 signature integration for secure decryption
- Production-ready deployment configuration
Use Case: Landlords and tenants can match without revealing sensitive information (prices, locations) until both parties confirm mutual interest.
Live Demo: https://simple-rental-matching.vercel.app/
A modern React implementation of the privacy-preserving rental matching platform:
Features:
- Built with React 18 and TypeScript for type safety
- Vite for fast development and optimized builds
- Custom React hooks for wallet and contract interactions
- Component-based architecture for better code organization
- Real-time event listeners for instant updates
- Responsive design that works on all devices
- Full integration with Ethers.js 6
- FHE encryption for all sensitive data
Tech Stack:
- React 18 with TypeScript
- Vite build tool
- Ethers.js 6 for blockchain interaction
- FHEVM for fully homomorphic encryption
- CSS3 for styling
Running the React Version:
# From the root directory
cd examples/rental-matching-react
# Install dependencies (if not using workspace)
npm install
# Start development server
npm run dev
# Build for production
npm run buildVisit http://localhost:3000 to see the React application.
Key Improvements over HTML Version:
- Better code organization with reusable components
- Type safety with TypeScript
- Custom hooks for cleaner state management
- Improved developer experience with hot reload
- Better testability and maintainability
- Optimized production builds
The examples/README.md file contains additional integration patterns including:
- React 18 standalone example
- Vue 3 Composition API integration
- Node.js backend integration
- Vanilla JavaScript usage
Explore the Examples:
# View all examples
ls examples/
# Read the examples documentation
cat examples/README.mdThe primary example demonstrates all SDK features in a Next.js 14 application:
# Option 1: Run from root with npm script
npm run dev:nextjs
# Option 2: Run directly from example directory
cd examples/nextjs-demo
npm install
npm run devOpen http://localhost:3000 to see:
- Interactive encryption/decryption interface
- Multiple FHE type support (euint8, euint16, euint32)
- Real-time loading states and error handling
- Full TypeScript integration
The Next.js example showcases the recommended integration pattern:
1. Provider Setup (examples/nextjs-demo/src/app/providers.tsx)
import { FhevmProvider } from '@fhevm/sdk/react';
export function Providers({ children }) {
return (
<FhevmProvider config={{
network: 'sepolia',
gatewayUrl: 'https://gateway.zama.ai'
}}>
{children}
</FhevmProvider>
);
}2. Using Hooks (examples/nextjs-demo/src/app/page.tsx)
import { useFhevm, useEncrypt, useDecrypt } from '@fhevm/sdk/react';
export default function Home() {
const { isInitialized } = useFhevm();
const { encrypt, isEncrypting, result } = useEncrypt();
const handleEncrypt = async () => {
await encrypt(42, 'euint32');
};
return (
<button onClick={handleEncrypt} disabled={isEncrypting}>
{isEncrypting ? 'Encrypting...' : 'Encrypt'}
</button>
);
}To adapt the examples for your own project:
- Copy the provider setup from
examples/nextjs-demo/src/app/providers.tsx - Import the hooks in your components
- Adjust the configuration (network, gateway URL, contract addresses)
- Add your business logic around encryption/decryption
- Style to match your design system
The examples demonstrate several real-world scenarios:
- Encrypted Forms: User input encryption before submission
- Private Data Storage: Storing sensitive data on-chain
- Selective Disclosure: Decrypting only when authorized
- Batch Operations: Encrypting multiple values efficiently
- BOUNTY_SUBMISSION.md: Complete bounty requirements checklist
- SETUP_GUIDE.md: Detailed installation and configuration
- SDK_DOCUMENTATION.md: Full API reference
- packages/fhevm-sdk/README.md: SDK-specific docs
| Resource | URL |
|---|---|
| GitHub Repository | Your repository URL |
| Demo Videos | Available in repository root |
| Contract Address | 0x980051585b6DC385159BD53B5C78eb7B91b848E5 |
| Sepolia Explorer | https://sepolia.etherscan.io/address/0x980051585b6DC385159BD53B5C78eb7B91b848E5 |
| Examples Directory | ./examples/ |
| SDK Package | ./packages/fhevm-sdk/ |
# Run all tests
npm test
# Run contract tests
npm run test:contracts
# Run SDK tests
npm run test:sdk
# Test coverage
npm run test:coverage- Frontend: Next.js 14, React 18, TypeScript, Tailwind CSS
- Web3: wagmi, viem, RainbowKit
- FHE: Zama fhEVM SDK
- Smart Contracts: Solidity, Hardhat
- Deployment: Vercel
This project is submitted for the Zama FHEVM SDK Bounty.
- Universal SDK package importable into any application
- Initialization, encryption, and decryption utilities
- EIP-712 signature support for userDecrypt
- Wagmi-like modular API structure
- Reusable components for common scenarios
- Clean, well-documented, and extensible code
- Complete setup from root directory
- Example templates with Next.js
- Video demonstration
- Deployment links in README
See BOUNTY_SUBMISSION.md for detailed checklist.
Contributions are welcome! Please follow these steps:
- Fork the repository
- Create a feature branch (git checkout -b feature/amazing-feature)
- Commit your changes (git commit -m 'Add amazing feature')
- Push to the branch (git push origin feature/amazing-feature)
- Open a Pull Request
MIT License - see LICENSE for details.
- Zama for creating fhEVM and hosting this bounty
- wagmi and RainbowKit for API design inspiration
- Next.js team for the excellent framework
- Community for feedback and support
For questions and support:
- Open an issue on GitHub
- Check the documentation
- Explore the examples directory
- Review the SDK documentation
Built for privacy-preserving Web3