1. Resolve fee posture#
Each manager carries its own fee posture, baked immutably into the clone bytecode at deployment time (the factory'ssetCustomFeeonly changes the defaults applied to a creator's future deployments — it never alters a running manager). Read it once per manager, the result is cacheable per-clone.
import { useManagerFeeInfo } from "@tokenops/sdk/fhe-vesting/react";
const { data: feeInfo } = useManagerFeeInfo({ address: managerAddress });
// feeInfo → { feeType: FeeType (0 = Gas, 1 = DistributionToken), fee: bigint }2. Submit the matching branch#
Gas fees attach as value on the tx. Token (DistributionToken) fees are deducted on-chain, so omit value on that branch — no fee handle to generate.
import { FeeType } from "@tokenops/sdk/fhe-vesting";
import { useClaim } from "@tokenops/sdk/fhe-vesting/react";
const claim = useClaim({ address: managerAddress });
claim.mutate(
feeInfo.feeType === FeeType.Gas
? { feeType: FeeType.Gas, vestingId, value: feeInfo.fee }
: { feeType: FeeType.DistributionToken, vestingId },
);Quote-before-claim#
Render the fee inline so users know what they're paying. The story flow on /stories/vesting demonstrates this, the claim button surfaces the cost in the same row.
How much gas do FHE transactions use?#
FHE writes are heavier than plain ERC-20 transfers, but far below the folklore numbers that circulate. Across the full on-chain history of the deployed contracts (2,648 transactions, Sepolia + mainnet, surveyed July 2026), no TokenOps FHE transaction has ever used more than 14.5M gas. Typical single actions land around 0.35M–1.0M: creating an airdrop ≈ 0.36M, funding it ≈ 0.5M, deploying a vesting manager ≈ 0.97M, a vesting claim ≈ 0.78M.
Batch operations (batchCreateVesting, disperseConfidentialTokens) scale linearly at roughly 0.4M–0.46M gas per item, and the contract-enforced batch limits keep the worst observed case under 15M — inside every mainstream provider's defaults, so no special RPC configuration is needed.
If a transaction fails before submission, distinguish an estimation failure from a real revert: a provider error or timeout on eth_estimateGascarries no revert data (retry or switch RPC), while a real revert carries a selector the SDK decodes into a typed error — run the product's preflight* helper to get the actionable blocker instead of guessing.