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.
Disperse 2.0 · Types · 35@tokenops/sdk/fhe-disperse

Disperse 2.0 type surface.

Every receipt-free write has a mined result and a Pending* twin that share one pending discriminant. Args that take an object accept a per-call gas; the preflight report carries typed blockerErrors only.

Args· 9

  • DisperseArgs{ token, mode, recipients, amounts, gasFeeOverride?, account?, gas? }

    Plaintext amounts in token base units; the SDK encrypts them. gasFeeOverride, when set, must equal recipients.length * gasFeeWei: the contract reverts on any other ETH value. At most 32 recipients in "direct", 30 in the wallet modes. disperse() takes DisperseArgs & ReceiptMode.

  • DisperseMode"wallet" | "wallet-token-fee" | "direct"

    Picks the entry point: subwallets with a per-recipient ETH fee, subwallets with a BPS token fee on the subtotals, or a direct confidentialTransferFrom with the ETH fee.

  • RegisterArgs{ token, account?, gas? }

    Token the new subwallets are approved for. register() takes RegisterArgs & ReceiptMode.

  • PreflightDisperseArgs{ user, token, recipients, amounts, mode }

    Same units and mode as the disperse you are about to send, so the report reflects the real call.

  • CalculateFeeArgs{ user, mode, recipients: number, totalTokens? }

    totalTokens is required for "wallet-token-fee".

  • DiscloseHandleArgs{ handle, party, account?, gas? }

    Grant persistent ACL on one handle the caller already holds. Append-only.

  • BatchDiscloseHandlesArgs{ handles, party, account?, gas? }

    The same grant on many handles in one transaction.

  • GetEncryptedFeeReserveArgs{ token, account?, gas? }

    Args of getEncryptedFeeReserve and useAccessEncryptedFeeReserve.

  • WithdrawTokenFeeArgs{ token, to, account?, gas? } & ({ amount, encryptor? } | { encryptedInput })

    Exactly one of a plaintext amount or a pre-built encryptedInput; passing both fails to compile. Build the input with encryptUint64 (or encryptUint64Batch) from @tokenops/sdk/fhe-disperse, which returns an EncryptedInput.

Results· 10

  • RegisterResult{ hash, wallets: [Address, Address] }

    Mined register(). wallets comes from the caller's own UserRegistered event.

  • PendingRegisterResult{ hash, wallets: undefined, pending: true }

    register() with waitForReceipt: false. From a Safe, hash is the safeTxHash.

  • DisperseResult{ hash, distributions: DisperseDistribution[] }

    Mined disperse(). Never empty: a receipt without a distribution event throws ReceiptEventNotFoundError.

  • PendingDisperseResult{ hash, distributions: undefined, pending: true }

    disperse() with waitForReceipt: false.

  • DisperseDistribution{ wallet?, recipients, requested, transferred }

    One row per WalletDistribution (up to two) or DirectDistribution. Decrypt requested with the singleton as contract, transferred with the token.

  • WithdrawTokenFeeResult{ hash, transferredHandle: Hex }

    Always a Hex on a mined result; may be less than requested because the contract caps at the reserve.

  • PendingWithdrawTokenFeeResult{ hash, transferredHandle: undefined, pending: true }

    withdrawTokenFee() with waitForReceipt: false.

  • DisclosureResult{ hash, discloser, party, disclosedHandles }

    Parsed from HandlesDisclosedToParty. Also exported from /fhe-disperse/react as the data type of both disclosure hooks.

  • PendingDisclosureResult{ hash, discloser: undefined, party: undefined, disclosedHandles: undefined, pending: true }

    Either disclosure with waitForReceipt: false.

  • EncryptedViewResult{ hash, handle }

    Returned by getEncryptedFeeReserve / useAccessEncryptedFeeReserve. Pass handle to a user-decrypt.

Preflight· 4

  • PreflightReport{ isUserRegistered, wallets, predictedWallets, hasApprovedSubwallets, hasApprovedSingleton: boolean, feeEth, feeTokenAmount?, batchLimit, batchOk, recipientChecks, amountsOk, subtotals?, ready, blockerErrors }

    hasApprovedSingleton is checked in every mode. batchOk is false over the on-chain cap or one input proof. Branch on each blockerErrors entry's code.

  • RecipientCheck{ address, ok, reason? }

    Per-recipient structural check (zero address and similar).

  • SubwalletApprovalState{ wallet0, wallet1, both }

    Returned by hasApprovedSubwallets; mirrored on PreflightReport.hasApprovedSubwallets.

  • PreflightResult{ ready, blockers: TokenOpsSdkError[] }

    The shared preflight contract from core, re-exported here. The disperse report names the same list blockerErrors.

Fees + config· 6

  • ConfidentialDisperseClientConfig{ publicClient, walletClient?, address?, chainId?, encryptor?, aclAddress?, gasHeadroomPercent?, telemetry? }

    Client constructor. chainId also picks the FHEVM ACL address.

  • FeeConfig{ gasFeeEnabled, tokenFeeEnabled, defaultGasFee, defaultTokenFee }

    Round-trips between getFeeConfig() and setFeeConfig().

  • UserFees{ isCustom, gasFeeWei, tokenFeeBps, gasFeeEnabled, tokenFeeEnabled }

    Resolved per-user fees with the global toggles applied.

  • CustomFee{ enabled, gasFeeWei, tokenFeeBps }

    Raw per-user override, before the global toggles.

  • CalculatedFee{ ethValue, tokenFeeAmount? }

    ethValue covers the gas fee; tokenFeeAmount is set only for "wallet-token-fee".

  • BatchLimits{ holding, direct, tokenFee }

    On-chain per-mode caps. 0n means no cap; the one-input-proof limit applies regardless.

Receipts, gas + hook options· 6

  • ReceiptModeReceiptMode<W>: { waitForReceipt: false } when W is false, otherwise { waitForReceipt?: W }

    The option kept off the *Args types. The default ReceiptMode is { waitForReceipt?: boolean }; Args & ReceiptMode with a runtime boolean gets the Mined | Pending union, narrowed by pending.

    Concept primer →
  • PendingWrite / MinedWrite{ pending: true } / { pending?: never }

    Every Pending* result extends PendingWrite and every mined result MinedWrite, so if (result.pending) narrows any of them.

  • GasOverride{ gas?: bigint }

    Per-call gas limit, sent as is instead of the padded estimate.

    Concept primer →
  • GasHeadroomOption{ gasHeadroomPercent?: number }

    Percent added to every estimate. Defaults to DEFAULT_GAS_HEADROOM_PERCENT (25).

    Concept primer →
  • DisperseHookOptionsBaseHookOptions & { encryptor?, aclAddress?, gasHeadroomPercent? }

    Options of the write hooks. Import from @tokenops/sdk/fhe-disperse/react, not the root subpath. BaseHookOptions is { address?, chainId?, telemetry? } and is exported there too.

  • ReadHookQueryOptions{ query?: Omit<UseQueryOptions, 'queryKey' | 'queryFn'> }

    query on every read hook. Import from @tokenops/sdk/fhe-disperse/react, not the root subpath. query.enabled can turn a ready query off, never an unready one on.

    Concept primer →