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.
WriteuseMutation

useMerkleClaimAndUnwrap

Claim a proof-bearing Merkle entry and route the allocation straight into the wrapper's unwrap, making to the underlying ERC-20 beneficiary.

Import
@tokenops/sdk/fhe-airdrop/react
Return
{ mutate, mutateAsync, isPending, error, data }
Lifecycle
Write

Description

Claim a proof-bearing Merkle entry and route the allocation straight into the wrapper's unwrap, making to the underlying ERC-20 beneficiary.

Self-only, unlike `useMerkleClaim`. This entrypoint takes no claim identity: the leaf and the accounting are both msg.sender, so an entry whose account is not the sender is refused before the write. Gate the button on sender === entry.account and fall back to useMerkleClaim for third-party claims. Also requires an unwrappable campaign - see useAirdropConfig().unwrappable.

A third party can still settle the same entry first through useMerkleClaim, after which an unwrap pays an encrypted zero; see MerkleClaimArgs.entry.

The amount is public from the claim transaction. With the stock wrapper the unwrapped amount is publicly decryptable at once (the emitted unwrapRequestId is its handle); finalizeUnwrap only releases the ERC-20. Only a plain claim keeps it confidential.

Resolves to the claim's transaction hash; the underlying ERC-20 moves only at the wrapper's later finalizeUnwrap. Pass the hash to useUnwrapRequest for the unwrapRequestId that call takes.

Invalidates: useClaimedAmount for the SENDING account on this instance. The contract advances claimedAmount[msg.sender] here, so the key is built from the sender resolved in onMutate (variables.account ?? walletClient.account) and NOT from entry.account the way useMerkleClaim does it. The two identities are equal on this path by construction - the client refuses a mismatch - but the divergence is deliberate: claim records the explicit claim identity, this records the caller. Do not unify them.

Signature

@tokenops/sdk/fhe-airdrop/react
ts
function useMerkleClaimAndUnwrap(options: AirdropInstanceClientOptions): UseMutationResult<Hex, Error, MerkleClaimArgs>;

Parameters

Shape of the object you pass to .mutate(args) is the SDK type MerkleClaimArgs. Inspect the type for the full shape (discriminated unions collapse to a tagged variant at call time).

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 useMerkleClaimAndUnwrap; pick another from the dropdown if you'd rather start there.

Example

@tokenops/sdk/fhe-airdrop/react · @example
tsx
const unwrapClaim = useMerkleClaimAndUnwrap({ address: airdropAddress });
await unwrapClaim.mutateAsync({ entry, to: erc20Beneficiary });

Pulled directly from the hook's TSDoc block — the same snippet your IDE shows on hover.

Errors

This mutation can reject with SDK-level, product-level, or generic-fallback errors. Product classes carry the offending value as fields — render them inline instead of a generic "transaction failed." See Airdrop v2 › Errors for the per-class recovery table.

Invalidation recipe

After this mutation succeeds, invalidate the queries it affects so consumer UI re-fetches fresh state. The SDK never auto-invalidates — that's a consumer decision (different apps cache different shapes).

patterns/invalidation.ts
ts
import { useQueryClient } from "@tanstack/react-query";

const queryClient = useQueryClient();
const merkleClaimAndUnwrap = useMerkleClaimAndUnwrap(/* options */);

merkleClaimAndUnwrap.mutate(args, {
  onSuccess() {
    // Coarse invalidation: refresh every cached read on this product surface.
    queryClient.invalidateQueries({
      queryKey: ["tokenops-sdk", "fhe-airdrop"],
    });
  },
});

See also

Other Write hooks in airdrop v2: