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.getTokenBalance()).

import { useDecryptedHandle } from "@tokenops/sdk/fhe/react";

const { status, value } = useDecryptedHandle({
  handle: viewResult?.handle,
  contractAddress: managerAddress,
  userDecryptor: () => useZamaSDK().relayer,
  relayerParams: { ...keypair, requestValidity, contractsChainId },
});

The relayer source resolves lazily per decrypt — the hook does NOT memoize the SDK client across renders, because user-decrypt is a one-shot action (no benefit to client caching).

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 — useful when the handle comes from a downstream query that hasn't resolved yet.
contractAddressAddress | undefinedThe contract that granted ACL access to the handle. The relayer enforces (handle, contractAddress, userAddress) triples — passing the wrong contract here returns an empty result with no diagnostic.
userDecryptorUserDecryptorSource | undefinedLazy or eager Zama RelayerSDK / MockFhevmInstance / RelayerWeb / RelayerNode. Recommended in React: userDecryptor: () => useZamaSDK().relayer — the SDK calls this per-decryption so it picks up the live RelayerSDK instance rather than a stale capture (CLAUDE.md Pitfall #3).
relayerParamsOmit<Parameters<UserDecryptor["userDecrypt"]>[0], "handleContractPairs"> | undefinedExtra params passed straight through to the relayer's userDecrypt. The Zama RelayerWeb / RelayerNode require privateKey, publicKey, signature, requestValidity, contractsChainId. MockFhevmInstance tolerates a partial shape. Hosts that wrap their own keypair management pass the full shape here.
enabledboolean | undefinedSkip the decrypt — defaults to false. Useful when the consumer wants to render an "Encrypted" placeholder until the user opts in.
Want to run a similar shape interactively? The Playground ships 8 ready presets across vesting / airdrop / disperse — deploy a manager, create a vesting, claim, and the airdrop / disperse 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