Recipe · Operations

Gas + custom fee plumbing

Manager clones charge either gas-side or token-side fees. ClaimArgs is a discriminated union, pass the matching branch or get ContractRevertError.

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.

components/Claim.tsx
ts
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.

components/Claim.tsx
ts
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.

See also