A comprehensive monorepo for building privacy-preserving applications with Fully Homomorphic Encryption (FHE) using Zama's FHEVM technology. This project includes an SDK, React Native mobile app, Next.js web app, smart contracts, and relayer service.
FHEVM (Fully Homomorphic Encryption Virtual Machine) enables smart contracts to work with encrypted data without ever decrypting it. This allows for:
- Private transactions - Transfer amounts remain secret
- Confidential balances - Account balances are encrypted on-chain
- Encrypted voting - Vote choices remain private until reveal
- Private auctions - Bids stay secret until auction ends
- And much more...
This monorepo contains:
fhevm-react-native-template/
βββ packages/
β βββ fhevm-sdk/ # Core SDK for React & React Native
β βββ react-native/ # React Native mobile wallet app
β βββ nextjs/ # Next.js web application
β βββ hardhat/ # Smart contracts & deployment
β βββ relayer-service/ # Backend relayer for mobile apps
β βββ docs/ # Docusaurus documentation
βββ test-app/ # Standalone test app
βββ scripts/ # Build and deployment scripts
The core SDK providing React hooks and utilities for FHEVM applications.
Features:
- π Automatic encryption/decryption
- π£ React hooks for contracts, tokens, and operators
- πΎ Caching for optimized performance
- π Universal (React, React Native, Next.js)
- π Full TypeScript support
- π Wagmi-like API design
Installation:
npm install fhevm-sdk
# or
pnpm add fhevm-sdkQuick Start:
import { FhevmProvider, createConfig, useReadContract } from 'fhevm-sdk';
import { sepolia } from 'wagmi/chains';
// 1. Create config
const config = createConfig({
chains: [sepolia],
contracts: {
myToken: {
address: '0x...',
abi: [...],
},
},
});
// 2. Wrap your app
function App() {
return (
<FhevmProvider config={config}>
<YourComponent />
</FhevmProvider>
);
}
// 3. Use hooks
function YourComponent() {
const { decryptedData, isLoading } = useReadContract({
name: 'myToken',
functionName: 'balanceOf',
args: [address],
decrypt: true, // Auto-decrypt encrypted values
});
return <div>Balance: {decryptedData}</div>;
}A mobile wallet application demonstrating FHEVM integration with Reown AppKit (WalletConnect).
Features:
- π Wallet connection via Reown AppKit
- π FHE counter operations (increment/decrement)
- π Relayer-based architecture
- π± Cross-platform (iOS, Android, Web)
- β‘ Real-time encrypted data updates
Quick Start:
cd packages/react-native
bun install
bun startSee React Native Documentation β
A modern web application showcasing FHEVM capabilities.
Features:
- π¨ Beautiful UI with Tailwind CSS
- π FHE Counter Demo
- π° Confidential Token Demo (ERC-20 with encrypted balances)
- π Rainbow Kit integration
- π Real-time decryption
- π― Type-safe with TypeScript
Quick Start:
cd packages/nextjs
pnpm install
pnpm devVisit http://localhost:3000
Smart contracts with FHEVM support.
Included Contracts:
FHECounter.sol- Encrypted counter with increment/decrementConfidentialERC20.sol- ERC-20 with fully encrypted balancesEncryptedVoting.sol- Private voting system
Quick Start:
cd packages/hardhat
pnpm install
pnpm chain # Start local node
pnpm deploy:localhostBackend service for mobile apps to handle FHE operations server-side.
Features:
- π Server-side encryption/decryption
- π Key management
- π‘ RESTful API
- π― Session management
- π‘οΈ Signature verification
Quick Start:
cd packages/relayer-service
cp .env.example .env
# Edit .env with your RPC_URL and PRIVATE_KEY
pnpm relayer:devServer runs on http://localhost:4000
Comprehensive Docusaurus documentation site.
Quick Start:
pnpm docs:startVisit http://localhost:3001
The SDK provides powerful React hooks for FHEVM operations:
useContract- Get a contract instanceuseReadContract- Read from contracts with auto-decryptionuseWriteContract- Write to contracts with auto-encryptionuseDecryptedValue- Decrypt encrypted handles
useTokenBalance- Read token balances (standard or confidential)useTokenTransfer- Transfer tokens with automatic encryption
useOperator- Manage operator permissionsuseBatchTransactions- Batch multiple transactions
useFhevm- Initialize FHEVM instanceuseFHEEncryption- Encrypt datauseFHEDecrypt- Decrypt datauseFheCounter- Counter operationsuseRemoteFheCounter- Remote counter (via relayer)
Before you begin, ensure you have:
- Node.js >= 20.0.0
- pnpm (recommended) or npm
- MetaMask browser extension
- Git for cloning the repository
- For React Native: Expo CLI, Xcode (iOS), or Android Studio (Android)
- Clone the repository:
git clone <repository-url>
cd fhevm-react-native-template- Install dependencies:
pnpm install- Build the SDK:
pnpm sdk:buildpnpm chainpnpm deploy:localhostpnpm startVisit http://localhost:3000
pnpm mobile
# or
pnpm mobile:ios
pnpm mobile:androidpnpm relayer:devCreate a config with your chains and contracts:
import { createConfig } from 'fhevm-sdk';
import { sepolia } from 'wagmi/chains';
const config = createConfig({
chains: [sepolia],
contracts: {
myToken: {
address: '0xYourContractAddress',
abi: [...],
},
},
cache: {
enabled: true,
ttl: 60000, // 1 minute
},
});NEXT_PUBLIC_WALLET_CONNECT_PROJECT_ID=your_project_id
NEXT_PUBLIC_ALCHEMY_API_KEY=your_alchemy_keyEXPO_PUBLIC_REOWN_PROJECT_ID=your_project_idRPC_URL=https://sepolia.infura.io/v3/YOUR_KEY
PRIVATE_KEY=your_relayer_private_key
PORT=4000import { useReadContract, useWriteContract } from 'fhevm-sdk';
function Counter() {
// Read encrypted counter
const { decryptedData: count, isDecrypting } = useReadContract({
name: 'FHECounter',
functionName: 'getCounter',
args: [userAddress],
decrypt: true,
});
// Write to counter
const { write: increment, isLoading } = useWriteContract({
name: 'FHECounter',
});
return (
<div>
<p>Count: {isDecrypting ? '...' : count}</p>
<button
onClick={() => increment({ functionName: 'increment' })}
disabled={isLoading}
>
Increment
</button>
</div>
);
}import { useTokenBalance, useTokenTransfer } from 'fhevm-sdk';
function TokenWallet({ address }) {
// Read encrypted balance
const { balanceFormatted, isDecrypting, refetch } = useTokenBalance({
name: 'ConfidentialToken',
account: address,
isConfidential: true,
});
// Transfer tokens
const { transfer, isLoading } = useTokenTransfer({
name: 'ConfidentialToken',
isConfidential: true,
});
const handleTransfer = async () => {
await transfer({
to: '0xRecipient...',
amount: '100',
decimals: 18,
});
await refetch();
};
return (
<div>
<p>Balance: {isDecrypting ? 'Decrypting...' : balanceFormatted}</p>
<button onClick={handleTransfer} disabled={isLoading}>
Transfer 100 Tokens
</button>
</div>
);
}import { useFhevmClient, useRemoteFheCounter } from 'fhevm-sdk';
function MobileCounter({ contractAddress, contractAbi }) {
const { client, isReady } = useFhevmClient({
contractAddress,
contractAbi,
contractName: 'FHECounter',
relayerBaseUrl: 'http://localhost:4000',
});
const { value, increment, decrement, refresh, isMutating } =
useRemoteFheCounter({ client });
if (!isReady) return <Text>Loading...</Text>;
return (
<View>
<Text>Counter: {value ?? 'Loading...'}</Text>
<Button title="+" onPress={increment} disabled={isMutating} />
<Button title="-" onPress={decrement} disabled={isMutating} />
<Button title="Refresh" onPress={refresh} />
</View>
);
}βββββββββββββββ
β Next.js β
β App β
ββββββββ¬βββββββ
β
β uses hooks
βΌ
βββββββββββββββ ββββββββββββββββ
β fhevm-sdk ββββββββ€ FHEVM Instanceβ
β Hooks β β (fhevmjs) β
ββββββββ¬βββββββ ββββββββββββββββ
β
β encrypts/decrypts
βΌ
βββββββββββββββ
β Ethereum β
β Network β
βββββββββββββββ
βββββββββββββββ
βReact Native β
β App β
ββββββββ¬βββββββ
β
β HTTP requests
βΌ
βββββββββββββββ ββββββββββββββββ
β Relayer ββββββββ€ FHEVM Instanceβ
β Service β β (fhevmjs) β
ββββββββ¬βββββββ ββββββββββββββββ
β
β encrypts/decrypts
βΌ
βββββββββββββββ
β Ethereum β
β Network β
βββββββββββββββ
- Local Development: Hardhat local node (chainId: 31337)
- Testnet: Sepolia (chainId: 11155111)
- Zama Devnet: (chainId: 8009)
const customNetwork = {
id: 12345,
name: 'Custom Network',
network: 'custom',
nativeCurrency: {
decimals: 18,
name: 'Ether',
symbol: 'ETH',
},
rpcUrls: {
default: { http: ['https://rpc.custom.network'] },
},
blockExplorers: {
default: { name: 'Explorer', url: 'https://explorer.custom.network' },
},
};
const config = createConfig({
chains: [customNetwork],
// ...
});# SDK Development
pnpm sdk:build # Build SDK
pnpm sdk:watch # Watch mode
pnpm sdk:test # Run tests
pnpm sdk:clean # Clean build
# Blockchain
pnpm chain # Start local node
pnpm deploy:localhost # Deploy to local
pnpm deploy:sepolia # Deploy to Sepolia
# Applications
pnpm start # Start Next.js
pnpm mobile # Start React Native
pnpm relayer:dev # Start relayer
# Documentation
pnpm docs:start # Start docs
pnpm docs:build # Build docs
# Testing
pnpm test # Run all tests
pnpm lint # Lint code# Unit tests
pnpm sdk:test
# Contract tests
pnpm hardhat:test
# Watch mode
pnpm sdk:test:watch# Build SDK
pnpm sdk:build
# Build Next.js
pnpm next:build
# Build docs
pnpm docs:buildThis is expected in React Native. The SDK uses mocks for web-only dependencies. Make sure you have the metro.config.js properly configured.
Run pnpm install or bun install in the react-native package.
- Check that the relayer service is running on the correct port
- For Android emulator, use
http://10.0.2.2:4000 - For iOS simulator, use
http://localhost:4000 - For physical devices, use your computer's local IP address
- Check firewall settings if using physical device
- Ensure you have approved the decryption signature request
- Check that you're connected to the correct network
- Verify the contract address is correct
- Clear cache and retry
Problem: MetaMask tracks transaction nonces, but when you restart Hardhat, the node resets while MetaMask doesn't update its tracking.
Solution:
- Open MetaMask extension
- Select the Hardhat network
- Go to Settings β Advanced
- Click "Clear Activity Tab" (red button)
- This resets MetaMask's nonce tracking
Problem: MetaMask caches smart contract view function results. After restarting Hardhat, you may see outdated data.
Solution:
- Restart your entire browser (not just refresh the page)
- MetaMask's cache is stored in extension memory and requires a full browser restart to clear
π‘ Pro Tip: Always restart your browser after restarting Hardhat to avoid cache issues.
Enable debug logging:
// In your app
localStorage.setItem('DEBUG', 'fhevm:*');Location: packages/fhevm-sdk/
Exports:
FhevmProvider- React context providercreateConfig- Configuration builderuseContract,useReadContract,useWriteContract- Contract hooksuseTokenBalance,useTokenTransfer- Token hooksuseOperator,useBatchTransactions- Utility hooksuseDecryptedValue- Decryption hook- Legacy hooks:
useFhevm,useFHEEncryption,useFHEDecrypt
Location: packages/react-native/
Key Features:
- Reown AppKit integration for wallet connection
- Metro bundler configuration for monorepo
- Mock files for web-only dependencies
- Example implementation with FHE Counter
Location: packages/nextjs/
Key Features:
- Rainbow Kit integration
- FHE Counter Demo
- Confidential Token Demo
- Wagmi integration
- Server-side rendering support
Location: packages/hardhat/
Contracts:
FHECounter.sol- Basic encrypted counterConfidentialERC20.sol- Token with encrypted balances- Deployment scripts for all networks
Location: packages/relayer-service/
API Endpoints:
GET /status- Service status and configurationGET /counter- Read encrypted counter valuePOST /counter- Modify counter value- Session management with signature verification
- FHEVM Documentation - Official FHEVM docs
- Zama.ai - Zama homepage
- fhevmjs Library - Core FHE library
- Reown AppKit - Wallet connection library
- Wagmi Documentation - React hooks for Ethereum
Contributions are welcome! Please read our contributing guidelines before submitting PRs.
- Fork the repository
- Create your 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
This project handles cryptographic operations. Please:
- Never commit private keys
- Use environment variables for sensitive data
- Audit smart contracts before mainnet deployment
- Report security issues privately
BSD-3-Clause-Clear
- Documentation: packages/docs/
- Issues: GitHub Issues
- Discord: Zama Discord
Built with β€οΈ using Zama's FHEVM