();
+
+ const client = getFHEVMClient();
+
+ const initialize = async (initConfig: FHEVMConfig) => {
+ try {
+ setIsLoading(true);
+ setError(undefined);
+
+ const fhevmInstance = await client.initialize(initConfig);
+
+ if (fhevmInstance.status === 'error') {
+ const errorMessage = fhevmInstance.error || 'Failed to initialize FHEVM';
+ setError(errorMessage);
+ onError?.(errorMessage);
+ return;
+ }
+
+ setInstance(fhevmInstance);
+ setIsInitialized(true);
+ onReady?.();
+ } catch (err) {
+ const errorMessage = err instanceof Error ? err.message : 'Unknown error';
+ setError(errorMessage);
+ onError?.(errorMessage);
+ } finally {
+ setIsLoading(false);
+ }
+ };
+
+ // Auto-initialize if config is provided
+ useEffect(() => {
+ if (config && !isInitialized && !isLoading) {
+ initialize(config);
+ }
+ }, [config, isInitialized, isLoading]);
+
+ const contextValue: FHEVMContextType = {
+ instance,
+ isInitialized,
+ isLoading,
+ error,
+ initialize,
+ };
+
+ return (
+
+ {children}
+
+ );
+}
+
+/**
+ * Hook to use FHEVM context
+ */
+export function useFHEVMContext(): FHEVMContextType {
+ const context = useContext(FHEVMContext);
+ if (context === undefined) {
+ throw new Error('useFHEVMContext must be used within a FHEVMProvider');
+ }
+ return context;
+}
+
+/**
+ * Higher-order component for FHEVM
+ */
+export function withFHEVM(
+ Component: React.ComponentType
,
+ config: FHEVMConfig
+) {
+ return function WithFHEVMComponent(props: P) {
+ return (
+
+
+
+ );
+ };
+}
diff --git a/packages/fhevm-sdk/src/adapters/react/components/EncryptButton.tsx b/packages/fhevm-sdk/src/adapters/react/components/EncryptButton.tsx
new file mode 100644
index 00000000..82c8e386
--- /dev/null
+++ b/packages/fhevm-sdk/src/adapters/react/components/EncryptButton.tsx
@@ -0,0 +1,110 @@
+import React, { useState } from 'react';
+import { useFHEVM } from '../useFHEVM';
+
+interface EncryptButtonProps {
+ contractAddress: string;
+ values: (number | bigint | boolean)[];
+ onSuccess?: (result: any) => void;
+ onError?: (error: string) => void;
+ children?: React.ReactNode;
+ className?: string;
+ disabled?: boolean;
+}
+
+/**
+ * Reusable encrypt button component
+ */
+export function EncryptButton({
+ contractAddress,
+ values,
+ onSuccess,
+ onError,
+ children,
+ className = "px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600 disabled:opacity-50",
+ disabled = false,
+}: EncryptButtonProps) {
+ const [isLoading, setIsLoading] = useState(false);
+ const fhevm = useFHEVM();
+
+ const handleEncrypt = async () => {
+ if (!fhevm.isConnected || !fhevm.isInitialized) {
+ onError?.('FHEVM not initialized or wallet not connected');
+ return;
+ }
+
+ try {
+ setIsLoading(true);
+ const result = await fhevm.encrypt(contractAddress, values);
+ onSuccess?.(result);
+ } catch (error) {
+ const errorMessage = error instanceof Error ? error.message : 'Encryption failed';
+ onError?.(errorMessage);
+ } finally {
+ setIsLoading(false);
+ }
+ };
+
+ return (
+
+ );
+}
+
+interface DecryptButtonProps {
+ handles: string[];
+ contractAddress: string;
+ onSuccess?: (result: any) => void;
+ onError?: (error: string) => void;
+ children?: React.ReactNode;
+ className?: string;
+ disabled?: boolean;
+}
+
+/**
+ * Reusable decrypt button component
+ */
+export function DecryptButton({
+ handles,
+ contractAddress,
+ onSuccess,
+ onError,
+ children,
+ className = "px-4 py-2 bg-green-500 text-white rounded hover:bg-green-600 disabled:opacity-50",
+ disabled = false,
+}: DecryptButtonProps) {
+ const [isLoading, setIsLoading] = useState(false);
+ const fhevm = useFHEVM();
+
+ const handleDecrypt = async () => {
+ if (!fhevm.isConnected || !fhevm.isInitialized) {
+ onError?.('FHEVM not initialized or wallet not connected');
+ return;
+ }
+
+ try {
+ setIsLoading(true);
+ const result = await fhevm.decrypt(handles, contractAddress);
+ onSuccess?.(result);
+ } catch (error) {
+ const errorMessage = error instanceof Error ? error.message : 'Decryption failed';
+ onError?.(errorMessage);
+ } finally {
+ setIsLoading(false);
+ }
+ };
+
+ return (
+
+ );
+}
diff --git a/packages/fhevm-sdk/src/adapters/react/useFHEVM.ts b/packages/fhevm-sdk/src/adapters/react/useFHEVM.ts
new file mode 100644
index 00000000..98cc4725
--- /dev/null
+++ b/packages/fhevm-sdk/src/adapters/react/useFHEVM.ts
@@ -0,0 +1,198 @@
+import { useState, useEffect, useCallback, useRef } from 'react';
+import { ethers } from 'ethers';
+import { FHEVMConfig, FHEVMInstance, FHEVMHookReturn, StorageInterface } from '../../types';
+import { getFHEVMClient } from '../../core/fhevm-client';
+import { createEncryptedInput } from '../../core/encryption';
+import { createDecryptionSignature, decryptHandles } from '../../core/decryption';
+
+/**
+ * React hook for FHEVM operations
+ * Provides a wagmi-like API for React applications
+ */
+export function useFHEVM(_config?: FHEVMConfig): FHEVMHookReturn {
+ const [isConnected, setIsConnected] = useState(false);
+ const [isInitialized, setIsInitialized] = useState(false);
+ const [isLoading, setIsLoading] = useState(false);
+ const [error, setError] = useState();
+ const [instance, setInstance] = useState();
+
+ const clientRef = useRef(getFHEVMClient());
+ const storageRef = useRef(null);
+
+ // Initialize storage
+ useEffect(() => {
+ // Create in-memory storage by default
+ storageRef.current = {
+ get: async (key: string) => {
+ try {
+ return localStorage.getItem(key);
+ } catch {
+ return null;
+ }
+ },
+ set: async (key: string, value: string) => {
+ try {
+ localStorage.setItem(key, value);
+ } catch (error) {
+ console.warn('Failed to store data:', error);
+ }
+ },
+ remove: async (key: string) => {
+ try {
+ localStorage.removeItem(key);
+ } catch (error) {
+ console.warn('Failed to remove data:', error);
+ }
+ },
+ };
+ }, []);
+
+ // Connect to wallet
+ const connect = useCallback(async () => {
+ try {
+ setIsLoading(true);
+ setError(undefined);
+
+ if (typeof window === 'undefined' || !window.ethereum) {
+ throw new Error('MetaMask not found. Please install MetaMask.');
+ }
+
+ const provider = new ethers.BrowserProvider(window.ethereum);
+ await provider.getSigner();
+ await provider.getNetwork();
+
+ setIsConnected(true);
+ setIsLoading(false);
+ } catch (err) {
+ const errorMessage = err instanceof Error ? err.message : 'Failed to connect wallet';
+ setError(errorMessage);
+ setIsLoading(false);
+ }
+ }, []);
+
+ // Disconnect wallet
+ const disconnect = useCallback(() => {
+ setIsConnected(false);
+ setIsInitialized(false);
+ setInstance(undefined);
+ setError(undefined);
+ }, []);
+
+ // Initialize FHEVM
+ const initialize = useCallback(async (initConfig: FHEVMConfig) => {
+ try {
+ setIsLoading(true);
+ setError(undefined);
+
+ if (!isConnected) {
+ throw new Error('Wallet not connected');
+ }
+
+ const client = clientRef.current;
+ const fhevmInstance = await client.initialize(initConfig);
+
+ if (fhevmInstance.status === 'error') {
+ throw new Error(fhevmInstance.error || 'Failed to initialize FHEVM');
+ }
+
+ setInstance(fhevmInstance);
+ setIsInitialized(true);
+ setIsLoading(false);
+ } catch (err) {
+ const errorMessage = err instanceof Error ? err.message : 'Failed to initialize FHEVM';
+ setError(errorMessage);
+ setIsLoading(false);
+ }
+ }, [isConnected]);
+
+ // Encrypt values
+ const encrypt = useCallback(async (
+ contractAddress: string,
+ values: (number | bigint | boolean)[]
+ ) => {
+ if (!instance?.instance || !isConnected) {
+ throw new Error('FHEVM not initialized or wallet not connected');
+ }
+
+ try {
+ const provider = new ethers.BrowserProvider(window.ethereum!);
+ const signer = await provider.getSigner();
+ const userAddress = await signer.getAddress();
+
+ const encryptedInput = instance.instance.createEncryptedInput(contractAddress, userAddress);
+ return await createEncryptedInput(encryptedInput, values);
+ } catch (err) {
+ const errorMessage = err instanceof Error ? err.message : 'Encryption failed';
+ setError(errorMessage);
+ throw err;
+ }
+ }, [instance, isConnected]);
+
+ // Decrypt handles
+ const decrypt = useCallback(async (
+ handles: string[],
+ contractAddress: string
+ ) => {
+ if (!instance?.instance || !isConnected || !storageRef.current) {
+ throw new Error('FHEVM not initialized, wallet not connected, or storage not available');
+ }
+
+ try {
+ const provider = new ethers.BrowserProvider(window.ethereum!);
+ const signer = await provider.getSigner();
+
+ const signature = await createDecryptionSignature(
+ instance.instance,
+ [contractAddress],
+ signer,
+ storageRef.current
+ );
+
+ if (!signature) {
+ throw new Error('Failed to create decryption signature');
+ }
+
+ return await decryptHandles(instance.instance, handles, contractAddress, signature);
+ } catch (err) {
+ const errorMessage = err instanceof Error ? err.message : 'Decryption failed';
+ setError(errorMessage);
+ throw err;
+ }
+ }, [instance, isConnected]);
+
+ return {
+ // State
+ isConnected,
+ isInitialized,
+ isLoading,
+ error,
+
+ // Instance
+ instance,
+
+ // Methods
+ connect,
+ disconnect,
+ initialize,
+
+ // FHE Operations
+ encrypt,
+ decrypt,
+ };
+}
+
+/**
+ * Hook for FHEVM with automatic initialization
+ */
+export function useFHEVMWithConfig(config: FHEVMConfig) {
+ const fhevm = useFHEVM(config);
+
+ // Auto-initialize when config is provided
+ useEffect(() => {
+ if (config && fhevm.isConnected && !fhevm.isInitialized && !fhevm.isLoading) {
+ fhevm.initialize(config);
+ }
+ }, [config, fhevm.isConnected, fhevm.isInitialized, fhevm.isLoading]);
+
+ return fhevm;
+}
diff --git a/packages/fhevm-sdk/src/adapters/vue/useFHEVM.ts b/packages/fhevm-sdk/src/adapters/vue/useFHEVM.ts
new file mode 100644
index 00000000..5734d42c
--- /dev/null
+++ b/packages/fhevm-sdk/src/adapters/vue/useFHEVM.ts
@@ -0,0 +1,199 @@
+// Vue imports - only import if Vue is available
+let ref: any, computed: any, watch: any;
+try {
+ const vue = require('vue');
+ ref = vue.ref;
+ computed = vue.computed;
+ watch = vue.watch;
+} catch (e) {
+ // Vue not available, will throw error when used
+}
+import { ethers } from 'ethers';
+import { FHEVMConfig } from '../../types';
+import { getFHEVMClient } from '../../core/fhevm-client';
+import { createEncryptedInput } from '../../core/encryption';
+import { createDecryptionSignature, decryptHandles } from '../../core/decryption';
+
+/**
+ * Vue composable for FHEVM operations
+ * Provides a wagmi-like API for Vue applications
+ */
+export function useFHEVM(config?: FHEVMConfig) {
+ const isConnected = ref(false);
+ const isInitialized = ref(false);
+ const isLoading = ref(false);
+ const error = ref(undefined);
+ const instance = ref(undefined);
+
+ const client = getFHEVMClient();
+ const storage = ref(null);
+
+ // Initialize storage
+ const initStorage = () => {
+ storage.value = {
+ get: async (key: string) => {
+ try {
+ return localStorage.getItem(key);
+ } catch {
+ return null;
+ }
+ },
+ set: async (key: string, value: string) => {
+ try {
+ localStorage.setItem(key, value);
+ } catch (error) {
+ console.warn('Failed to store data:', error);
+ }
+ },
+ remove: async (key: string) => {
+ try {
+ localStorage.removeItem(key);
+ } catch (error) {
+ console.warn('Failed to remove data:', error);
+ }
+ },
+ };
+ };
+
+ // Connect to wallet
+ const connect = async () => {
+ try {
+ isLoading.value = true;
+ error.value = undefined;
+
+ if (typeof window === 'undefined' || !window.ethereum) {
+ throw new Error('MetaMask not found. Please install MetaMask.');
+ }
+
+ const provider = new ethers.BrowserProvider(window.ethereum);
+ await provider.getSigner();
+
+ isConnected.value = true;
+ isLoading.value = false;
+ } catch (err) {
+ const errorMessage = err instanceof Error ? err.message : 'Failed to connect wallet';
+ error.value = errorMessage;
+ isLoading.value = false;
+ }
+ };
+
+ // Disconnect wallet
+ const disconnect = () => {
+ isConnected.value = false;
+ isInitialized.value = false;
+ instance.value = undefined;
+ error.value = undefined;
+ };
+
+ // Initialize FHEVM
+ const initialize = async (initConfig: FHEVMConfig) => {
+ try {
+ isLoading.value = true;
+ error.value = undefined;
+
+ if (!isConnected.value) {
+ throw new Error('Wallet not connected');
+ }
+
+ const fhevmInstance = await client.initialize(initConfig);
+
+ if (fhevmInstance.status === 'error') {
+ throw new Error(fhevmInstance.error || 'Failed to initialize FHEVM');
+ }
+
+ instance.value = fhevmInstance;
+ isInitialized.value = true;
+ isLoading.value = false;
+ } catch (err) {
+ const errorMessage = err instanceof Error ? err.message : 'Failed to initialize FHEVM';
+ error.value = errorMessage;
+ isLoading.value = false;
+ }
+ };
+
+ // Encrypt values
+ const encrypt = async (contractAddress: string, values: (number | bigint | boolean)[]) => {
+ if (!instance.value?.instance || !isConnected.value) {
+ throw new Error('FHEVM not initialized or wallet not connected');
+ }
+
+ try {
+ const provider = new ethers.BrowserProvider(window.ethereum!);
+ const signer = await provider.getSigner();
+ const userAddress = await signer.getAddress();
+
+ const encryptedInput = instance.value.instance.createEncryptedInput(contractAddress, userAddress);
+ return await createEncryptedInput(encryptedInput, values);
+ } catch (err) {
+ const errorMessage = err instanceof Error ? err.message : 'Encryption failed';
+ error.value = errorMessage;
+ throw err;
+ }
+ };
+
+ // Decrypt handles
+ const decrypt = async (handles: string[], contractAddress: string) => {
+ if (!instance.value?.instance || !isConnected.value || !storage.value) {
+ throw new Error('FHEVM not initialized, wallet not connected, or storage not available');
+ }
+
+ try {
+ const provider = new ethers.BrowserProvider(window.ethereum!);
+ const signer = await provider.getSigner();
+
+ const signature = await createDecryptionSignature(
+ instance.value.instance,
+ [contractAddress],
+ signer,
+ storage.value
+ );
+
+ if (!signature) {
+ throw new Error('Failed to create decryption signature');
+ }
+
+ return await decryptHandles(instance.value.instance, handles, contractAddress, signature);
+ } catch (err) {
+ const errorMessage = err instanceof Error ? err.message : 'Decryption failed';
+ error.value = errorMessage;
+ throw err;
+ }
+ };
+
+ // Auto-initialize storage
+ initStorage();
+
+ // Auto-initialize when config is provided
+ watch([config, isConnected], async () => {
+ if (config && isConnected.value && !isInitialized.value && !isLoading.value) {
+ await initialize(config);
+ }
+ });
+
+ return {
+ // State
+ isConnected: computed(() => isConnected.value),
+ isInitialized: computed(() => isInitialized.value),
+ isLoading: computed(() => isLoading.value),
+ error: computed(() => error.value),
+
+ // Instance
+ instance: computed(() => instance.value),
+
+ // Methods
+ connect,
+ disconnect,
+ initialize,
+
+ // FHE Operations
+ encrypt,
+ decrypt,
+ };
+}
+
+/**
+ * Composable for FHEVM with automatic initialization
+ */
+export function useFHEVMWithConfig(config: FHEVMConfig) {
+ return useFHEVM(config);
+}
diff --git a/packages/fhevm-sdk/src/core/decryption.ts b/packages/fhevm-sdk/src/core/decryption.ts
new file mode 100644
index 00000000..bc4001a5
--- /dev/null
+++ b/packages/fhevm-sdk/src/core/decryption.ts
@@ -0,0 +1,147 @@
+import { DecryptionSignature, StorageInterface } from '../types';
+
+/**
+ * Decryption utilities for FHEVM operations
+ */
+export class DecryptionUtils {
+ /**
+ * Create decryption signature
+ */
+ static async createDecryptionSignature(
+ instance: any,
+ contractAddresses: string[],
+ signer: any,
+ storage: StorageInterface
+ ): Promise {
+ try {
+ // Load or create decryption signature
+ const signature = await this.loadOrCreateSignature(
+ instance,
+ contractAddresses,
+ signer,
+ storage
+ );
+
+ return signature;
+ } catch (error) {
+ console.error('Failed to create decryption signature:', error);
+ return null;
+ }
+ }
+
+ /**
+ * Load or create decryption signature
+ */
+ private static async loadOrCreateSignature(
+ instance: any,
+ contractAddresses: string[],
+ signer: any,
+ storage: StorageInterface
+ ): Promise {
+ const userAddress = await signer.getAddress();
+ const key = `fhevm-signature-${userAddress}-${contractAddresses.join('-')}`;
+
+ try {
+ // Try to load existing signature
+ const existingSignature = await storage.get(key);
+ if (existingSignature) {
+ const parsed = JSON.parse(existingSignature);
+ // Check if signature is still valid
+ if (this.isSignatureValid(parsed)) {
+ return parsed;
+ }
+ }
+ } catch (error) {
+ console.warn('Failed to load existing signature:', error);
+ }
+
+ try {
+ // Create new signature
+ const signature = await instance.generatePublicKey(contractAddresses);
+ const publicKey = signature.publicKey;
+ const privateKey = signature.privateKey;
+
+ // Sign the public key
+ const signatureHash = await signer.signMessage(publicKey);
+
+ const decryptionSignature: DecryptionSignature = {
+ privateKey,
+ publicKey,
+ signature: signatureHash,
+ contractAddresses,
+ userAddress,
+ startTimestamp: Math.floor(Date.now() / 1000),
+ durationDays: 7, // 7 days validity
+ };
+
+ // Store signature
+ await storage.set(key, JSON.stringify(decryptionSignature));
+
+ return decryptionSignature;
+ } catch (error) {
+ console.error('Failed to create new signature:', error);
+ return null;
+ }
+ }
+
+ /**
+ * Check if signature is still valid
+ */
+ private static isSignatureValid(signature: DecryptionSignature): boolean {
+ const now = Math.floor(Date.now() / 1000);
+ const expiry = signature.startTimestamp + (signature.durationDays * 24 * 60 * 60);
+ return now < expiry;
+ }
+
+ /**
+ * Decrypt handles with signature
+ */
+ static async decryptHandles(
+ instance: any,
+ handles: string[],
+ contractAddress: string,
+ signature: DecryptionSignature
+ ): Promise> {
+ try {
+ const result = await instance.userDecrypt(
+ handles.map(handle => ({ handle, contractAddress })),
+ signature.privateKey,
+ signature.publicKey,
+ signature.signature,
+ signature.contractAddresses,
+ signature.userAddress,
+ signature.startTimestamp,
+ signature.durationDays
+ );
+
+ return result;
+ } catch (error) {
+ console.error('Failed to decrypt handles:', error);
+ throw error;
+ }
+ }
+}
+
+/**
+ * Helper function to create decryption signature
+ */
+export async function createDecryptionSignature(
+ instance: any,
+ contractAddresses: string[],
+ signer: any,
+ storage: StorageInterface
+): Promise {
+ return DecryptionUtils.createDecryptionSignature(instance, contractAddresses, signer, storage);
+}
+
+/**
+ * Helper function to decrypt handles
+ */
+export async function decryptHandles(
+ instance: any,
+ handles: string[],
+ contractAddress: string,
+ signature: DecryptionSignature
+): Promise> {
+ return DecryptionUtils.decryptHandles(instance, handles, contractAddress, signature);
+}
diff --git a/packages/fhevm-sdk/src/core/encryption.ts b/packages/fhevm-sdk/src/core/encryption.ts
new file mode 100644
index 00000000..497b9b21
--- /dev/null
+++ b/packages/fhevm-sdk/src/core/encryption.ts
@@ -0,0 +1,83 @@
+import { EncryptedInput, EncryptedResult } from '../types';
+
+/**
+ * Encryption utilities for FHEVM operations
+ */
+export class EncryptionUtils {
+ /**
+ * Create encrypted input with multiple values
+ */
+ static async createEncryptedInput(
+ encryptedInput: EncryptedInput,
+ values: (number | bigint | boolean)[]
+ ): Promise {
+ // Add all values to the encrypted input
+ for (const value of values) {
+ if (typeof value === 'number') {
+ encryptedInput.add32(value);
+ } else if (typeof value === 'bigint') {
+ encryptedInput.add64(value);
+ } else if (typeof value === 'boolean') {
+ encryptedInput.addBool(value);
+ }
+ }
+
+ // Encrypt the input
+ return await encryptedInput.encrypt();
+ }
+
+ /**
+ * Create encrypted input for a single value
+ */
+ static async encryptSingleValue(
+ encryptedInput: EncryptedInput,
+ value: number | bigint | boolean
+ ): Promise {
+ if (typeof value === 'number') {
+ encryptedInput.add32(value);
+ } else if (typeof value === 'bigint') {
+ encryptedInput.add64(value);
+ } else if (typeof value === 'boolean') {
+ encryptedInput.addBool(value);
+ }
+
+ return await encryptedInput.encrypt();
+ }
+
+ /**
+ * Batch encrypt multiple values
+ */
+ static async batchEncrypt(
+ encryptedInput: EncryptedInput,
+ values: (number | bigint | boolean)[][]
+ ): Promise {
+ const results: EncryptedResult[] = [];
+
+ for (const batch of values) {
+ const result = await this.createEncryptedInput(encryptedInput, batch);
+ results.push(result);
+ }
+
+ return results;
+ }
+}
+
+/**
+ * Helper function to create encrypted input
+ */
+export function createEncryptedInput(
+ encryptedInput: EncryptedInput,
+ values: (number | bigint | boolean)[]
+): Promise {
+ return EncryptionUtils.createEncryptedInput(encryptedInput, values);
+}
+
+/**
+ * Helper function to encrypt single value
+ */
+export function encryptSingleValue(
+ encryptedInput: EncryptedInput,
+ value: number | bigint | boolean
+): Promise {
+ return EncryptionUtils.encryptSingleValue(encryptedInput, value);
+}
diff --git a/packages/fhevm-sdk/src/core/fhevm-client.ts b/packages/fhevm-sdk/src/core/fhevm-client.ts
new file mode 100644
index 00000000..b9da73ad
--- /dev/null
+++ b/packages/fhevm-sdk/src/core/fhevm-client.ts
@@ -0,0 +1,130 @@
+// import { ethers } from 'ethers'; // Not used in this file
+import { FHEVMConfig, FHEVMInstance, EncryptedInput, DecryptionSignature, FHEVMClient } from '../types';
+
+/**
+ * Core FHEVM Client - Framework agnostic
+ * Provides the main functionality for FHEVM operations
+ */
+export class FHEVMClientImpl implements FHEVMClient {
+ private instance: any = null;
+ private config: FHEVMConfig | null = null;
+ private supportedChains: number[] = [31337, 11155111]; // Hardhat, Sepolia
+
+ constructor() {
+ this.supportedChains = [31337, 11155111];
+ }
+
+ /**
+ * Initialize FHEVM instance
+ */
+ async initialize(config: FHEVMConfig): Promise {
+ try {
+ this.config = config;
+
+ // Dynamic import to avoid bundling issues
+ const { initSDK, createInstance } = await import('@zama-fhe/relayer-sdk');
+
+ // Initialize SDK first (load WASM)
+ await initSDK();
+
+ const instance = await createInstance({
+ chainId: config.chainId,
+ } as any);
+
+ this.instance = instance;
+
+ return {
+ status: 'ready',
+ instance,
+ };
+ } catch (error) {
+ return {
+ status: 'error',
+ error: error instanceof Error ? error.message : 'Unknown error',
+ };
+ }
+ }
+
+ /**
+ * Create encrypted input for FHE operations
+ */
+ createEncryptedInput(contractAddress: string, userAddress: string): EncryptedInput {
+ if (!this.instance) {
+ throw new Error('FHEVM instance not initialized');
+ }
+
+ return this.instance.createEncryptedInput(contractAddress, userAddress);
+ }
+
+ /**
+ * Decrypt FHE handles
+ */
+ async decrypt(
+ handles: string[],
+ contractAddress: string,
+ signature: DecryptionSignature
+ ): Promise> {
+ if (!this.instance) {
+ throw new Error('FHEVM instance not initialized');
+ }
+
+ return await this.instance.userDecrypt(
+ handles.map(handle => ({ handle, contractAddress })),
+ signature.privateKey,
+ signature.publicKey,
+ signature.signature,
+ signature.contractAddresses,
+ signature.userAddress,
+ signature.startTimestamp,
+ signature.durationDays
+ );
+ }
+
+ /**
+ * Check if chain is supported
+ */
+ isSupported(chainId: number): boolean {
+ return this.supportedChains.includes(chainId);
+ }
+
+ /**
+ * Get list of supported chains
+ */
+ getSupportedChains(): number[] {
+ return [...this.supportedChains];
+ }
+
+ /**
+ * Get current instance
+ */
+ getInstance() {
+ return this.instance;
+ }
+
+ /**
+ * Get current config
+ */
+ getConfig() {
+ return this.config;
+ }
+}
+
+// Singleton instance
+let clientInstance: FHEVMClientImpl | null = null;
+
+/**
+ * Get or create FHEVM client instance
+ */
+export function getFHEVMClient(): FHEVMClient {
+ if (!clientInstance) {
+ clientInstance = new FHEVMClientImpl();
+ }
+ return clientInstance;
+}
+
+/**
+ * Create new FHEVM client instance
+ */
+export function createFHEVMClient(): FHEVMClient {
+ return new FHEVMClientImpl();
+}
diff --git a/packages/fhevm-sdk/src/index.ts b/packages/fhevm-sdk/src/index.ts
new file mode 100644
index 00000000..6fd41971
--- /dev/null
+++ b/packages/fhevm-sdk/src/index.ts
@@ -0,0 +1,78 @@
+// Core exports
+export { getFHEVMClient, createFHEVMClient } from './core/fhevm-client';
+export { createEncryptedInput, encryptSingleValue, EncryptionUtils } from './core/encryption';
+export { createDecryptionSignature, decryptHandles, DecryptionUtils } from './core/decryption';
+
+// Types
+export type {
+ FHEVMConfig,
+ FHEVMInstance,
+ EncryptedInput,
+ EncryptedResult,
+ DecryptionSignature,
+ FHEVMClient,
+ StorageInterface,
+ WalletProvider,
+ FHEVMHookReturn,
+ FHEVMComponentProps,
+} from './types';
+
+// React exports
+export { useFHEVM, useFHEVMWithConfig } from './adapters/react/useFHEVM';
+export { FHEVMProvider, useFHEVMContext, withFHEVM } from './adapters/react/FHEVMProvider';
+export { EncryptButton, DecryptButton } from './adapters/react/components/EncryptButton';
+
+// Vue exports
+export { useFHEVM as useFHEVMVue, useFHEVMWithConfig as useFHEVMWithConfigVue } from './adapters/vue/useFHEVM';
+
+// Node.js exports
+export { FHEVMNode, createFHEVMNode, createProviderAndSigner } from './adapters/node/fhevm-node';
+
+// Utility functions
+export const SUPPORTED_CHAINS = [31337, 11155111]; // Hardhat, Sepolia
+
+/**
+ * Check if chain is supported
+ */
+export function isChainSupported(chainId: number): boolean {
+ return SUPPORTED_CHAINS.includes(chainId);
+}
+
+/**
+ * Get supported chains
+ */
+export function getSupportedChains(): number[] {
+ return [...SUPPORTED_CHAINS];
+}
+
+/**
+ * Create default FHEVM config
+ */
+export function createDefaultConfig(chainId: number) {
+ return {
+ chainId,
+ mockChains: [31337],
+ };
+}
+
+/**
+ * Create Sepolia config
+ */
+export function createSepoliaConfig(rpcUrl?: string) {
+ return {
+ chainId: 11155111,
+ rpcUrl,
+ mockChains: [31337],
+ };
+}
+
+/**
+ * Create Hardhat config
+ */
+export function createHardhatConfig(rpcUrl = 'http://127.0.0.1:8545') {
+ return {
+ chainId: 31337,
+ rpcUrl,
+ mockChains: [31337],
+ };
+}
diff --git a/packages/fhevm-sdk/src/types.ts b/packages/fhevm-sdk/src/types.ts
new file mode 100644
index 00000000..63063bac
--- /dev/null
+++ b/packages/fhevm-sdk/src/types.ts
@@ -0,0 +1,94 @@
+import { ethers } from 'ethers';
+
+export interface FHEVMConfig {
+ chainId: number;
+ rpcUrl?: string;
+ relayerUrl?: string;
+ mockChains?: number[];
+}
+
+// Extend Window interface for ethereum
+declare global {
+ interface Window {
+ ethereum?: any;
+ }
+}
+
+export interface FHEVMInstance {
+ status: 'loading' | 'ready' | 'error';
+ error?: string;
+ instance?: any; // FhevmInstance from @zama-fhe/relayer-sdk
+}
+
+export interface EncryptedInput {
+ add32: (value: number) => void;
+ add64: (value: bigint) => void;
+ addBool: (value: boolean) => void;
+ encrypt: () => Promise;
+}
+
+export interface EncryptedResult {
+ handles: string[];
+ inputProof: string;
+}
+
+export interface DecryptionSignature {
+ privateKey: string;
+ publicKey: string;
+ signature: string;
+ contractAddresses: string[];
+ userAddress: string;
+ startTimestamp: number;
+ durationDays: number;
+}
+
+export interface FHEVMClient {
+ // Core methods
+ initialize: (config: FHEVMConfig) => Promise;
+ createEncryptedInput: (contractAddress: string, userAddress: string) => EncryptedInput;
+ decrypt: (handles: string[], contractAddress: string, signature: DecryptionSignature) => Promise>;
+
+ // Utility methods
+ isSupported: (chainId: number) => boolean;
+ getSupportedChains: () => number[];
+}
+
+export interface StorageInterface {
+ get: (key: string) => Promise;
+ set: (key: string, value: string) => Promise;
+ remove: (key: string) => Promise;
+}
+
+export interface WalletProvider {
+ provider: ethers.Eip1193Provider;
+ signer: ethers.JsonRpcSigner;
+ address: string;
+ chainId: number;
+}
+
+export interface FHEVMHookReturn {
+ // State
+ isConnected: boolean;
+ isInitialized: boolean;
+ isLoading: boolean;
+ error?: string;
+
+ // Instance
+ instance?: FHEVMInstance;
+
+ // Methods
+ connect: () => Promise;
+ disconnect: () => void;
+ initialize: (config: FHEVMConfig) => Promise;
+
+ // FHE Operations
+ encrypt: (contractAddress: string, values: (number | bigint | boolean)[]) => Promise;
+ decrypt: (handles: string[], contractAddress: string) => Promise>;
+}
+
+export interface FHEVMComponentProps {
+ children?: any; // React.ReactNode
+ config: FHEVMConfig;
+ onError?: (error: string) => void;
+ onReady?: () => void;
+}
diff --git a/packages/fhevm-sdk/tsconfig.json b/packages/fhevm-sdk/tsconfig.json
new file mode 100644
index 00000000..e8f4699c
--- /dev/null
+++ b/packages/fhevm-sdk/tsconfig.json
@@ -0,0 +1,31 @@
+{
+ "compilerOptions": {
+ "target": "ES2020",
+ "lib": ["ES2020", "DOM", "DOM.Iterable"],
+ "allowJs": true,
+ "skipLibCheck": true,
+ "esModuleInterop": true,
+ "allowSyntheticDefaultImports": true,
+ "strict": true,
+ "forceConsistentCasingInFileNames": true,
+ "module": "ESNext",
+ "moduleResolution": "node",
+ "resolveJsonModule": true,
+ "isolatedModules": true,
+ "noEmit": true,
+ "jsx": "react-jsx",
+ "declaration": true,
+ "declarationMap": true,
+ "outDir": "dist",
+ "rootDir": "src"
+ },
+ "include": [
+ "src/**/*"
+ ],
+ "exclude": [
+ "node_modules",
+ "dist",
+ "**/*.test.ts",
+ "**/*.test.tsx"
+ ]
+}
diff --git a/packages/site/USING_THE_SDK.md b/packages/site/USING_THE_SDK.md
new file mode 100644
index 00000000..dce0a320
--- /dev/null
+++ b/packages/site/USING_THE_SDK.md
@@ -0,0 +1,200 @@
+# 🚀 How to Use Your Universal FHEVM SDK
+
+## 📋 Quick Start Guide
+
+Your Universal FHEVM SDK is now integrated into this project! Here's how to use it:
+
+## 🎮 Try the Demo
+
+### 1. Start the Development Server
+```bash
+cd packages/site
+npm run dev
+```
+
+### 2. Open the SDK Demo
+- Go to: http://localhost:3000
+- Click "Try SDK Demo" button
+- Or go directly to: http://localhost:3000/sdk-demo
+
+### 3. Test the SDK
+- Connect your MetaMask wallet
+- Initialize the FHEVM SDK
+- Try encrypting and decrypting values
+- See the SDK in action!
+
+## 💻 Using the SDK in Your Code
+
+### React Hook Usage
+```tsx
+import { useFHEVM, createSepoliaConfig } from '../../fhevm-sdk/src';
+
+function MyComponent() {
+ const fhevm = useFHEVM();
+
+ const handleConnect = async () => {
+ await fhevm.connect();
+ await fhevm.initialize(createSepoliaConfig());
+ };
+
+ const handleEncrypt = async () => {
+ const result = await fhevm.encrypt(
+ '0x1234...', // contract address
+ [42, 100, true] // values to encrypt
+ );
+ console.log('Encrypted:', result);
+ };
+
+ return (
+
+
+
+
+ );
+}
+```
+
+### Using Components
+```tsx
+import { EncryptButton, DecryptButton } from '../../fhevm-sdk/src';
+
+function MyComponent() {
+ return (
+
+ console.log('Encrypted:', result)}
+ onError={(error) => console.error('Error:', error)}
+ >
+ Encrypt Values
+
+
+ );
+}
+```
+
+### With Provider
+```tsx
+import { FHEVMProvider, createSepoliaConfig } from '../../fhevm-sdk/src';
+
+function App() {
+ return (
+
+
+
+ );
+}
+```
+
+## 🛠️ SDK Features
+
+### Core Features
+- **Framework Agnostic** - Works with React, Vue, Node.js
+- **Wagmi-like API** - Familiar developer experience
+- **TypeScript Support** - Full type safety
+- **Easy Setup** - Simple configuration
+
+### Available Hooks
+- `useFHEVM()` - Main React hook
+- `useFHEVMWithConfig()` - Auto-initialization hook
+
+### Available Components
+- `EncryptButton` - Reusable encryption component
+- `DecryptButton` - Reusable decryption component
+- `FHEVMProvider` - Context provider
+
+### Configuration Helpers
+- `createSepoliaConfig()` - Sepolia testnet config
+- `createHardhatConfig()` - Hardhat local config
+- `createDefaultConfig()` - Custom chain config
+
+## 📁 SDK Structure
+
+```
+packages/fhevm-sdk/
+├── src/
+│ ├── core/ # Framework-agnostic core
+│ │ ├── fhevm-client.ts # Main FHEVM client
+│ │ ├── encryption.ts # Encryption utilities
+│ │ └── decryption.ts # Decryption utilities
+│ ├── adapters/ # Framework adapters
+│ │ ├── react/ # React hooks & components
+│ │ ├── vue/ # Vue composables
+│ │ └── node/ # Node.js utilities
+│ └── types.ts # TypeScript definitions
+├── examples/ # Usage examples
+├── demo/ # Interactive demo
+└── README.md # Complete documentation
+```
+
+## 🔧 Development
+
+### Building the SDK
+```bash
+cd packages/fhevm-sdk
+npm run build
+```
+
+### Running Tests
+```bash
+cd packages/fhevm-sdk
+npm test
+```
+
+### Type Checking
+```bash
+cd packages/fhevm-sdk
+npm run type-check
+```
+
+## 📚 Examples
+
+### React Example
+See: `packages/fhevm-sdk/examples/react-example.tsx`
+
+### Vue Example
+See: `packages/fhevm-sdk/examples/vue-example.vue`
+
+### Node.js Example
+See: `packages/fhevm-sdk/examples/node-example.ts`
+
+## 🎯 Use Cases
+
+### 1. Privacy-Preserving Voting
+```tsx
+const fhevm = useFHEVM();
+const vote = await fhevm.encrypt(contractAddress, [candidateId]);
+```
+
+### 2. Private Auctions
+```tsx
+const fhevm = useFHEVM();
+const bid = await fhevm.encrypt(contractAddress, [bidAmount]);
+```
+
+### 3. Confidential Transactions
+```tsx
+const fhevm = useFHEVM();
+const transaction = await fhevm.encrypt(contractAddress, [amount, recipient]);
+```
+
+## 🚀 Next Steps
+
+1. **Try the Demo** - Test the SDK functionality
+2. **Read the Documentation** - Check `packages/fhevm-sdk/README.md`
+3. **Explore Examples** - Look at the example files
+4. **Build Your App** - Use the SDK in your own projects
+5. **Contribute** - Help improve the SDK
+
+## 🏆 Bounty Submission
+
+This SDK was created for the **Zama Developer Program Bounty Track - October 2025**.
+
+**Repository**: https://github.com/83mhpll/fhevm-react-template/tree/bounty-submission-october-2025
+
+**Developer**: mk83
+
+---
+
+*Enjoy building privacy-preserving dApps with your Universal FHEVM SDK! 🎉*
diff --git a/packages/site/abi/FHECounterABI.ts b/packages/site/abi/FHECounterABI.ts
index d76a60c2..133ec9c3 100644
--- a/packages/site/abi/FHECounterABI.ts
+++ b/packages/site/abi/FHECounterABI.ts
@@ -1,4 +1,3 @@
-
/*
This file is auto-generated.
Command: 'npm run genabi'
@@ -53,7 +52,19 @@ export const FHECounterABI = {
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "protocolId",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "pure",
+ "type": "function"
}
]
-} as const;
-
+} as const;
\ No newline at end of file
diff --git a/packages/site/abi/FHECounterAddresses.ts b/packages/site/abi/FHECounterAddresses.ts
index 74fdc267..dcfe85cf 100644
--- a/packages/site/abi/FHECounterAddresses.ts
+++ b/packages/site/abi/FHECounterAddresses.ts
@@ -1,9 +1,3 @@
-
-/*
- This file is auto-generated.
- Command: 'npm run genabi'
-*/
-export const FHECounterAddresses = {
- "11155111": { address: "0x0000000000000000000000000000000000000000", chainId: 11155111, chainName: "sepolia" },
- "31337": { address: "0x7553CB9124f974Ee475E5cE45482F90d5B6076BC", chainId: 31337, chainName: "hardhat" },
-};
+export const FHECounterAddresses = {
+ "31337": "0x5FbDB2315678afecb367f032d93F642f64180aa3"
+} as const;
\ No newline at end of file
diff --git a/packages/site/app/layout.tsx b/packages/site/app/layout.tsx
index 8a5ed7c4..512e1245 100644
--- a/packages/site/app/layout.tsx
+++ b/packages/site/app/layout.tsx
@@ -4,8 +4,11 @@ import { Providers } from "./providers";
import Image from "next/image";
export const metadata: Metadata = {
- title: "Zama FHEVM SDK Quickstart",
- description: "Zama FHEVM SDK Quickstart app",
+ title: "Universal FHEVM SDK - Privacy-Preserving dApps",
+ description: "Framework-agnostic SDK for building privacy-preserving dApps with Fully Homomorphic Encryption. Created by mk83 for Zama Developer Program Bounty Track.",
+ keywords: ["FHEVM", "privacy", "encryption", "blockchain", "ethereum", "SDK", "framework-agnostic"],
+ authors: [{ name: "mk83" }],
+ viewport: "width=device-width, initial-scale=1",
};
export default async function RootLayout({
@@ -16,14 +19,15 @@ export default async function RootLayout({
return (
-
-
-