@zama-fhe/react-sdk 1.0.0-alpha.2 → 1.0.0-alpha.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -6,6 +6,10 @@ React hooks for confidential token operations, built on [React Query](https://ta
6
6
 
7
7
  ```bash
8
8
  pnpm add @zama-fhe/react-sdk @tanstack/react-query
9
+ # or
10
+ npm install @zama-fhe/react-sdk @tanstack/react-query
11
+ # or
12
+ yarn add @zama-fhe/react-sdk @tanstack/react-query
9
13
  ```
10
14
 
11
15
  `@zama-fhe/sdk` is included as a direct dependency — no need to install it separately.
@@ -148,8 +152,10 @@ import { ZamaProvider } from "@zama-fhe/react-sdk";
148
152
  <ZamaProvider
149
153
  relayer={relayer} // RelayerSDK (RelayerWeb or RelayerNode instance)
150
154
  signer={signer} // GenericSigner (WagmiSigner, ViemSigner, EthersSigner, or custom)
151
- storage={storage} // GenericStringStorage
152
- credentialDurationDays={1} // Optional. Days FHE credentials remain valid. Default: 1. Set 0 for sign-every-time.
155
+ storage={storage} // GenericStorage
156
+ sessionStorage={sessionStorage} // Optional. Session storage for wallet signatures. Default: in-memory (lost on reload).
157
+ keypairTTL={86400} // Optional. Seconds the ML-KEM keypair remains valid. Default: 86400 (1 day).
158
+ sessionTTL={2592000} // Optional. Seconds the session signature remains valid. Default: 2592000 (30 days). 0 = re-sign every operation.
153
159
  onEvent={(event) => console.debug(event)} // Optional. Structured event listener for debugging.
154
160
  >
155
161
  {children}
@@ -169,36 +175,16 @@ const { mutateAsync: shield } = useShield({ tokenAddress });
169
175
  await shield({ amount: 1000n }); // encryption + approval handled for you
170
176
  ```
171
177
 
172
- **Use the library sub-path** (`/viem`, `/ethers`, `/wagmi`) when you need direct contract-level control without a provider. You handle encryption and cache management yourself:
173
-
174
178
  ```tsx
175
- import { useShield } from "@zama-fhe/react-sdk/viem";
176
-
177
- const { mutateAsync: shield } = useShield();
178
- await shield({ client: walletClient, wrapperAddress, to, amount }); // raw contract call
179
+ import { ViemSigner } from "@zama-fhe/sdk/viem";
180
+ import { EthersSigner } from "@zama-fhe/sdk/ethers";
179
181
  ```
180
182
 
181
- ### Comparison of Colliding Hook Names
182
-
183
- Five hooks share names across both layers. Here's how they differ:
183
+ The `WagmiSigner` is the only adapter in the react-sdk since wagmi is React-specific:
184
184
 
185
- | Hook | Main (`@zama-fhe/react-sdk`) | Sub-path (`/viem`, `/ethers`, `/wagmi`) |
186
- | ------------------------- | ----------------------------------------------------------- | ------------------------------------------------------------------------------------ |
187
- | `useConfidentialTransfer` | `mutate({ to, amount })` — auto-encrypts | `mutate({ client, token, to, handle, inputProof })` — pre-encrypted |
188
- | `useShield` | `mutate({ amount, approvalStrategy? })` — auto-approves | `mutate({ client, wrapper, to, amount })` — raw wrap call |
189
- | `useShieldETH` | `mutate({ amount, value? })` — `value` defaults to `amount` | `mutate({ client, wrapper, to, amount, value })` — all fields required |
190
- | `useUnwrap` | `mutate({ amount })` — auto-encrypts | `mutate({ client, token, from, to, encryptedAmount, inputProof })` — pre-encrypted |
191
- | `useFinalizeUnwrap` | `mutate({ burnAmountHandle })` — fetches proof from relayer | `mutate({ client, wrapper, burntAmount, cleartext, proof })` — caller provides proof |
192
-
193
- | Feature | Main | Sub-path |
194
- | ----------------------- | ----------------------- | ----------------------------- |
195
- | Requires `ZamaProvider` | Yes | No |
196
- | FHE encryption | Automatic | Manual (caller pre-encrypts) |
197
- | ERC-20 approval | Automatic (`useShield`) | None |
198
- | Cache invalidation | Automatic | None |
199
- | Return type | `TransactionResult` | Raw tx hash or wagmi mutation |
200
-
201
- > **Rule of thumb:** If you're building a standard dApp UI, use the main import. If you're building custom transaction pipelines or need to compose with other wagmi hooks at the contract level, use the sub-path.
185
+ ```tsx
186
+ import { WagmiSigner } from "@zama-fhe/react-sdk/wagmi";
187
+ ```
202
188
 
203
189
  ## Hooks Reference
204
190
 
@@ -289,24 +275,55 @@ const tokenABalance = balances?.get("0xTokenA");
289
275
 
290
276
  ### Authorization
291
277
 
292
- #### `useAuthorizeAll`
278
+ #### `useTokenAllow`
293
279
 
294
280
  Pre-authorize FHE decrypt credentials for a list of token addresses with a single wallet signature. Call this early (e.g. after loading the token list) so that subsequent individual decrypt operations reuse cached credentials without prompting the wallet again.
295
281
 
296
282
  ```ts
297
- function useAuthorizeAll(): UseMutationResult<void, Error, Address[]>;
283
+ function useTokenAllow(): UseMutationResult<void, Error, Address[]>;
298
284
  ```
299
285
 
300
286
  ```tsx
301
- const { mutateAsync: authorizeAll, isPending } = useAuthorizeAll();
287
+ const { mutateAsync: tokenAllow, isPending } = useTokenAllow();
302
288
 
303
289
  // Pre-authorize all known tokens up front
304
- await authorizeAll(allTokenAddresses);
290
+ await tokenAllow(allTokenAddresses);
305
291
 
306
292
  // Individual balance decrypts now reuse cached credentials
307
293
  const { data: balance } = useConfidentialBalance("0xTokenA");
308
294
  ```
309
295
 
296
+ #### `useIsTokenAllowed`
297
+
298
+ Check whether a session signature is cached for a given token. Returns `true` if decrypt operations can proceed without a wallet prompt. Use this to conditionally enable UI elements (e.g. a "Reveal Balances" button).
299
+
300
+ ```ts
301
+ function useIsTokenAllowed(tokenAddress: Address): UseQueryResult<boolean, Error>;
302
+ ```
303
+
304
+ ```tsx
305
+ const { data: allowed } = useIsTokenAllowed("0xTokenAddress");
306
+
307
+ <button disabled={!allowed}>Reveal Balance</button>;
308
+ ```
309
+
310
+ Automatically invalidated when `useTokenAllow` or `useTokenRevoke` succeed.
311
+
312
+ #### `useTokenRevoke`
313
+
314
+ Revoke the session signature for the connected wallet. Stored credentials remain intact, but the next decrypt operation will require a fresh wallet signature.
315
+
316
+ ```ts
317
+ function useTokenRevoke(): UseMutationResult<void, Error, Address[]>;
318
+ ```
319
+
320
+ ```tsx
321
+ const { mutate: tokenRevoke } = useTokenRevoke();
322
+
323
+ // Revoke session — addresses are included in the credentials:revoked event
324
+ tokenRevoke(["0xTokenA", "0xTokenB"]);
325
+ ```
326
+
310
327
  ### Transfer Hooks
311
328
 
312
329
  #### `useConfidentialTransfer`
@@ -581,7 +598,7 @@ function useConfidentialIsApproved(
581
598
 
582
599
  #### `useUnderlyingAllowance`
583
600
 
584
- Read the ERC-20 allowance of the underlying token for the wrapper.
601
+ Read the underlying ERC-20 allowance granted to the wrapper.
585
602
 
586
603
  ```ts
587
604
  function useUnderlyingAllowance(
@@ -777,44 +794,36 @@ const { data: value } = useUserDecryptedValue("0xHandleHash");
777
794
 
778
795
  ## Query Keys
779
796
 
780
- Exported query key factories for manual cache management (invalidation, prefetching, removal).
797
+ Use `zamaQueryKeys` for manual cache management (invalidation, prefetching, removal).
781
798
 
782
799
  ```ts
783
- import {
784
- confidentialBalanceQueryKeys,
785
- confidentialBalancesQueryKeys,
786
- confidentialHandleQueryKeys,
787
- confidentialHandlesQueryKeys,
788
- underlyingAllowanceQueryKeys,
789
- activityFeedQueryKeys,
790
- feeQueryKeys,
791
- decryptionKeys,
792
- } from "@zama-fhe/react-sdk";
800
+ import { zamaQueryKeys, decryptionKeys } from "@zama-fhe/react-sdk";
793
801
  ```
794
802
 
795
- | Factory | Keys | Description |
796
- | ------------------------------- | ---------------------------------------------------------------------------------------- | ----------------------------------- |
797
- | `confidentialBalanceQueryKeys` | `.all`, `.token(address)`, `.owner(address, owner)` | Single-token decrypted balance. |
798
- | `confidentialBalancesQueryKeys` | `.all`, `.tokens(addresses, owner)` | Multi-token batch balances. |
799
- | `confidentialHandleQueryKeys` | `.all`, `.token(address)`, `.owner(address, owner)` | Single-token encrypted handle. |
800
- | `confidentialHandlesQueryKeys` | `.all`, `.tokens(addresses, owner)` | Multi-token batch handles. |
801
- | `underlyingAllowanceQueryKeys` | `.all`, `.token(address, wrapper)` | Underlying ERC-20 allowance. |
802
- | `activityFeedQueryKeys` | `.all`, `.token(address)` | Activity feed items. |
803
- | `feeQueryKeys` | `.shieldFee(...)`, `.unshieldFee(...)`, `.batchTransferFee(addr)`, `.feeRecipient(addr)` | Fee manager queries. |
804
- | `decryptionKeys` | `.value(handle)` | Individual decrypted handle values. |
803
+ | Factory | Keys | Description |
804
+ | ------------------------------------ | ---------------------------------------------------------------------------------------- | ----------------------------------- |
805
+ | `zamaQueryKeys.confidentialBalance` | `.all`, `.token(address)`, `.owner(address, owner)` | Single-token decrypted balance. |
806
+ | `zamaQueryKeys.confidentialBalances` | `.all`, `.tokens(addresses, owner)` | Multi-token batch balances. |
807
+ | `zamaQueryKeys.confidentialHandle` | `.all`, `.token(address)`, `.owner(address, owner)` | Single-token encrypted handle. |
808
+ | `zamaQueryKeys.confidentialHandles` | `.all`, `.tokens(addresses, owner)` | Multi-token batch handles. |
809
+ | `zamaQueryKeys.isAllowed` | `.all` | Session signature status. |
810
+ | `zamaQueryKeys.underlyingAllowance` | `.all`, `.token(address)`, `.scope(address, owner, wrapper)` | Underlying ERC-20 allowance. |
811
+ | `zamaQueryKeys.activityFeed` | `.all`, `.token(address)`, `.scope(address, userAddress, logsKey, decrypt)` | Activity feed items. |
812
+ | `zamaQueryKeys.fees` | `.shieldFee(...)`, `.unshieldFee(...)`, `.batchTransferFee(addr)`, `.feeRecipient(addr)` | Fee manager queries. |
813
+ | `decryptionKeys` | `.value(handle)` | Individual decrypted handle values. |
805
814
 
806
815
  ```tsx
807
816
  import { useQueryClient } from "@tanstack/react-query";
808
- import { confidentialBalanceQueryKeys } from "@zama-fhe/react-sdk";
817
+ import { zamaQueryKeys } from "@zama-fhe/react-sdk";
809
818
 
810
819
  const queryClient = useQueryClient();
811
820
 
812
821
  // Invalidate all balances
813
- queryClient.invalidateQueries({ queryKey: confidentialBalanceQueryKeys.all });
822
+ queryClient.invalidateQueries({ queryKey: zamaQueryKeys.confidentialBalance.all });
814
823
 
815
824
  // Invalidate a specific token's balance
816
825
  queryClient.invalidateQueries({
817
- queryKey: confidentialBalanceQueryKeys.token("0xTokenAddress"),
826
+ queryKey: zamaQueryKeys.confidentialBalance.token("0xTokenAddress"),
818
827
  });
819
828
  ```
820
829
 
@@ -858,30 +867,13 @@ import { WagmiSigner } from "@zama-fhe/react-sdk/wagmi";
858
867
  const signer = new WagmiSigner({ config: wagmiConfig });
859
868
  ```
860
869
 
861
- ## Viem & Ethers Adapter Hooks
862
-
863
- Both `@zama-fhe/react-sdk/viem` and `@zama-fhe/react-sdk/ethers` export the same set of read/write hooks, but typed for their respective libraries. They also include `Suspense` variants of all read hooks.
864
-
865
- ### Read hooks
866
-
867
- `useConfidentialBalanceOf`, `useWrapperForToken`, `useUnderlyingToken`, `useWrapperExists`, `useSupportsInterface` — plus `*Suspense` variants.
868
-
869
- - **viem:** First parameter is `PublicClient`.
870
- - **ethers:** First parameter is `Provider | Signer`.
871
-
872
- ### Write hooks
873
-
874
- `useConfidentialTransfer`, `useConfidentialBatchTransfer`, `useUnwrap`, `useUnwrapFromBalance`, `useFinalizeUnwrap`, `useSetOperator`, `useShield`, `useShieldETH`.
870
+ ## Signer Adapters
875
871
 
876
- - **viem:** Mutation params include `client: WalletClient`.
877
- - **ethers:** Mutation params include `signer: Signer`.
878
-
879
- ### Signer adapters
872
+ Signer adapters are provided by the core SDK package:
880
873
 
881
874
  ```ts
882
- // Re-exported for convenience
883
- import { ViemSigner } from "@zama-fhe/react-sdk/viem";
884
- import { EthersSigner } from "@zama-fhe/react-sdk/ethers";
875
+ import { ViemSigner } from "@zama-fhe/sdk/viem";
876
+ import { EthersSigner } from "@zama-fhe/sdk/ethers";
885
877
  ```
886
878
 
887
879
  ## Wallet Integration Guide
@@ -900,12 +892,34 @@ Place `ZamaProvider` inside your client-only layout. Do **not** create the relay
900
892
 
901
893
  ### FHE Credentials Lifecycle
902
894
 
903
- FHE decrypt credentials are generated once per wallet + token set and cached in the storage backend you provide (e.g. `IndexedDBStorage`). The lifecycle:
895
+ FHE decrypt credentials are generated once per wallet + token set and cached in the storage backend you provide (e.g. `IndexedDBStorage`). The wallet signature is kept **in memory only** — never persisted to disk. The lifecycle:
896
+
897
+ 1. **First decrypt** — SDK generates an FHE keypair, creates EIP-712 typed data, and prompts the wallet to sign. The encrypted credential is stored; the signature is cached in memory.
898
+ 2. **Same session** — Cached credentials and session signature are reused silently (no wallet prompt).
899
+ 3. **Page reload** — Encrypted credentials are loaded from storage; the wallet is prompted once to re-sign for the session.
900
+ 4. **Expiry** — Credentials expire based on `keypairTTL` (default: 86400s = 1 day). After expiry, the next decrypt regenerates and re-prompts.
901
+ 5. **Pre-authorization** — Call `useTokenAllow(tokenAddresses)` early to batch-authorize all tokens in one wallet prompt, avoiding repeated popups.
902
+ 6. **Check status** — Use `useIsTokenAllowed(tokenAddress)` to conditionally enable UI elements (e.g. disable "Reveal" until allowed).
903
+ 7. **Disconnect** — Call `useTokenRevoke(tokenAddresses)` or `await credentials.revoke()` to clear the session signature from memory.
904
+
905
+ ### Web Extension Support
906
+
907
+ By default, wallet signatures are stored in memory and lost on page reload (or service worker restart). For MV3 web extensions, use the built-in `chromeSessionStorage` singleton so signatures survive service worker restarts and are shared across popup, background, and content script contexts:
908
+
909
+ ```tsx
910
+ import { chromeSessionStorage } from "@zama-fhe/react-sdk";
911
+
912
+ <ZamaProvider
913
+ relayer={relayer}
914
+ signer={signer}
915
+ storage={indexedDBStorage}
916
+ sessionStorage={chromeSessionStorage}
917
+ >
918
+ <App />
919
+ </ZamaProvider>;
920
+ ```
904
921
 
905
- 1. **First decrypt** SDK generates an FHE keypair, creates EIP-712 typed data, and prompts the wallet to sign. The signed credential is stored.
906
- 2. **Subsequent decrypts** — If cached credentials cover the requested token, they're reused silently (no wallet prompt).
907
- 3. **Expiry** — Credentials expire based on `durationDays`. After expiry, the next decrypt re-prompts the wallet.
908
- 4. **Pre-authorization** — Call `useAuthorizeAll(tokenAddresses)` early to batch-authorize all tokens in one wallet prompt, avoiding repeated popups.
922
+ This keeps the encrypted credentials in IndexedDB (persistent) while the unlock signature lives in `chrome.storage.session` (ephemeral, cleared when the browser closes).
909
923
 
910
924
  ### Error-to-User-Message Mapping
911
925
 
@@ -960,7 +974,7 @@ To force a refresh:
960
974
 
961
975
  ```tsx
962
976
  const queryClient = useQueryClient();
963
- queryClient.invalidateQueries({ queryKey: confidentialBalanceQueryKeys.all });
977
+ queryClient.invalidateQueries({ queryKey: zamaQueryKeys.confidentialBalance.all });
964
978
  ```
965
979
 
966
980
  ## Re-exports from Core SDK
@@ -973,9 +987,9 @@ All public exports from `@zama-fhe/sdk` are re-exported from the main entry poin
973
987
 
974
988
  **Pending unshield:** `savePendingUnshield`, `loadPendingUnshield`, `clearPendingUnshield`.
975
989
 
976
- **Types:** `Address`, `ZamaSDKConfig`, `ZamaConfig`, `ReadonlyTokenConfig`, `NetworkType`, `RelayerSDK`, `RelayerSDKStatus`, `EncryptResult`, `EncryptParams`, `UserDecryptParams`, `PublicDecryptResult`, `FHEKeypair`, `EIP712TypedData`, `DelegatedUserDecryptParams`, `KmsDelegatedUserDecryptEIP712Type`, `ZKProofLike`, `InputProofBytesType`, `BatchTransferData`, `StoredCredentials`, `GenericSigner`, `GenericStringStorage`, `ContractCallConfig`, `TransactionReceipt`, `TransactionResult`, `UnshieldCallbacks`.
990
+ **Types:** `Address`, `ZamaSDKConfig`, `ZamaConfig`, `ReadonlyTokenConfig`, `NetworkType`, `RelayerSDK`, `RelayerSDKStatus`, `EncryptResult`, `EncryptParams`, `UserDecryptParams`, `PublicDecryptResult`, `FHEKeypair`, `EIP712TypedData`, `DelegatedUserDecryptParams`, `KmsDelegatedUserDecryptEIP712Type`, `ZKProofLike`, `InputProofBytesType`, `BatchTransferData`, `StoredCredentials`, `GenericSigner`, `GenericStorage`, `ContractCallConfig`, `TransactionReceipt`, `TransactionResult`, `UnshieldCallbacks`.
977
991
 
978
- **Errors:** `ZamaError`, `ZamaErrorCode`, `SigningRejectedError`, `SigningFailedError`, `EncryptionFailedError`, `DecryptionFailedError`, `ApprovalFailedError`, `TransactionRevertedError`, `InvalidCredentialsError`, `NoCiphertextError`, `RelayerRequestFailedError`, `matchZamaError`.
992
+ **Errors:** `ZamaError`, `ZamaErrorCode`, `SigningRejectedError`, `SigningFailedError`, `EncryptionFailedError`, `DecryptionFailedError`, `ApprovalFailedError`, `TransactionRevertedError`, `InvalidKeypairError`, `NoCiphertextError`, `RelayerRequestFailedError`, `matchZamaError`.
979
993
 
980
994
  **Constants:** `ZERO_HANDLE`, `ERC7984_INTERFACE_ID`, `ERC7984_WRAPPER_INTERFACE_ID`.
981
995