Skip to main content

fhe

Interfaces

CreateMockEncryptorOptions

Defined in: fhe/mock-encryptor.ts:55

Configuration for createMockEncryptor. Most consumers only need rpcUrl; everything else has deterministic defaults that match what pnpm fhevm:up deploys.

Properties

PropertyTypeDescriptionDefined in
rpcUrl?... | ...JSON-RPC endpoint of a local Anvil node with FHEVM host contracts already deployed (i.e. pnpm fhevm:up succeeded). Defaults to http://127.0.0.1:8545.fhe/mock-encryptor.ts:61
chainId?... | ...Chain id of the local node. Defaults to 31337 (forge-fhevm default). Override only if you ran pnpm fhevm:up with a non-default --chain-id.fhe/mock-encryptor.ts:66
hostAddresses?... | ...Mock-utils host-contract addresses. Defaults to the Zama HardhatConfig deterministic deployment forge-fhevm produces. Override if you brought the FHEVM host contracts up some other way and they landed at different addresses.fhe/mock-encryptor.ts:73
coprocessorSignerPrivateKey?... | ...Override the coprocessor signer private key. Defaults to the deterministic forge-fhevm signer; you only need this if you deployed the host contracts with a custom KMS / coprocessor signer set.fhe/mock-encryptor.ts:87

MockEncryptor

Defined in: fhe/mock-encryptor.ts:92

Returned by createMockEncryptor. Carries the underlying MockFhevmInstance so consumers who need user-decrypt can reach it.

Extends

Properties

PropertyModifierTypeDescriptionDefined in
instancereadonlyunknownThe underlying MockFhevmInstance. Use this for userDecrypt flows that the SDK's structural Encryptor interface doesn't expose. Process-scoped: handles produced by one instance can only be decrypted by that same instance (the cleartext db lives in memory).fhe/mock-encryptor.ts:99
chainIdreadonlynumberLocal chain id this encryptor is bound to.fhe/mock-encryptor.ts:101

Methods

encrypt()
encrypt(params): Promise<...>;

Defined in: fhe-vesting/encryption.ts:42

Parameters
ParameterType
params{ values: ...; contractAddress: ...; userAddress: ...; }
params.values...
params.contractAddress...
params.userAddress...
Returns

Promise<...>

Inherited from

Encryptor.encrypt


MintMockERC7984Args

Defined in: fhe/mock-erc7984.ts:56

Arguments for mintMockERC7984. Mirrors the shape of import("./operators.js").SetOperatorArgs so consumers wiring both helpers in sequence reuse the same client / account references.

Properties

PropertyTypeDescriptionDefined in
publicClient{ }Read-only viem client for receipt waiting.fhe/mock-erc7984.ts:58
walletClient{ }Wallet client used to send the mint call.fhe/mock-erc7984.ts:60
token`0x${(...)}`MockERC7984Token contract address.fhe/mock-erc7984.ts:62
to`0x${(...)}`Recipient of the freshly-minted ciphertext balance.fhe/mock-erc7984.ts:64
amountbigintAmount to mint, base units. uint64 upper bound (2**64 - 1 ≈ 1.8e+19) is the on-chain ceiling; the helper rejects bigints above that BEFORE viem encodes them so the revert message is the SDK's, not viem's.fhe/mock-erc7984.ts:70
account?... | ... | ...Account paying the mint. Same `AccountAddressshape as import("./operators.js").SetOperatorArgs.account — passing the fullAccount object preserves the local-signing path (eth_sendRawTransaction); passing only an Addressfalls back toeth_sendTransaction` which most public RPCs reject.
waitForReceipt?... | ... | ...If true (default), waits for the transaction to be mined before returning. Set to false for fire-and-forget flows where the caller waits separately.fhe/mock-erc7984.ts:84
telemetry?... | ...Optional telemetry sink — span emits as fhe.mintMockERC7984.fhe/mock-erc7984.ts:86

MintMockERC7984Result

Defined in: fhe/mock-erc7984.ts:92

Result of mintMockERC7984: the tx hash plus the mined block number (or 0n when waitForReceipt: false). Shape mirrors the docs-site stopgap's return so the migration is a drop-in.

Properties

PropertyTypeDefined in
hash`0x${(...)}`fhe/mock-erc7984.ts:93
blockNumberbigintfhe/mock-erc7984.ts:94

CreateMockErc7984ClientArgs

Defined in: fhe/mock-erc7984.ts:197

Args for createMockErc7984Client.

Properties

PropertyTypeDescriptionDefined in
publicClient{ }-fhe/mock-erc7984.ts:198
walletClient{ }-fhe/mock-erc7984.ts:199
address`0x${(...)}`-fhe/mock-erc7984.ts:200
telemetry?... | ...Optional telemetry forwarded to every method call.fhe/mock-erc7984.ts:202

MockErc7984Client

Defined in: fhe/mock-erc7984.ts:208

Small client returned by createMockErc7984Client. Mirrors the broader SDK client shape ({ address, mint }) so consumers wiring multiple helpers can stash the client once and reuse the bound address.

Properties

PropertyModifierTypeDefined in
addressreadonly`0x${(...)}`fhe/mock-erc7984.ts:209

Methods

mint()
mint(args): Promise<...>;

Defined in: fhe/mock-erc7984.ts:216

