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 · Client@tokenops/sdk/fhe-disperse

ConfidentialDisperseClient

One singleton per chain, on mainnet and Sepolia. register() deploys two ERC-1167 subwallets the singleton controls on your behalf; disperse() then pays up to one input proof of recipients in a single transaction, each ACL-granted its own amount.

Construct

Headless TS — non-React consumers (Node, Vite, server workers). React hosts use the per-hook surface; same method names, lazy encryptor.

@tokenops/sdk/fhe-disperse
ts
import { createConfidentialDisperseClient } from "@tokenops/sdk/fhe-disperse";

const client = createConfidentialDisperseClient({
  publicClient,
  walletClient,
  // address optional: resolved from publicClient.chain.id
});

Methods

Read · 13

Recovery · 8

Configuration

ConfidentialDisperseClientConfig extends GasHeadroomOption. A malformed address or a bad gasHeadroomPercent throws from the constructor; the hooks keep that error instead of throwing during render, so their queries stay disabled and their mutations reject with it.

publicClientviem public client for reads. Required.
walletClient?viem wallet client for writes. Omit for a read-only client.
address?Singleton override. Defaults to DEPLOYED_ADDRESSES.fheDisperse.disperseConfidentialSingleton[chainId], set on mainnet and Sepolia.
chainId?Chain used for the default singleton and the FHEVM ACL address. Defaults to publicClient.chain?.id; a client built with chainId and a chain-less publicClient now resolves its ACL address from it.
encryptor?Eager Encryptor or lazy () => Encryptor | undefined, used by disperse and withdrawTokenFee. A lazy factory must return an encryptor for the active account after a wallet switch.
aclAddress?FHEVM ACL override, used by getEncryptedFeeReserve to find the granted handle.
gasHeadroomPercent?Percent added to every write's gas estimate. Defaults to DEFAULT_GAS_HEADROOM_PERCENT (25); 0 sends the bare estimate.
telemetry?Telemetry sink. Emits fhe-disperse.client.init and brackets every public write with a span. No-op by default.

Receipt-free writes and gas

Each of these methods is overloaded on waitForReceipt. Omitted or true, it waits and returns the mined result with every field set; false returns on submission with a result carrying pending: true. getEncryptedFeeReserve has no receipt-free form. Every write that takes an argument object also accepts gas; the positional admin setters (setFeeConfig, setCustomFee, the batch-size setters, pause, the rescues, grantRole) use the client's gasHeadroomPercent.

MethodPending resultReceipt-derived fields
registerPendingRegisterResultwallets: undefined - read the UserRegistered log
dispersePendingDisperseResultdistributions: undefined - read the WalletDistribution / DirectDistribution logs
withdrawTokenFeePendingWithdrawTokenFeeResulttransferredHandle: undefined - read the TokenFeeWithdrawn log
discloseHandleToPartyPendingDisclosureResultdiscloser, party, disclosedHandles undefined - read the HandlesDisclosedToParty log
batchDiscloseHandlesToPartyPendingDisclosureResultsame as discloseHandleToParty
@tokenops/sdk/fhe-disperse
ts
import type { DisperseArgs, ReceiptMode } from "@tokenops/sdk/fhe-disperse";

// Literal false: the pending overload.
const pending = await client.register({ token, waitForReceipt: false });
pending.wallets; // undefined

// A runtime boolean (what a hook passes): the union, narrowed by `pending`.
async function send(args: DisperseArgs & ReceiptMode) {
  const result = await client.disperse(args);
  if (result.pending) return result.hash; // safeTxHash from a Safe
  return result.distributions; // DisperseDistribution[], never empty
}

// Per-call gas limit, sent as is instead of the padded estimate.
await client.approveTokenOnWallets({ token, gas: 400_000n });

Shared behaviour: Receipt-free writes, Gas headroom, Encryptors.