Skip to main content

Storage Overview

The FHEVM SDK uses storage adapters to persist decryption signatures and other data across sessions.

Storage Interface

All storage adapters implement the GenericStringStorage interface:

interface GenericStringStorage {
getItem(key: string): string | Promise<string | null> | null;
setItem(key: string, value: string): void | Promise<void>;
removeItem(key: string): void | Promise<void>;
}

Built-in Storage Options

1. In-Memory Storage

Default storage adapter (session-only):

import { GenericStringInMemoryStorage } from '@fhevm/sdk';

const storage = new GenericStringInMemoryStorage();

Characteristics:

  • Data lost on page refresh
  • Fast access
  • No persistence
  • Good for testing

2. LocalStorage (Web)

Persistent browser storage:

class LocalStorageAdapter implements GenericStringStorage {
getItem(key: string): string | null {
return localStorage.getItem(key);
}

setItem(key: string, value: string): void {
localStorage.setItem(key, value);
}

removeItem(key: string): void {
localStorage.removeItem(key);
}
}

3. AsyncStorage (React Native)

Persistent mobile storage:

import AsyncStorage from '@react-native-async-storage/async-storage';

class AsyncStorageAdapter implements GenericStringStorage {
async getItem(key: string) {
return await AsyncStorage.getItem(key);
}

async setItem(key: string, value: string) {
await AsyncStorage.setItem(key, value);
}

async removeItem(key: string) {
await AsyncStorage.removeItem(key);
}
}

What is Stored

Decryption Signatures

Most common use case:

{
key: "userAddress:contractHash",
value: JSON.stringify({
publicKey: "0x...",
privateKey: "0x...",
signature: "0x...",
contractAddresses: ["0x123..."],
startTimestamp: 1234567890,
durationDays: 365,
...
})
}

Decryption Cache

Cached decrypted values (internal):

{
key: "chainId:account:contract:handle",
value: JSON.stringify({
value: "100",
timestamp: 1234567890,
chainId: 8009,
account: "0x..."
})
}

Using Storage

Default Usage

The SDK uses in-memory storage by default:

import { useFHEDecrypt } from '@fhevm/sdk';

// Uses default in-memory storage
const { decrypt } = useFHEDecrypt({
instance,
ethersSigner,
fhevmDecryptionSignatureStorage: new GenericStringInMemoryStorage(),
chainId,
requests,
});

Custom Storage

Provide your own storage adapter:

import { useFHEDecrypt } from '@fhevm/sdk';

const customStorage = new LocalStorageAdapter();

const { decrypt } = useFHEDecrypt({
instance,
ethersSigner,
fhevmDecryptionSignatureStorage: customStorage,
chainId,
requests,
});

Storage Keys

Key Format

Keys follow a consistent pattern:

userAddress:contractHash

Example:

0x1234...5678:0xabcd...ef01

Key Generation

Keys are generated based on:

  • User address
  • Contract addresses
  • Public key (optional)

The SDK automatically manages key generation.

Best Practices

1. Choose Appropriate Storage

Use CaseStorageReason
Production WebLocalStoragePersistent, no server needed
Production MobileAsyncStorageNative mobile persistence
DevelopmentInMemoryStorageFast, no cleanup needed
TestingInMemoryStorageIsolated test runs

2. Handle Async Storage

// Wait for async storage operations
const value = await storage.getItem(key);
if (value) {
const signature = JSON.parse(value);
}

3. Error Handling

try {
await storage.setItem(key, value);
} catch (error) {
console.error('Storage failed:', error);
// Fallback to in-memory
}

4. Clear Sensitive Data

// Clear on logout
const clearStorage = async () => {
await storage.removeItem(signatureKey);
};

Security Considerations

What to Store

  • Decryption signatures (safe to persist)
  • Cached decrypted values (temporary)
  • User preferences

What NOT to Store

  • Private keys used for transactions
  • Wallet mnemonics
  • Unencrypted sensitive data

Storage Security

  • LocalStorage is accessible to all scripts on the page
  • Consider encrypted storage for sensitive data
  • Clear storage on logout
  • Implement data expiration

Next Steps