Mint to to. The bound address is forwarded as the token — pass everything else inline. Same MintMockERC7984Args shape minus the token, publicClient, walletClient, telemetry fields the client already owns.

Parameters
ParameterType
argsOmit<..., ...>
Returns

Promise<...>


SetOperatorArgs

Defined in: fhe/operators.ts:71

Properties

PropertyTypeDescriptionDefined in
publicClient{ }Read-only viem client for receipt waiting.fhe/operators.ts:73
walletClient{ }Wallet client used to send the setOperator call.fhe/operators.ts:75
account?... | ... | ...Account that owns the tokens being authorized. Accepts either a full viem Account object (e.g. from privateKeyToAccount) or an Address string. Mirrors CreateVestingArgsCommon.account and viem's own writeContract flexibility. Fallback hierarchy when this arg is omitted: 1. walletClient.account — the full account object the wallet was built with (preferred — viem signs locally → eth_sendRawTransaction). 2. throws TokenOpsContractError — no signer available. **Why `AccountAddressand not justAddress:** viem's writeContractcallseth_sendTransaction(custodial-wallet path, rejected by Alchemy / Infura / public RPCs) when handed a string address, andeth_sendRawTransaction(local-signing path) when handed anAccountobject with asignTransactionmethod. Pass the full object you got fromprivateKeyToAccount` to get local signing; pass an address only when the wallet has multiple custodial accounts and you want to pick one by name.
token`0x${(...)}`ERC-7984 token contract address.fhe/operators.ts:102
spender`0x${(...)}`Address being authorized to pull tokens — typically a manager clone (/fhe-vesting), an airdrop clone (/fhe-airdrop), or the disperse singleton (/fhe-disperse).fhe/operators.ts:108
deadline?... | ...uint48 unix timestamp after which the operator authorization expires. Defaults to ERC7984_OPERATOR_MAX_DEADLINE ("forever" within uint48).fhe/operators.ts:114
waitForReceipt?... | ... | ...If true (default), waits for the transaction to be mined before returning. Set to false for fire-and-forget flows where the caller waits separately.fhe/operators.ts:120
telemetry?... | ...Optional telemetry sink — span emits as fhe.setOperator.fhe/operators.ts:122

RevokeOperatorArgs

Defined in: fhe/operators.ts:246

Arguments for revokeOperator. Identical to SetOperatorArgs minus the deadline field — revoke is a fixed until=0 call that cannot accept a non-zero deadline (the ERC-7984 contract treats 0 as the revoke convention; any non-zero until would be a re-grant, not a revoke).

Properties

PropertyTypeDescriptionDefined in
publicClient{ }Read-only viem client for receipt waiting.fhe/operators.ts:248
walletClient{ }Wallet client used to send the setOperator(..., 0) call.fhe/operators.ts:250
account?... | ... | ...Account that owns the tokens. Same fallback hierarchy as SetOperatorArgs — preserves the Account object when present so viem signs locally via eth_sendRawTransaction rather than the custodial eth_sendTransaction path that public RPCs reject.fhe/operators.ts:257
token`0x${(...)}`ERC-7984 token contract address.fhe/operators.ts:259
spender`0x${(...)}`Address whose operator authorization should be revoked — typically a stale manager clone (/fhe-vesting), a closed airdrop clone (/fhe-airdrop), or a singleton no longer in use (/fhe-disperse).fhe/operators.ts:265
waitForReceipt?... | ... | ...If true (default), waits for the transaction to be mined before returning. Set to false for fire-and-forget flows where the caller waits separately.fhe/operators.ts:271
telemetry?... | ...Optional telemetry sink — span emits as fhe.revokeOperator.fhe/operators.ts:273

ScaledRatio

Defined in: fhe/scale-ratio.ts:68

Properties

PropertyTypeDefined in
numeratorbigintfhe/scale-ratio.ts:69
denominatorbigintfhe/scale-ratio.ts:70

ScaleRatioArgs

Defined in: fhe/scale-ratio.ts:73

Properties

PropertyTypeDescriptionDefined in
numeratorbigint-fhe/scale-ratio.ts:74
denominatorbigint-fhe/scale-ratio.ts:75
minDenominator?... | ...Target denominator for the scaled output. Defaults to FHE_SPLIT_DENOMINATOR (90_090_000) — the privacy-preserving constant every confidential split must agree on. Override only for non-split contract surfaces that have a different precision floor.fhe/scale-ratio.ts:82
width?... | ...Bit-width the scaled values are validated against. Defaults to "uint128". Pass "uint64" for confidential split paths whose encrypted numerator goes through encryptUint64, so the bound the helper reports matches the bound the encryption call would enforce.fhe/scale-ratio.ts:89

CreateSepoliaEncryptorWebOpts

Defined in: fhe/sepolia-encryptor-web.ts:62

Configuration for createSepoliaEncryptorWeb. Minimal by design: the browser path doesn't expose worker pool sizing or storage knobs (the Web Worker is single-threaded by default, and RelayerWeb already defaults to IndexedDBStorage for FHE artifact caching).

Properties

PropertyTypeDescriptionDefined in
publicClient{ }Viem PublicClient — used only to resolve the chain id for the encryptor's getChainId callback. The encryptor itself never reads from the chain; encrypted handles + proofs are produced locally and the relayer is queried over HTTP.fhe/sepolia-encryptor-web.ts:67
walletClient{ }Viem WalletClient — kept on the options object for symmetry with the Node helper, even though RelayerWeb doesn't need it. Consumers compose the encryptor with the same client they pass to the SDK's vesting / disperse / airdrop factories.fhe/sepolia-encryptor-web.ts:72
relayerUrl?... | ...Override the Zama relayer URL. Defaults to Zama's public Sepolia testnet relayer (https://relayer.testnet.zama.org/v2) baked into @zama-fhe/sdk's SepoliaConfig. Set this only for private relayer forks (rare; Zama-internal).fhe/sepolia-encryptor-web.ts:79
chainId?... | ...Override the chain id this encryptor binds to. Defaults to SEPOLIA_CHAIN_ID. Pass MAINNET_CHAIN_ID for the mainnet relayer once Zama enables it; pre-mainnet this stays Sepolia.fhe/sepolia-encryptor-web.ts:85
logger?... | ...Optional logger for tracing worker lifecycle and request timing. Same shape as the Node helper. Mirrored here for surface parity — when a consumer migrates a server-side script to a browser app, the logger config moves over unchanged. Any missing methods are filled with no-op stubs before reaching the underlying Zama relayer (see createSepoliaEncryptor for the background on why).fhe/sepolia-encryptor-web.ts:96

SepoliaEncryptorWeb

Defined in: fhe/sepolia-encryptor-web.ts:106

Returned by createSepoliaEncryptorWeb. Same structural Encryptor contract as the Node version, plus the underlying RelayerWeb for callers that need userDecrypt / publicDecrypt (which the structural Encryptor interface doesn't surface) or explicit terminate() on page unload.

Extends

Properties

PropertyModifierTypeDescriptionDefined in
instancereadonlyunknownThe underlying RelayerWeb. Typed unknown to avoid leaking the optional @zama-fhe/sdk peer dep into the SDK's public types. Cast to import("@zama-fhe/sdk").RelayerWeb at the use site.fhe/sepolia-encryptor-web.ts:112
chainIdreadonlynumberChain id this encryptor is bound to (11155111 for Sepolia).fhe/sepolia-encryptor-web.ts:114

Methods

encrypt()
encrypt(params): Promise<...>;

Defined in: fhe-vesting/encryption.ts:42

Parameters
ParameterType
params{ values: ...; contractAddress: ...; userAddress: ...; }
params.values...
params.contractAddress...
params.userAddress...
Returns

Promise<...>

Inherited from

Encryptor.encrypt

terminate()
terminate(): void;

Defined in: fhe/sepolia-encryptor-web.ts:121

Tear down the Web Worker. The browser path doesn't require this — the worker is GC'd when the page unloads — but long-lived SPAs that swap encryptors (chain switch, user logout) should call it to free the WASM heap explicitly.

Returns

void


SepoliaEncryptorLogger

Defined in: fhe/sepolia-encryptor.ts:46

Subset of @zama-fhe/sdk/node's GenericLogger we accept. Mirrored structurally so consumers don't need to import the optional peer dep just to type-narrow a logger arg.

Properties

PropertyTypeDefined in
debug?... | ...fhe/sepolia-encryptor.ts:47
info?... | ...fhe/sepolia-encryptor.ts:48
warn?... | ...fhe/sepolia-encryptor.ts:49
error?... | ...fhe/sepolia-encryptor.ts:50

SepoliaEncryptorStorage

Defined in: fhe/sepolia-encryptor.ts:58

Subset of @zama-fhe/sdk/node's GenericStorage we accept. Mirrored structurally for the same reason as SepoliaEncryptorLogger. The RelayerNode caches FHE public-key + params here across sessions; default is an in-process memory map. Pass a redis-backed implementation for cross-restart persistence in long-lived Node servers.

Methods

get()
get<T>(key): Promise<...>;

Defined in: fhe/sepolia-encryptor.ts:59

Type Parameters
Type ParameterDefault type
Tunknown
Parameters
ParameterType
keystring
Returns

Promise<...>

set()
set<T>(key, value): Promise<...>;

Defined in: fhe/sepolia-encryptor.ts:60

Type Parameters
Type ParameterDefault type
Tunknown
Parameters
ParameterType
keystring
valueT
Returns

Promise<...>

delete()
delete(key): Promise<...>;

Defined in: fhe/sepolia-encryptor.ts:61

Parameters
ParameterType
keystring
Returns

Promise<...>


CreateSepoliaEncryptorOptions

Defined in: fhe/sepolia-encryptor.ts:68

Configuration for createSepoliaEncryptor. All fields are optional; defaults match the Zama public Sepolia relayer.

Properties

PropertyTypeDescriptionDefined in
relayerUrl?... | ...Override the Zama relayer URL. Defaults to Zama's public Sepolia testnet relayer (https://relayer.testnet.zama.org/v2) baked into @zama-fhe/sdk/node's SepoliaConfig. Set this only when running against a private relayer fork (rare; usually only Zama internal).fhe/sepolia-encryptor.ts:75
chainId?... | ...Override the chain id this encryptor binds to. Defaults to SEPOLIA_CHAIN_ID. Pass MAINNET_CHAIN_ID for the mainnet relayer once Zama enables it; pre-mainnet this stays Sepolia.fhe/sepolia-encryptor.ts:81
poolSize?... | ...Worker pool size. Defaults to min(os.availableParallelism(), 4) inside @zama-fhe/sdk. Each worker loads ~50–100 MB of WASM — decrease to 1–2 on memory-constrained hosts, increase to match CPU cores for high-throughput batch encryption.fhe/sepolia-encryptor.ts:88
logger?... | ...Optional logger for tracing worker lifecycle and request timing. Useful during onboarding to see when the relayer round-trips happen; remove for production to avoid noisy logs.fhe/sepolia-encryptor.ts:94
fheArtifactStorage?... | ...Persistent storage for FHE public key + params cache. Defaults to an in-process memory map (lost on restart). Pass a redis-backed GenericStorage for cross-restart persistence in long-lived servers — the public params are several MB; re-fetching on every restart adds seconds of cold start.fhe/sepolia-encryptor.ts:102
fheArtifactCacheTTL?... | ...Cache TTL in seconds for FHE public material. Default: 86400 (24h). Set to 0 to revalidate on every operation (rare; only useful for tests that want to exercise the fetch path).fhe/sepolia-encryptor.ts:108

SepoliaEncryptor

Defined in: fhe/sepolia-encryptor.ts:116

Returned by createSepoliaEncryptor. Carries the underlying RelayerNode so consumers who need user-decrypt or worker lifecycle control can reach it, plus the chain id this encryptor is bound to.

Extends

Properties

PropertyModifierTypeDescriptionDefined in
instancereadonlyunknownThe underlying RelayerNode. Use this for userDecrypt / publicDecrypt flows the SDK's structural Encryptor interface doesn't surface. Typed unknown to avoid importing the optional @zama-fhe/sdk peer dep into the SDK's public types.fhe/sepolia-encryptor.ts:123
chainIdreadonlynumberChain id this encryptor is bound to (11155111 for Sepolia).fhe/sepolia-encryptor.ts:125

Methods

encrypt()
encrypt(params): Promise<...>;

Defined in: fhe-vesting/encryption.ts:42

Parameters
ParameterType
params{ values: ...; contractAddress: ...; userAddress: ...; }
params.values...
params.contractAddress...
params.userAddress...
Returns

Promise<...>

Inherited from

Encryptor.encrypt

terminate()
terminate(): void;

Defined in: fhe/sepolia-encryptor.ts:133

Tear down the underlying worker thread pool. Must be called before process.exit() (or at the end of any Node script) — RelayerNode owns node:worker_threads that keep the event loop alive. Forgetting to call terminate() is the #1 reason Sepolia scripts hang after main() resolves.

Returns

void


EncryptedInput

Defined in: fhe/types.ts:18

A single externalEuint64 ciphertext: the on-chain handle plus the KMS input proof that authorises it. Produced by encryptUint64 and consumed by every @tokenops/sdk write method that takes an encrypted amount.

The handle and proof are bound to the (contractAddress, userAddress) pair passed at encryption time and cannot be replayed against a different contract or sender. Field names match the on-chain calldata layout (bytes32 handle, bytes inputProof) so the value spreads directly into contract calls.

The current SDK only produces uint64 ciphertexts. If a future version adds encryption helpers for other widths (e.g. encryptUint128), this type may be specialised; existing uint64 usage will keep type-checking.

Properties

PropertyTypeDefined in
handle`0x${(...)}`fhe/types.ts:19
inputProof`0x${(...)}`fhe/types.ts:20

EncryptedInputs

Defined in: fhe/types.ts:30

N externalEuint64 ciphertexts sharing a single KMS input proof. One proof per batch is cheaper than N independent proofs and is the shape the encryptor returns from a batched encrypt({ values: [...] }) call.

handles[i] corresponds to the i-th plaintext value passed in.

Properties

PropertyTypeDefined in
handles...[]fhe/types.ts:31
inputProof`0x${(...)}`fhe/types.ts:32

EncryptedViewResult

Defined in: fhe/types.ts:44

Return shape for SDK methods that perform an on-chain encrypted-view tx — the contract emits FHE.allow(handle, msg.sender) and the SDK extracts handle from the receipt's ACL Allowed event.

Pass handle to the Zama relayer's userDecrypt to obtain the plaintext. hash is the tx that committed the persistent ACL grant — surface it if your UI needs to show the receipt.

Properties

PropertyTypeDefined in
handle`0x${(...)}`fhe/types.ts:45
hash`0x${(...)}`fhe/types.ts:46

Type Aliases

ScaleRatioWidth

type ScaleRatioWidth = ... | ...;

Defined in: fhe/scale-ratio.ts:66

Bit-width to validate the scaled numerator/denominator against.

  • "uint64" matches the encrypted-numerator width every confidential split path actually uses (the SDK routes through encryptUint64). Hit splitVesting-style call sites with this so the validator's bound matches the encryption path's bound — same InvalidArgumentError instead of a less specific EncryptionFailedError downstream.
  • "uint128" is the legacy default kept for non-split contract surfaces that the helper might also serve in the future.

EncryptedInput64

type EncryptedInput64 = EncryptedInput;

Defined in: fhe/types.ts:56

Deprecated

Use EncryptedInput. Earlier versions of @tokenops/sdk/fhe exported this name with field proof, which did not match the rest of the SDK or the on-chain calldata layout (the contracts accept bytes inputProof). This alias points at the corrected shape and will be removed in the next major.


EncryptedHandle

type EncryptedHandle = Hex;

Defined in: fhe/types.ts:62

Deprecated

Use Hex from viem directly. This alias added no narrowing beyond Hex and will be removed in the next major.


ExternalInputProof

type ExternalInputProof = Hex;

Defined in: fhe/types.ts:68

Deprecated

Use Hex from viem directly. This alias added no narrowing beyond Hex and will be removed in the next major.

Variables

FHEVM_ACL_ADDRESS_BY_CHAIN

const FHEVM_ACL_ADDRESS_BY_CHAIN: {
31337: ...;
11155111: ...;
1: ...;
};

Defined in: fhe/acl.ts:25

FHEVM ACL contract addresses indexed by chain id. Encrypted-view helpers in product modules (fhe-vesting, fhe-airdrop, fhe-disperse) filter receipt logs by this address to identify ACL grants emitted during the tx — picking the wrong address means the strict-singleton check spuriously fails or, worse, returns the wrong handle.

Keep this map as the single source of truth across products. Update all three entries together when Zama publishes new host contracts.

  • Hardhat / Anvil (forge-fhevm) — see @zama-fhe/sdk HardhatConfig.
  • Sepolia — SepoliaConfig.aclContractAddress.
  • Mainnet — MainnetConfig.aclContractAddress.

Prefer the accessors getFhevmAclAddress / requireFhevmAclAddress over reaching into this object directly — they centralise chain-id resolution and the typed-error policy. Indexing the map directly is still supported for advanced consumers who need raw registry access.

Type Declaration

31337
readonly 31337: ... = "0x50157CFfD6bBFA2DECe204a89ec419c23ef5755D";
11155111
readonly 11155111: ... = "0xf0Ffdc93b7E186bC2f8CB3dAA75D86d1930A433D";
1
readonly 1: ... = "0xcA2E8f1F656CD25C01F05d0b243Ab1ecd4a8ffb6";

ACL_ALLOWED_EVENT

const ACL_ALLOWED_EVENT: {
};

Defined in: fhe/acl.ts:38

Allowed(address indexed caller, address indexed account, bytes32 handle) — emitted by the FHEVM ACL contract whenever a handle is granted to an address. Encrypted-view helpers parse this from the tx receipt to extract the handle the contract granted to the caller; using simulateContract for the same purpose returns a divergent handle that has no ACL grant.


erc7984OperatorAbi

const erc7984OperatorAbi: readonly [..., ..., ...];

Defined in: fhe/erc7984-abi.ts:9


createLocalFhevmEncryptor

const createLocalFhevmEncryptor: (options) => ... = createMockEncryptor;

Defined in: fhe/mock-encryptor.ts:453

Alias for createMockEncryptor. Some docs and consumer agents reach for the more-descriptive name; both resolve to the same implementation.

Construct an SDK-shaped Encryptor backed by MockFhevmInstance against a local FHEVM-ready Anvil node (pnpm fhevm:up). One call replaces the 7-address MockFhevmInstance.create boilerplate every local-chain consumer used to copy from node_modules/@fhevm/mock-utils.

Parameters

ParameterType
options...

Returns

...

Example

import { createMockEncryptor } from "@tokenops/sdk/fhe";

const encryptor = await createMockEncryptor({ rpcUrl: "http://127.0.0.1:8545" });
const mgr = createConfidentialVestingManagerClient({ publicClient, walletClient, address, encryptor });
await mgr.createVesting({ params, amount: 1_000_000n });

Remarks

MockFhevmInstance is process-scoped: handles produced by one instance are only decryptable by that same instance. For end-to-end encrypt → submit → decrypt loops, keep one encryptor alive for the whole run and serialize state (vestingId, manager, etc.) to disk between steps. See /concepts/encryption for the recommended pattern.


MOCK_ERC7984_MINT_ABI

const MOCK_ERC7984_MINT_ABI: readonly [...];

Defined in: fhe/mock-erc7984.ts:40

Minimal mint(address,uint64) ABI fragment. Embedded inline (rather than imported from a shared mock-token JSON artifact) because the selector is stable across every ERC-7984-conformant mock — production ERC-7984s with a mint(address,uint64) shape are accepted by the same fragment. No artifact dependency.

The contract signature is:

function mint(address to, uint64 amount) external;

ERC7984_SET_OPERATOR_ABI

const ERC7984_SET_OPERATOR_ABI: readonly [...];

Defined in: fhe/operators.ts:48

Minimal setOperator ABI fragment. Embedded inline (rather than imported from a shared mock-token ABI) because every ERC-7984-conformant token — production or mock — exposes this exact 4-byte selector. No artifact dependency.

The contract signature is:

function setOperator(address operator, uint48 until) external;

uint48 upper bound (2**48 - 1 ≈ 8.9e+14) is comfortably past year 9999 in unix seconds, so a "far-future" deadline is structurally safe.


ERC7984_OPERATOR_MAX_DEADLINE

const ERC7984_OPERATOR_MAX_DEADLINE: bigint;

Defined in: fhe/operators.ts:69

Far-future uint48 deadline. The on-chain until parameter is a uint48 unix timestamp; this constant is the maximum value the type can hold (2**48 - 1). Use as the default deadline when a consumer doesn't care about expiry — typical for local-chain dev loops and end-to-end fixture setup. For production flows, scope the deadline to the expected operation window (e.g. Date.now()/1000 + 3600).


FHE_SPLIT_DENOMINATOR

const FHE_SPLIT_DENOMINATOR: 90090000n = 90_090_000n;

Defined in: fhe/scale-ratio.ts:44

Fixed plaintext denominator used by every confidential split call.

= LCM(1..16, 10_000) = 2⁴ × 3² × 5⁴ × 7 × 11 × 13 = 90,090,000.

The denominator lives in plaintext (calldata or storage). Sizing it per-call to fit each specific split would leak the split's shape — a 1/2 split would use a different plaintext denominator than a 1/7 split, and observers could distinguish them without decrypting anything. Pinning every split to a single universal constant removes that side channel.

90_090_000 specifically is the smallest integer divisible by every common human split shape we support, in two flavours:

  • n/m with m ∈ 1..16 (halves, thirds, …, sixteenths and their combinations) — produces an exact integer numerator because m divides 90_090_000.
  • o/10_000 (basis points, o ∈ 0..10_000) — produces an exact integer numerator because 90_090_000 = 10_000 × 9_009, so bps maps to bps × 9_009.

No rounding artifacts in either case — the denominator itself is the only signal an observer sees, and it never changes, so the leak surface is zero. Use the share builder to construct ratios from either shape ergonomically.

Overflow is not a concern. The confidential-vesting contract upcasts the encrypted numerator to euint128 before multiplying by the holder balance, so the intermediate amount × numerator math happens in euint128 space (max ~3.4 × 10³⁸). For a 6-decimal ERC-7984 balance (max ~1.84 × 10¹⁹) and our denominator (~9 × 10⁷) the product tops out at ~1.7 × 10²⁷ — eleven orders of magnitude under the euint128 ceiling. The plaintext denominator itself fits trivially in the contract's uint128 denominator parameter.

Do NOT shrink this. All split-style SDK methods must use the same value — the leak surface is only zero when every product agrees on one constant. Today that's fhe-vesting splitVesting; future split-style surfaces (weighted disperses, weighted airdrops if added) must pin to this same constant.


share

const share: {
fraction: ...;
basisPoints: ...;
};

Defined in: fhe/scale-ratio.ts:210

Guided builders for the two split shapes the SDK supports as exact-integer numerators over FHE_SPLIT_DENOMINATOR (90_090_000 = LCM(1..16, 10_000)).

Use these when you know your split as one of:

  • a simple fraction n/m with m ∈ 1..16 (halves, thirds, …, sixteenths), or
  • a basis-point amount bps/10_000 with bps ∈ 0..10_000 (1 bp = 0.01%, 100 bp = 1%, 10_000 bp = 100%).

Both shapes land on 90_090_000 with no rounding artifacts. The returned ScaledRatio is ready to pass to split-style SDK calls with preScaled: true — the auto-scaling path is skipped because the math has already been done exactly.

Type Declaration

fraction()
readonly fraction(numerator, denominator): ...;

Build a ScaledRatio from a simple fraction n/m.

  • m must be in 1..16 — every integer in this range divides FHE_SPLIT_DENOMINATOR cleanly, so the result is exact.
  • n must be in 0..m0 is a zero-share (no-op split) and m itself is the whole position.

Both arguments accept number (must be an integer) or bigint — use whichever is convenient at the call site.

Parameters
ParameterType
numerator...
denominator...
Returns

...

Throws

InvalidArgumentError if m is outside 1..16 or n is outside 0..m, or either input is a non-integer number.

basisPoints()
readonly basisPoints(bps): ...;

Build a ScaledRatio from a basis-point amount.

bps must be in 0..10_0000 is a zero-share and 10_000 is the whole position (= 100%). 10_000 divides FHE_SPLIT_DENOMINATOR cleanly, so the result is exact: bps × 9_009 over 90_090_000.

Accepts number (must be an integer) or bigint.

Parameters
ParameterType
bps...
Returns

...

Throws

InvalidArgumentError if bps is outside 0..10_000, or is a non-integer number.

Examples

share.fraction(1, 3) // → { numerator: 30_030_000n, denominator: 90_090_000n }
share.basisPoints(250) // → { numerator: 2_252_250n, denominator: 90_090_000n } // 2.5%
const ratio = share.basisPoints(50); // 0.5%
await manager.splitVesting({
vestingId,
numerator: ratio.numerator,
denominator: ratio.denominator,
preScaled: true, // skip auto-scaling; share already did it
newRecipient,
});

SEPOLIA_CHAIN_ID

const SEPOLIA_CHAIN_ID: 11155111;

Defined in: fhe/sepolia-encryptor.ts:39

Sepolia testnet chain id (11155111). Re-exported as a typed literal so consumers indexing DEPLOYED_ADDRESSES against this constant get the narrow return type, not Address | undefined.


MAINNET_CHAIN_ID

const MAINNET_CHAIN_ID: 1;

Defined in: fhe/sepolia-encryptor.ts:41

Mainnet chain id (1). Same use as SEPOLIA_CHAIN_ID.

Functions

getFhevmAclAddress()

function getFhevmAclAddress(chainId): ... | ...;

Defined in: fhe/acl.ts:51

Resolve the FHEVM ACL contract address for chainId, returning undefined when the chain isn't recognised. Mirrors the get*Address shape in core/addresses.ts.

Use this when the caller wants to handle "no ACL on this chain" without a throw — e.g. constructing a product client lazily and deferring the error to first encrypted-view use.

Parameters

ParameterType
chainIdnumber

Returns

... | ...


requireFhevmAclAddress()

function requireFhevmAclAddress(chainId, clientLabel): `0x${(...)}`;

Defined in: fhe/acl.ts:69

Resolve the FHEVM ACL contract address for chainId, throwing DeploymentAddressUnavailableError when it can't be determined. Mirrors the require*Address shape in core/addresses.ts.

Accepts chainId: undefined so callers can pass publicClient.chain?.id directly without a pre-check; the helper handles the chain-id-missing branch itself.

clientLabel is embedded in the thrown error so consumers can tell which client misconfigured ACL (e.g. "ConfidentialVestingManagerClient"). The error's context.overrideName is set to "aclAddress" so the message points users at the right config knob.

Parameters

ParameterType
chainId... | ...
clientLabelstring

Returns

`0x${(...)}`


createMockEncryptor()

function createMockEncryptor(options?): Promise<...>;

Defined in: fhe/mock-encryptor.ts:327

Construct an SDK-shaped Encryptor backed by MockFhevmInstance against a local FHEVM-ready Anvil node (pnpm fhevm:up). One call replaces the 7-address MockFhevmInstance.create boilerplate every local-chain consumer used to copy from node_modules/@fhevm/mock-utils.

Parameters

ParameterType
optionsCreateMockEncryptorOptions

Returns

Promise<...>

Example

import { createMockEncryptor } from "@tokenops/sdk/fhe";

const encryptor = await createMockEncryptor({ rpcUrl: "http://127.0.0.1:8545" });
const mgr = createConfidentialVestingManagerClient({ publicClient, walletClient, address, encryptor });
await mgr.createVesting({ params, amount: 1_000_000n });

Remarks

MockFhevmInstance is process-scoped: handles produced by one instance are only decryptable by that same instance. For end-to-end encrypt → submit → decrypt loops, keep one encryptor alive for the whole run and serialize state (vestingId, manager, etc.) to disk between steps. See /concepts/encryption for the recommended pattern.


mintMockERC7984()

function mintMockERC7984(args): Promise<...>;

Defined in: fhe/mock-erc7984.ts:122

Mint amount MockERC7984 ciphertext units to to. Required pre-step for any outside-in /fhe-vesting / /fhe-airdrop / /fhe-disperse walkthrough where the operator's wallet needs a starting balance before the next setOperator + createX call.

Parameters

ParameterType
argsMintMockERC7984Args

Returns

Promise<...>

Example

import { mintMockERC7984, DEPLOYED_ADDRESSES } from "@tokenops/sdk";

const { hash, blockNumber } = await mintMockERC7984({
publicClient,
walletClient,
token: DEPLOYED_ADDRESSES.tokens.testConfidential[11155111]!,
to: walletClient.account!.address,
amount: 1_000_000n,
});

Throws

TokenOpsContractError if the writeContract or receipt-wait step throws. The original viem error is attached as the cause.


createMockErc7984Client()

function createMockErc7984Client(args): MockErc7984Client;

Defined in: fhe/mock-erc7984.ts:240

Construct a bound MockERC7984Token client. Lighter than mintMockERC7984 when a consumer makes multiple mints against the same token — the bound address + clients are stashed once.

Parameters

ParameterType
argsCreateMockErc7984ClientArgs

Returns

MockErc7984Client

Example

import { createMockErc7984Client, DEPLOYED_ADDRESSES } from "@tokenops/sdk/fhe";

const token = createMockErc7984Client({
publicClient,
walletClient,
address: DEPLOYED_ADDRESSES.tokens.testConfidential[11155111]!,
});

await token.mint({ to: alice, amount: 1_000_000n });
await token.mint({ to: bob, amount: 2_000_000n });

setOperator()

function setOperator(args): Promise<...>;

Defined in: fhe/operators.ts:154

Authorize spender to pull ERC-7984 tokens from account until deadline. Required pre-step before any /fhe-vesting, /fhe-airdrop, or /fhe-disperse flow that takes funds from the operator's balance.

Resolves to the transaction hash. Waits for the transaction to be mined by default (waitForReceipt: true) — the receipt is the strongest "operator is now authorized" signal a consumer can build the next call on top of. Pass waitForReceipt: false if your call site manages receipt polling itself.

Parameters

ParameterType
argsSetOperatorArgs

Returns

Promise<...>

Example

import { setOperator, ERC7984_OPERATOR_MAX_DEADLINE } from "@tokenops/sdk/fhe";

await setOperator({
publicClient,
walletClient,
token: DEPLOYED_ADDRESSES.tokens.testConfidential[31337]!,
spender: manager,
// deadline defaults to ERC7984_OPERATOR_MAX_DEADLINE (forever).
});

// Now safe to call manager.createVesting / factory.fundConfidentialAirdrop / etc.

Throws

TokenOpsContractError if the writeContract or receipt-wait step throws. The original viem error is attached as the cause.


revokeOperator()

function revokeOperator(args): Promise<...>;

Defined in: fhe/operators.ts:308

Revoke a previously granted ERC-7984 operator authorization. Calls token.setOperator(spender, 0) — the ERC-7984 convention where until=0 means "no future authorization" (the on-chain timestamp check until >= block.timestamp fails immediately).

When to use this. Any setOperator flow leaves the spender authorized for the deadline window. The default deadline is ERC7984_OPERATOR_MAX_DEADLINE (uint48 max ≈ year 8.9e+14) — useful for local-chain dev loops, hostile for production deployments where a stale manager clone (replaced by a new one) would otherwise keep operator rights forever. The original setOperator shipped without a revoke sibling, forcing consumers to hand-roll walletClient.writeContract({ ..., args: [spender, 0] }).

Parameters

ParameterType
argsRevokeOperatorArgs

Returns

Promise<...>

Example

import { revokeOperator } from "@tokenops/sdk/fhe";

await revokeOperator({
publicClient,
walletClient,
token: DEPLOYED_ADDRESSES.tokens.testConfidential[31337]!,
spender: staleManager, // old manager clone after deploying a new one
});
// `staleManager` can no longer call `confidentialTransferFrom` against
// the caller's balance.

Throws

TokenOpsContractError if the writeContract or receipt-wait step throws. The original viem error is attached as the cause.


scaleRatio()

function scaleRatio(__namedParameters): ScaledRatio;

Defined in: fhe/scale-ratio.ts:122

Scale a plaintext ratio so the output denominator equals the privacy-preserving split constant (FHE_SPLIT_DENOMINATOR, default 90_090_000) while keeping both values within uint128.

For arbitrary numerator/denominator inputs the output is the closest exact-integer numerator under that constant — i.e. numerator × (90_090_000 / denominator) when denominator divides 90_090_000 (every 1..16 fraction and every basis-point amount), or ceil(90_090_000 × numerator / denominator) for general inputs (with the denominator still pinned to 90_090_000).

Pre-scaled inputs whose denominator already matches minDenominator are returned unchanged; pre-scaled inputs whose denominator exceeds minDenominator are also returned unchanged (the caller is asking for higher precision than the standard constant, e.g. for a non-split surface).

Most consumers should use share instead — its builders express the two natural shapes (n/m, basis points) directly and produce ScaledRatio outputs that are exact-integer by construction.

Parameters

ParameterType
__namedParametersScaleRatioArgs

Returns

ScaledRatio

Examples

scaleRatio({ numerator: 1n, denominator: 2n });
// → { numerator: 45_045_000n, denominator: 90_090_000n } // 50% of 90_090_000
scaleRatio({ numerator: 2n, denominator: 3n });
// → { numerator: 60_060_000n, denominator: 90_090_000n } // exact: 2/3 × 90_090_000

createSepoliaEncryptorWeb()

function createSepoliaEncryptorWeb(opts): Promise<...>;

Defined in: fhe/sepolia-encryptor-web.ts:168

Construct an SDK-shaped Encryptor backed by Zama's RelayerWeb against the public Sepolia (or mainnet) relayer. The browser parity peer of createSepoliaEncryptor — same Encryptor contract, no node:worker_threads / node:module in the import graph, so bundlers (Next, Vite, etc.) follow only browser-safe paths.

Parameters

ParameterType
optsCreateSepoliaEncryptorWebOpts

Returns

Promise<...>

Example

import { createSepoliaEncryptorWeb } from "@tokenops/sdk/fhe";
import { createConfidentialVestingManagerClient } from "@tokenops/sdk/fhe-vesting";

const encryptor = await createSepoliaEncryptorWeb({ publicClient, walletClient });
const mgr = createConfidentialVestingManagerClient({
publicClient, walletClient, address: manager, encryptor,
});
await mgr.createVesting({ params, amount: 1_000_000n });

Remarks

This is the Sepolia / mainnet path. For local Anvil (pnpm fhevm:up), use createMockEncryptor instead. Mock and real relayer ciphertexts are not interchangeable.


createSepoliaEncryptor()

function createSepoliaEncryptor(options?): Promise<...>;

Defined in: fhe/sepolia-encryptor.ts:211

Construct an SDK-shaped Encryptor backed by Zama's RelayerNode against the public Sepolia (or mainnet) relayer. One call replaces the hand-rolled new RelayerNode({ transports: { 11155111: SepoliaConfig }, getChainId: async () => 11155111 }) boilerplate every Sepolia consumer used to copy from node_modules/@zama-fhe/sdk/dist/esm/node/index.d.ts.

Parameters

ParameterType
optionsCreateSepoliaEncryptorOptions

Returns

Promise<...>

Example

import { createSepoliaEncryptor } from "@tokenops/sdk/fhe";
import { createConfidentialVestingManagerClient } from "@tokenops/sdk/fhe-vesting";

const encryptor = await createSepoliaEncryptor();
try {
const mgr = createConfidentialVestingManagerClient({
publicClient, walletClient, address: manager, encryptor,
});
await mgr.createVesting({ params, amount: 1_000_000n });
} finally {
encryptor.terminate(); // RelayerNode owns worker_threads — always tear down.
}

Remarks

This is the Sepolia / mainnet path. For local Anvil (pnpm fhevm:up), use createMockEncryptor instead. The mock and the real relayer do not share a bytestream — handles are not portable across them.