2.0 RC docsView 1.x docs
Concept · Deployments

Where each product is deployed

Every table below is read from DEPLOYED_ADDRESSES in the installed build, so it cannot drift from what the SDK calls.

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.

The SDK only calls pre-deployed contracts; there are no factory-deployment helpers. Each client resolves its address from the registry by chain id unless you pass address (or aclAddress for the FHEVM ACL).

Usable chains per product#

chainsWithDeployment(product) lists chains where every contract of the product has an address, since a partial deployment is not usable. chainsWithKnownRegistryEntry also includes chains recorded as null (known, not yet deployed), for a deployment-pending state separate from an unsupported chain.

Product keychainsWithDeploymentchainsWithKnownRegistryEntry
fheVestingSepolia (11155111)Ethereum (1), Sepolia (11155111)
fheAirdropEthereum (1), Sepolia (11155111)Ethereum (1), Sepolia (11155111)
fheDisperseEthereum (1), Sepolia (11155111)Ethereum (1), Sepolia (11155111)
testnetFaucetSepolia (11155111)Sepolia (11155111)

DEPLOYED_ADDRESSES#

Vesting (/fhe-vesting)#

Contract keyEthereum (1)Sepolia (11155111)
confidentialVestingFactorynull: registry-not-deployed0x059d6Bb8ff9a13E794fe416d4757d7310CdC69ab

Disperse (/fhe-disperse)#

Contract keyEthereum (1)Sepolia (11155111)
disperseConfidentialSingleton0x4fC0d28cBe4B82D512Ad0B42F6787480Cc98cC700x710dD9885Cc9986EfD234E7719483147a6d8DBb4

Testnet faucet (/testnet-faucet)#

Contract keySepolia (11155111)
testToken0x37a057Fa8C201a7bf8caF32dfa9A0878f577D92b
confidentialTestToken0x258F9D60dc023870e4E3109c894D834D5377361a

The accessors#

Prefer the accessors to indexing the object. The get* forms return undefined for both a missing chain and a null entry; the require* forms throw DeploymentAddressUnavailableError. All are on the root @tokenops/sdk.

AccessorResolves
getDeployedAddress(product, contract, chainId)Any registry entry
getFheVestingFactoryAddress / requireFheVestingFactoryAddressfheVesting.confidentialVestingFactory
getFheAirdropFactoryAddress / requireFheAirdropFactoryAddressfheAirdrop.airdropFactory (the v2 factory; the name is unchanged from 1.x)
getFheAirdropEcdsaImplementationAddress, getFheAirdropMerkleImplementationAddress, getFheAirdropComplianceImplementationAddressThe three airdrop implementations
getFheDisperseSingletonAddress / requireFheDisperseSingletonAddressfheDisperse.disperseConfidentialSingleton
getTestTokenAddress / requireTestTokenAddresstestnetFaucet.testToken (TTT, plain ERC-20)
getConfidentialTestTokenAddress / requireConfidentialTestTokenAddresstestnetFaucet.confidentialTestToken (CTTT, ERC-7984)
import {
  chainsWithDeployment,
  getDeployedAddress,
  getFheAirdropFactoryAddress,
  requireFheDisperseSingletonAddress,
} from "@tokenops/sdk";

getFheAirdropFactoryAddress(1);                              // Address | undefined
getDeployedAddress("fheVesting", "confidentialVestingFactory", 1); // undefined: null in the registry
requireFheDisperseSingletonAddress(11155111);                 // Address, or throws
chainsWithDeployment("fheVesting");                           // chains where every contract is set

Live from the installed build: getFheAirdropFactoryAddress(1) returns 0x3c6a7Ae9f03a7c2c30938bae94a75491027d470C; getFheAirdropFactoryAddress(11155111) returns 0x3c6a7Ae9f03a7c2c30938bae94a75491027d470C.

registry-not-deployed vs registry-unknown-chain#

A client that cannot resolve an address throws DeploymentAddressUnavailableError, and context.reason says why. Every client and hook reports the reason the registry gives: registry-not-deployed for an explicit null (vesting on mainnet, for example) and registry-unknown-chain for a chain with no entry at all. context.overrideName names the config field that bypasses the registry, usually address.

import { DeploymentAddressUnavailableError } from "@tokenops/sdk";
import { createConfidentialVestingFactoryClient } from "@tokenops/sdk/fhe-vesting";

function networkNotice(err: unknown): string | undefined {
  if (!(err instanceof DeploymentAddressUnavailableError)) return undefined;
  switch (err.context.reason) {
    case "registry-not-deployed":
      return "Not deployed on this network yet.";
    case "registry-unknown-chain":
      return "Unsupported network.";
    case "chain-id-missing":
      return "Pass chainId: the public client has no chain.";
  }
}

try {
  createConfidentialVestingFactoryClient({ publicClient: mainnetClient, walletClient });
} catch (err) {
  showNotice(networkNotice(err) ?? "Something went wrong.");
}

FHEVM ACL addresses#

Encrypted views filter receipt logs by the FHEVM ACL contract to find the granted handle. FHEVM_ACL_ADDRESS_BY_CHAIN (/fhe) is the single source for every product, with getFhevmAclAddress and requireFhevmAclAddress as accessors.

ChainACL contract
Ethereum (1)0xcA2E8f1F656CD25C01F05d0b243Ab1ecd4a8ffb6
Local Hardhat / Anvil (31337)0x50157CFfD6bBFA2DECe204a89ec419c23ef5755D
Sepolia (11155111)0xf0Ffdc93b7E186bC2f8CB3dAA75D86d1930A433D

Airdrop contract generation#

The airdrop system is deployed at the same addresses on mainnet and Sepolia. AIRDROP_CONTRACTS_COMMIT (/fhe-airdrop) names the contract commit the vendored ABIs resolve against; read it at runtime to confirm which generation an installed build speaks to.

ValueSource
Contracts commit 6b0edcc89c65f59d9c9f4e58d00b478253b69083AIRDROP_CONTRACTS_COMMIT, exported by the installed build
CREATE3 salt epoch 0The contracts repo's deployment record at that commit (not exported by the SDK)
Build fingerprint 0x56ffbee6d221ab468fe05029ba724d752214e1c69539933da9d3d3797f07bb48The contracts repo's deployment record at that commit (not exported by the SDK)

See also