2.0 RC docsView 1.x docs
v2.0.0-rc.1 release candidate
The API is frozen and later candidates carry fixes only, except the receipt-free and Safe create surface of /fhe-airdrop, which is @beta. Published on the next dist-tag; latest stays on 1.6.0 until 2.0.0.
Encrypted readcustom hookencrypted handle Curated

useDecryptedHandle

Subscribe to a single encrypted handle and reactively decrypt via the connected wallet.

Import
@tokenops/sdk/fhe/react
Return
(see signature — custom result type)
Lifecycle
Encrypted read

Description

Decrypt a single EncryptedHandle returned by an FHE-product encrypted view (e.g. EncryptedViewResult.handle from ConfidentialVestingManagerClient.getClaimableAmount()).

import { useZamaSDK } from "@zama-fhe/react-sdk";
import { useDecryptedHandle } from "@tokenops/sdk/fhe/react";
import { useConnection } from "wagmi"; // wagmi v2: useAccount

const sdk = useZamaSDK();
const { address } = useConnection();
const { status, value } = useDecryptedHandle({
  handle: viewResult?.handle,
  contractAddress: managerAddress,
  userDecryptor: () => sdk.decryption,
  account: address,
});

Numeric results (bigint, or number for euint8/16/32) resolve to a bigint. A missing entry or any other value type yields a TokenOpsValidationError; decryptor failures are mapped to typed TokenOpsSdkErrors (for example UserDecryptNotAllowedError when the signer has no ACL grant).

Signature

@tokenops/sdk/fhe/react
ts
function useDecryptedHandle(opts: UseDecryptedHandleOptions): UseDecryptedHandleResult;

Parameters

Shape of the options object passed to the hook itself.

PropertyTypeDescription
handleEncryptedHandle | undefinedThe encrypted handle to decrypt. undefined keeps the hook in idle state, e.g. while the query producing the handle has not resolved.
contractAddressAddress | undefinedThe contract that granted ACL access to the handle. Decryption is checked against the (handle, contractAddress, signer) triple, so the wrong contract makes the decryption fail.
userDecryptorUserDecryptorSource | undefinedLazy or eager decryptor. Recommended in React: const sdk = useZamaSDK(); then userDecryptor: () => sdk.decryption. The lazy form is called per decryption, so it always sees the live SDK. A lazy source that resolves to undefined (an SDK still initializing) leaves the hook in error; it decrypts once the source resolves. The hook compares the resolved decryptor by identity on every render. When it becomes a different object, for example a new ZamaSDK for another signer, the shown value is dropped at once and the handle is decrypted again with the new decryptor. Pass a stable decryptor: sdk.decryption and () => sdk.decryption resolve to the same object across renders; memoize anything else. A decryptor that resolves to a new object on consecutive renders (an object literal built inline) makes a swap undetectable, so the hook fails closed: it shows no value and reports error with a TokenOpsValidationError instead of decrypting. It decrypts again once the decryptor keeps its identity for a render.
accountAddress | undefinedThe connected signer's address, for example wagmi's useConnection().address (v3) or useAccount().address (v2). Pass it whenever the wallet can change: a ZamaSDK keeps the same decryption object across account switches, so without it a switch that leaves handle and contractAddress as they were keeps showing the previous account's clear value. A change drops that value, aborts an in-flight decryption, and decrypts again as the new account, which fails if that account has no ACL grant. Replacing the decryptor itself (a new ZamaSDK) is detected without it.
enabledboolean | undefinedSkip the decrypt (defaults to false). Useful to render an "Encrypted" placeholder until the user opts in.
Want to run a similar shape interactively? The Playground ships 12 ready presets across vesting / airdrop / disperse / faucet — deploy a manager, create a vesting, claim, and run the product equivalents. The deep-link above auto-selects the closest preset to useDecryptedHandle; pick another from the dropdown if you'd rather start there.

Example

components/useDecryptedHandleExample.tsx
tsx
"use client";
import { useDecryptedHandle } from "@tokenops/sdk/fhe/react";

export function Example() {
  const read = useDecryptedHandle(/* args */);

  // Encrypted view: read.mutate() submits a tx that calls FHE.allow,
  // so the connected wallet gains ACL on the returned handle.
  // Pair read.data.handle with useDecryptedHandle (from @tokenops/sdk/fhe/react)
  // to user-decrypt via the Zama relayer.
}

Auto-generated from the hook's shape (the SDK doesn't carry a TSDoc @example here yet).

See also