@zama-fhe/sdk 3.4.0-alpha.2 → 3.4.0-alpha.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,10 +1,10 @@
1
1
  import { u as FheChain } from "./index-doNE2KoX.js";
2
- import { $ as TransferOptions, Bt as EncryptedValue, C as ChainRouter, Ht as FhevmRelayerOptions, K as ZamaSDKEventInput, Mt as TransactionResult, Nt as ClearValue, Pt as DecryptPublicValuesResult, R as TransactionOperation, Rt as EncryptParams, Ut as FhevmRelayerSDK, Z as ShieldOptions, c as GenericStorage, d as WalletAccount, et as UnshieldOptions, i as ZamaConfig, l as GenericProvider, n as RelayerConfig, nt as TransferCallbacks, o as ZamaConfigGeneric, p as WalletAccountListener, rt as UnshieldCallbacks, s as GenericLogger, u as GenericSigner, x as WriteContractConfig, zt as EncryptResult } from "./types-nwhfaUCK.js";
3
- import "./cleartext-Bvx-0y6k.js";
4
- import "./types-D8g0H49N.js";
5
- import "./types-CObfaH4A.js";
6
- import "./index-CDJk5ZAg.js";
7
- import { Address, Hex } from "viem";
2
+ import { $ as TransferOptions, Bt as EncryptResult, C as ChainRouter, Ft as DecryptPublicValuesResult, K as ZamaSDKEventInput, Nt as TransactionResult, Pt as ClearValue, R as TransactionOperation, Ut as FhevmRelayerOptions, Vt as EncryptedValue, Wt as FhevmRelayerSDK, Z as ShieldOptions, c as GenericStorage, d as WalletAccount, et as UnshieldOptions, i as ZamaConfig, it as UnshieldCallbacks, l as GenericProvider, n as RelayerConfig, o as ZamaConfigGeneric, p as WalletAccountListener, rt as TransferCallbacks, s as GenericLogger, tt as UnwrapResult, u as GenericSigner, x as WriteContractConfig, zt as EncryptParams } from "./types-DOrkGzQq.js";
3
+ import "./cleartext-BFMBTVAU.js";
4
+ import "./types-DqVUdAH4.js";
5
+ import "./base-signer-C50IEnIg.js";
6
+ import "./types-BhiOPQgL.js";
7
+ import { Address, Address as Address$1, Hex, Hex as Hex$1 } from "viem";
8
8
  import { z } from "zod/mini";
9
9
  import { MutationFunctionContext, QueryKey, QueryObserverOptions, skipToken } from "@tanstack/query-core";
10
10
  //#region src/config/create.d.ts
@@ -18459,34 +18459,6 @@ declare function isConfidentialTokenValidContract(registry: Address, confidentia
18459
18459
  readonly args: readonly [`0x${string}`];
18460
18460
  };
18461
18461
  //#endregion
18462
- //#region src/query/utils.d.ts
18463
- type StrippedQueryOptionKeys = "gcTime" | "staleTime" | "enabled" | "select" | "refetchInterval" | "refetchOnMount" | "refetchOnWindowFocus" | "refetchOnReconnect" | "retry" | "retryDelay" | "retryOnMount" | "queryFn" | "queryKey" | "queryKeyHashFn" | "initialData" | "initialDataUpdatedAt" | "placeholderData" | "structuralSharing" | "throwOnError" | "meta" | "query" | "pollingInterval";
18464
- /**
18465
- * Remove TanStack behavioral options from a query config object so only domain
18466
- * parameters remain for the lower-level factory.
18467
- *
18468
- * @example
18469
- * ```ts
18470
- * const params = filterQueryOptions({
18471
- * query: { enabled: false },
18472
- * gcTime: 60_000,
18473
- * owner: "0xabc",
18474
- * });
18475
- * // => { owner: "0xabc" }
18476
- * ```
18477
- */
18478
- declare function filterQueryOptions<TOptions extends Record<string, unknown>>(options: TOptions): Omit<TOptions, StrippedQueryOptionKeys>;
18479
- /**
18480
- * Stable hash function for query keys.
18481
- * Sorts object keys recursively and converts bigint values to strings.
18482
- *
18483
- * @remarks
18484
- * bigint values are serialized as decimal strings, so `42n` and `"42"` hash to
18485
- * the same token when they occupy the same position. This collision is accepted
18486
- * by design for the current query-key conventions in this package.
18487
- */
18488
- declare function hashFn(queryKey: readonly unknown[]): string;
18489
- //#endregion
18490
18462
  //#region src/query/factory-types.d.ts
18491
18463
  type RequiredBy<T, K extends keyof T> = Omit<T, K> & Required<Pick<T, K>>;
18492
18464
  type QueryFactoryOptions<TQueryFnData = unknown, TError = Error, TData = TQueryFnData, TQueryKey extends QueryKey = QueryKey> = Omit<RequiredBy<QueryObserverOptions<TQueryFnData, TError, TData, TQueryFnData, TQueryKey>, "queryKey">, "queryFn" | "queryHash" | "queryKeyHashFn" | "throwOnError"> & {
@@ -18498,11 +18470,6 @@ interface MutationFactoryOptions<TMutationKey extends readonly unknown[], TVaria
18498
18470
  onSuccess?: (data: TData, variables: TVariables, onMutateResult: TOnMutateResult, context: MutationFunctionContext) => void;
18499
18471
  }
18500
18472
  //#endregion
18501
- //#region src/query/signer-query-context.d.ts
18502
- interface SignerQueryContext {
18503
- walletAccount?: WalletAccount;
18504
- }
18505
- //#endregion
18506
18473
  //#region src/query/query-keys.d.ts
18507
18474
  /**
18508
18475
  * Canonical query-key namespace for `@zama-fhe/sdk/query`.
@@ -18706,53 +18673,19 @@ declare const zamaQueryKeys: {
18706
18673
  };
18707
18674
  };
18708
18675
  //#endregion
18709
- //#region src/query/invalidation.d.ts
18710
- interface QueryLike {
18711
- queryKey: readonly unknown[];
18712
- }
18713
- interface QueryFilterLike {
18714
- queryKey?: readonly unknown[];
18715
- predicate?: (query: QueryLike) => boolean;
18716
- }
18717
- interface QueryClientLike {
18718
- invalidateQueries(filters: QueryFilterLike): void | Promise<void>;
18719
- removeQueries(filters: QueryFilterLike): void;
18720
- }
18721
- declare function invalidateAfterUnwrap(queryClient: QueryClientLike, tokenAddress: Address): void;
18722
- declare function invalidateBalanceQueries(queryClient: QueryClientLike, tokenAddress: Address): void;
18723
- declare function invalidateAfterShield(queryClient: QueryClientLike, tokenAddress: Address): void;
18724
- declare function invalidateAfterUnshield(queryClient: QueryClientLike, tokenAddress: Address): void;
18725
- declare function invalidateAfterUnshieldSettled(queryClient: QueryClientLike, tokenAddress: Address): void;
18726
- declare function invalidateAfterTransfer(queryClient: QueryClientLike, tokenAddress: Address): void;
18727
- declare function invalidateAfterApproveUnderlying(queryClient: QueryClientLike, tokenAddress: Address): void;
18728
- declare function invalidateAfterSetOperator(queryClient: QueryClientLike, tokenAddress: Address): void;
18729
- declare function invalidateWagmiBalanceQueries(queryClient: QueryClientLike): void;
18730
- declare function invalidateWalletLifecycleQueries(queryClient: QueryClientLike): void;
18731
- //#endregion
18732
- //#region src/query/token-metadata.d.ts
18733
- /** ERC-20 token metadata returned by {@link tokenMetadataQueryOptions}. */
18734
- interface TokenMetadata {
18735
- name: string;
18736
- symbol: string;
18737
- decimals: number;
18738
- }
18739
- interface TokenMetadataQueryConfig {
18740
- query?: Record<string, unknown>;
18741
- }
18742
- declare function tokenMetadataQueryOptions(sdk: ZamaSDK, tokenAddress: Address, config?: TokenMetadataQueryConfig): QueryFactoryOptions<TokenMetadata, Error, TokenMetadata, ReturnType<typeof zamaQueryKeys.tokenMetadata.token>>;
18743
- //#endregion
18744
- //#region src/query/is-confidential.d.ts
18745
- interface IsConfidentialQueryConfig {
18746
- query?: Record<string, unknown>;
18676
+ //#region src/query/signer-query-context.d.ts
18677
+ interface SignerQueryContext {
18678
+ walletAccount?: WalletAccount;
18747
18679
  }
18748
- declare function isConfidentialQueryOptions(sdk: ZamaSDK, tokenAddress: Address, config?: IsConfidentialQueryConfig): QueryFactoryOptions<boolean, Error, boolean, ReturnType<typeof zamaQueryKeys.isConfidential.token>>;
18749
- declare function isWrapperQueryOptions(sdk: ZamaSDK, tokenAddress: Address, config?: IsConfidentialQueryConfig): QueryFactoryOptions<boolean, Error, boolean, ReturnType<typeof zamaQueryKeys.isWrapper.token>>;
18750
18680
  //#endregion
18751
- //#region src/query/total-supply.d.ts
18752
- interface TotalSupplyQueryConfig {
18753
- query?: Record<string, unknown>;
18681
+ //#region src/query/user-decrypt.d.ts
18682
+ interface EncryptedInput {
18683
+ encryptedValue: EncryptedValue;
18684
+ contractAddress: Address;
18754
18685
  }
18755
- declare function totalSupplyQueryOptions(sdk: ZamaSDK, tokenAddress: Address, config?: TotalSupplyQueryConfig): QueryFactoryOptions<bigint, Error, bigint, ReturnType<typeof zamaQueryKeys.totalSupply.token>>;
18686
+ /** Decrypted clear values keyed by encrypted handle. */
18687
+ type DecryptResult = Readonly<Record<EncryptedValue, ClearValue>>;
18688
+ declare function decryptValuesQueryOptions(sdk: ZamaSDK, encryptedInputs: EncryptedInput[], signerContext?: SignerQueryContext): QueryFactoryOptions<DecryptResult, Error, DecryptResult, ReturnType<typeof zamaQueryKeys.decryption.encryptedInputs>>;
18756
18689
  //#endregion
18757
18690
  //#region src/schemas/primitives.d.ts
18758
18691
  declare const checksummedTag: unique symbol;
@@ -18820,272 +18753,149 @@ interface SerializedTransportKeyPairWithPermissions {
18820
18753
  readonly permissions: readonly Permission[];
18821
18754
  }
18822
18755
  //#endregion
18823
- //#region src/wrappers-registry.d.ts
18824
- /**
18825
- * Default wrappers registry addresses for known chains.
18826
- * Only includes chains where a registry is deployed (excludes Hardhat).
18827
- *
18828
- * @deprecated Read `registryAddress` from the chain presets instead (e.g.
18829
- * `sepolia.registryAddress`). Will be removed in the next major version.
18830
- */
18831
- declare const DefaultRegistryAddresses: Record<number, Address>;
18832
- /** Configuration for {@link WrappersRegistry}. */
18833
- interface WrappersRegistryConfig {
18834
- /** Read-only chain provider used for every registry lookup. */
18835
- provider: GenericProvider;
18836
- /**
18837
- * Per-chain registry address overrides, merged on top of
18838
- * {@link DefaultRegistryAddresses}. Use this to supply a registry
18839
- * address for custom or local chains (e.g. Hardhat).
18840
- *
18841
- * @example
18842
- * ```ts
18843
- * new WrappersRegistry({
18844
- * provider,
18845
- * registryAddresses: { [31337]: "0xYourHardhatRegistry" },
18846
- * });
18847
- * ```
18848
- */
18849
- registryAddresses?: Record<number, Address>;
18850
- /**
18851
- * How long cached registry results remain valid, in seconds.
18852
- * Default: `86400` (24 hours).
18853
- */
18854
- registryTTL?: number;
18855
- }
18856
- /** Options for {@link WrappersRegistry.listPairs}. */
18857
- interface ListPairsOptions {
18858
- /** Page number (1-indexed). Default: `1`. */
18859
- page?: number;
18860
- /** Number of items per page. Default: `100`. */
18861
- pageSize?: number;
18756
+ //#region src/credentials/credential-service.d.ts
18757
+ /** Configuration for {@link CredentialService}. TTLs are pre-validated by the caller. */
18758
+ interface CredentialServiceConfig {
18759
+ router: ChainRouter;
18760
+ signer: GenericSigner;
18761
+ /** Transport key pair lifetime in seconds. Pre-validated. */
18762
+ transportKeyPairTTL: number;
18763
+ /** Permit lifetime in days. Pre-validated. */
18764
+ permitTTL: number;
18765
+ /** Backing storage for transport key pairs (and permits if `permitStorage` is omitted). */
18766
+ storage: GenericStorage;
18767
+ /** Optional dedicated storage for permits; defaults to `storage`. */
18768
+ permitStorage?: GenericStorage;
18769
+ /** SDK-wide logger for credential-path diagnostics. */
18770
+ logger: GenericLogger;
18862
18771
  /**
18863
- * When `true`, fetches on-chain metadata (name, symbol, decimals) for both
18864
- * the ERC-20 and confidential token, plus totalSupply for the ERC-20.
18865
- * Default: `false`.
18772
+ * Opt-in shared-tenant scope (B2B2C/WaaS operators). When set, every signer
18773
+ * configured with the same scope shares one transport key pair instead of one
18774
+ * per signer address. Permits stay per-signer regardless — see
18775
+ * {@link revokeTransportKeyPair} for the operator-level counterpart to
18776
+ * signer-level revocation.
18866
18777
  */
18867
- metadata?: boolean;
18778
+ scope?: string;
18868
18779
  }
18869
18780
  /**
18870
- * High-level interface for the on-chain token wrappers registry.
18871
- *
18872
- * Uses the configured {@link GenericProvider} to resolve the correct registry
18873
- * contract address for the current chain and exposes typed read helpers for
18874
- * every registry query. Results are cached in memory with a configurable TTL
18875
- * (default 24 hours).
18876
- *
18877
- * @example
18878
- * ```ts
18879
- * const registry = new WrappersRegistry({ provider });
18880
- *
18881
- * // Paginated listing
18882
- * const page1 = await registry.listPairs({ page: 1, pageSize: 20 });
18781
+ * Single facade coordinating the keypair vault and the permission store.
18883
18782
  *
18884
- * // Structured lookups
18885
- * const result = await registry.getConfidentialToken(erc20Address);
18886
- * if (result) console.log(result.confidentialTokenAddress);
18783
+ * `CredentialService` is the only credentials object held by `ZamaSDK`. It accepts identity
18784
+ * transitions via `handleWalletAccountChange`.
18887
18785
  *
18888
- * // Force refresh
18889
- * registry.refresh();
18890
- * ```
18786
+ * Two distinct revocation tiers exist and must not be conflated: {@link clearCredentials}
18787
+ * (signer-level, e.g. an end-user "disconnect") only ever removes that signer's own
18788
+ * key-pair slot and permits — when a scope is configured, the shared key pair was never
18789
+ * stored there, so it's untouched. {@link revokeTransportKeyPair} (operator-level) is
18790
+ * the only way to invalidate a scope's shared key pair, and it does so for every signer
18791
+ * in the scope at once.
18891
18792
  */
18892
- declare class WrappersRegistry {
18793
+ declare class CredentialService {
18893
18794
  #private;
18894
- readonly provider: GenericProvider;
18895
- constructor(config: WrappersRegistryConfig);
18896
- /**
18897
- * Synchronous lookup of the registry address for a given chain ID.
18898
- * Returns `undefined` if no address is configured for that chain.
18899
- */
18900
- getAddress(chainId: number): Address | undefined;
18901
- /**
18902
- * Force-invalidate the in-memory cache. The next call to any read method
18903
- * will fetch fresh data from the chain.
18904
- */
18905
- refresh(): void;
18795
+ constructor(config: CredentialServiceConfig);
18906
18796
  /**
18907
- * The cache TTL in milliseconds.
18908
- * Exposed so query option factories can set a matching `staleTime`.
18797
+ * Resolve a keypair and permissions covering `contracts`, minimizing wallet
18798
+ * prompts by reusing or widening existing permits where possible. Empty
18799
+ * `contracts` warms the keypair without prompting.
18800
+ *
18801
+ * @returns The resolved keypair and permits covering the requested contracts.
18802
+ * @throws if the user rejects a wallet signature prompt. {@link SigningRejectedError}
18803
+ * @throws if signing fails for any other reason. {@link SigningFailedError}
18909
18804
  */
18910
- get ttlMs(): number;
18805
+ grantPermit(contracts: readonly Address[], delegator?: Address): Promise<SerializedTransportKeyPairWithPermissions>;
18911
18806
  /**
18912
- * Resolve the registry contract address for the current chain.
18913
- *
18914
- * Priority: `registryAddresses[chainId]` \> built-in default.
18807
+ * Pure store lookup: are stored permits sufficient to cover `contracts`? No wallet prompt.
18915
18808
  *
18916
- * @returns The registry contract address for the connected chain.
18917
- * @throws if no address is configured for the chain. {@link ConfigurationError}
18809
+ * @returns `true` if cached permits cover all requested contracts (vacuously
18810
+ * true for an empty list); `false` if no keypair exists or coverage is
18811
+ * incomplete.
18918
18812
  */
18919
- getRegistryAddress(): Promise<Address>;
18813
+ hasPermit(contracts: readonly Address[], delegator?: Address): Promise<boolean>;
18920
18814
  /**
18921
- * List token wrapper pairs with page-based pagination.
18922
- *
18923
- * Internally maps to `getTokenConfidentialTokenPairsSlice` on-chain.
18924
- *
18925
- * @param options - Pagination and enrichment options.
18926
- * @returns A {@link PaginatedResult} of pairs.
18815
+ * Wipe FHE permits for the current signer.
18927
18816
  *
18928
- * @example
18929
- * ```ts
18930
- * const result = await registry.listPairs({ page: 1, pageSize: 20 });
18931
- * console.log(`${result.total} pairs, showing page ${result.page}`);
18817
+ * - With no argument: every permit referencing this signer is removed across
18818
+ * all chains and delegators. The keypair survives — use
18819
+ * {@link clearCredentials} to also wipe the keypair.
18820
+ * - With a contract list: every signed permit in the direct-decrypt scope
18821
+ * (current chain) whose immutable payload touches any listed address is
18822
+ * removed. Delegated permits are not touched in this mode.
18932
18823
  *
18933
- * // With on-chain metadata
18934
- * const withMeta = await registry.listPairs({ metadata: true, pageSize: 10 });
18935
- * for (const pair of withMeta.items) {
18936
- * console.log(pair.underlying.symbol, "→", pair.confidential.symbol);
18937
- * }
18938
- * ```
18824
+ * @throws if reading the signer address fails. {@link SigningFailedError}
18939
18825
  */
18940
- listPairs(options: ListPairsOptions & {
18941
- metadata: true;
18942
- }): Promise<PaginatedResult<TokenWrapperPairWithMetadata>>;
18943
- listPairs(options?: ListPairsOptions): Promise<PaginatedResult<TokenWrapperPair>>;
18826
+ revokePermits(contracts?: readonly Address[]): Promise<void>;
18944
18827
  /**
18945
- * Look up the confidential token for a given plain ERC-20 address.
18828
+ * Wipe the keypair for the current signer and cascade-delete every
18829
+ * permission referencing it across all chains and delegators.
18946
18830
  *
18947
- * @param tokenAddress - The plain ERC-20 token address.
18948
- * @returns The lookup result, or `null` if the token has never been registered.
18949
- * **Note:** revoked tokens (registered then invalidated) return a non-null result
18950
- * with `isValid: false`. Check `result.isValid` explicitly rather than using
18951
- * `if (result)` to guard against processing revoked tokens.
18831
+ * Signer-level only: when a scope is configured, the shared key pair was never
18832
+ * stored under this signer's own slot, so it survives untouched — only this
18833
+ * signer's permits are removed. Use {@link revokeTransportKeyPair} to invalidate
18834
+ * the shared key pair itself.
18952
18835
  *
18953
- * @example
18954
- * ```ts
18955
- * const result = await registry.getConfidentialToken(usdcAddress);
18956
- * if (result?.isValid) {
18957
- * console.log(result.confidentialTokenAddress);
18958
- * }
18959
- * ```
18836
+ * @throws if reading the signer address fails. {@link SigningFailedError}
18960
18837
  */
18961
- getConfidentialToken(tokenAddress: Address): Promise<{
18962
- confidentialTokenAddress: Address;
18963
- isValid: boolean;
18964
- } | null>;
18838
+ clearCredentials(): Promise<void>;
18965
18839
  /**
18966
- * Reverse lookup — find the plain ERC-20 for a given confidential token.
18840
+ * Revoke this scope's shared transport key pair (operator-level action).
18967
18841
  *
18968
- * @param confidentialTokenAddress - The confidential token address.
18969
- * @returns The lookup result, or `null` if no pair is registered.
18842
+ * Deletes the shared key pair. Every permit signed under it embeds the old
18843
+ * public key, so `listUsableAndPrune` treats them all as stale on next access —
18844
+ * no permit is touched directly, and no connected wallet is required. This is
18845
+ * the only operation that can invalidate a shared key pair; signer-level
18846
+ * {@link clearCredentials} never does.
18970
18847
  *
18971
- * @example
18972
- * ```ts
18973
- * const result = await registry.getUnderlyingToken(cUsdcAddress);
18974
- * if (result) {
18975
- * console.log(result.tokenAddress, result.isValid);
18976
- * }
18977
- * ```
18978
- */
18979
- getUnderlyingToken(confidentialTokenAddress: Address): Promise<{
18980
- tokenAddress: Address;
18981
- isValid: boolean;
18982
- } | null>;
18983
- /**
18984
- * Fetch all token wrapper pairs from the registry.
18848
+ * Not best-effort: unlike {@link clearCredentials}, a storage failure here rejects
18849
+ * instead of being logged and swallowed — see {@link TransportKeyPairVault.clearScope}.
18985
18850
  *
18986
- * @returns All registered `TokenWrapperPair` entries.
18987
- */
18988
- getTokenPairs(): Promise<readonly TokenWrapperPair[]>;
18989
- /**
18990
- * Get the total number of token wrapper pairs.
18851
+ * Only stops the SDK from reissuing or reusing the deleted key going forward — does
18852
+ * not revoke any permit already issued under it. A permit is a self-contained,
18853
+ * bearer-style EIP-712 signature the relayer accepts independently of this SDK's
18854
+ * storage; one already exfiltrated alongside the key remains usable until its own
18855
+ * `permitTTL` expiry regardless of this call.
18991
18856
  *
18992
- * @returns The count as a bigint.
18857
+ * @param scopeId - Must match the scope this service was configured with. Requiring
18858
+ * the caller to name it guards against revoking the wrong scope by mistake.
18859
+ * @throws if no scope is configured, or `scopeId` doesn't match it. {@link ConfigurationError}
18860
+ * @throws if the underlying storage delete fails.
18993
18861
  */
18994
- getTokenPairsLength(): Promise<bigint>;
18862
+ revokeTransportKeyPair(scopeId: string): Promise<void>;
18995
18863
  /**
18996
- * Fetch a range of token wrapper pairs (paginated by index).
18864
+ * Warm the signer transport key pair cache for a known address.
18997
18865
  *
18998
- * @param fromIndex - Start index (inclusive).
18999
- * @param toIndex - End index (exclusive).
19000
- * @returns The slice of `TokenWrapperPair` entries.
19001
- */
19002
- getTokenPairsSlice(fromIndex: bigint, toIndex: bigint): Promise<readonly TokenWrapperPair[]>;
19003
- /**
19004
- * Fetch a single token wrapper pair by index.
18866
+ * Best-effort prefetch primitive: correctness still comes from `grantPermit`,
18867
+ * which lazily creates the transport key pair when needed. Errors (storage failure,
18868
+ * relayer 4xx, missing Worker in SSR) are **not** swallowed here — the caller
18869
+ * decides whether to log, ignore, or surface them.
19005
18870
  *
19006
- * @param index - Zero-based pair index.
19007
- * @returns The `TokenWrapperPair` at that index.
18871
+ * Not for pre-warming a shared scope: `address` is ignored for storage keying once
18872
+ * a scope is configured (see {@link TransportKeyPairVault}), so this call's actual
18873
+ * effect wouldn't match its apparent per-signer intent. Use
18874
+ * {@link warmTransportKeyPairScope} instead.
19008
18875
  */
19009
- getTokenPair(index: bigint): Promise<TokenWrapperPair>;
18876
+ warmTransportKeyPair(address: Address): Promise<void>;
19010
18877
  /**
19011
- * Look up the confidential token address for a given plain ERC-20 token.
18878
+ * Warm this scope's shared transport key pair (operator-level, no wallet needed) —
18879
+ * the pre-warm counterpart to {@link revokeTransportKeyPair}.
19012
18880
  *
19013
- * @param tokenAddress - The plain ERC-20 token address.
19014
- * @returns A tuple `[isValid, confidentialTokenAddress]`. `isValid` is `true` only for a
19015
- * registered, non-revoked wrapper. The address is the zero address when no pair is registered.
19016
- * A non-zero address with `isValid=false` means the wrapper was registered but later revoked.
18881
+ * @param scopeId - Must match the scope this service was configured with. Requiring
18882
+ * the caller to name it guards against warming the wrong scope by mistake.
18883
+ * @throws if no scope is configured, or `scopeId` doesn't match it. {@link ConfigurationError}
19017
18884
  */
19018
- getConfidentialTokenAddress(tokenAddress: Address): Promise<readonly [boolean, Address]>;
18885
+ warmTransportKeyPairScope(scopeId: string): Promise<void>;
19019
18886
  /**
19020
- * Reverse lookup — find the plain ERC-20 for a given confidential token.
18887
+ * Apply a wallet account transition.
19021
18888
  *
19022
- * @param confidentialTokenAddress - The confidential token address.
19023
- * @returns A tuple `[isValid, tokenAddress]`. `isValid` is `true` only for a registered,
19024
- * non-revoked wrapper. The address is the zero address when no pair is registered.
19025
- * A non-zero address with `isValid=false` means the wrapper was registered but later revoked.
18889
+ * Address change clears persisted credentials for the previous account.
18890
+ * Chain-only changes keep credentials intact because permits are chain-scoped
18891
+ * already and stale decrypt plaintext is cleared by `ZamaSDK`.
19026
18892
  */
19027
- getTokenAddress(confidentialTokenAddress: Address): Promise<readonly [boolean, Address]>;
19028
- /**
19029
- * Check whether a confidential token is registered and valid.
19030
- *
19031
- * @param confidentialTokenAddress - The confidential token address to check.
19032
- * @returns `true` if the token is a known valid wrapper in the registry.
19033
- */
19034
- isConfidentialTokenValid(confidentialTokenAddress: Address): Promise<boolean>;
19035
- }
19036
- //#endregion
19037
- //#region src/query/wrapper-discovery.d.ts
19038
- interface WrapperDiscoveryQueryConfig {
19039
- /**
19040
- * Address of any confidential token you control.
19041
- * Used to scope the query cache key and to gate whether the query
19042
- * is enabled — it does not affect which wrapper the registry returns.
19043
- */
19044
- tokenAddress?: Address;
19045
- /**
19046
- * The ERC-20 token address to discover the confidential wrapper for.
19047
- * The registry is resolved automatically from chain config.
19048
- */
19049
- erc20Address?: Address;
19050
- /**
19051
- * The resolved registry contract address for the current chain.
19052
- * Included in the query key so that switching chains invalidates
19053
- * stale cached results. Pass `undefined` when the chain ID is not
19054
- * yet known — the query will be disabled.
19055
- */
19056
- registryAddress?: Address;
19057
- query?: Record<string, unknown>;
19058
- }
19059
- declare function wrapperDiscoveryQueryOptions(registry: WrappersRegistry, config: WrapperDiscoveryQueryConfig): QueryFactoryOptions<Address | null, Error, Address | null, ReturnType<typeof zamaQueryKeys.wrapperDiscovery.token>>;
19060
- //#endregion
19061
- //#region src/query/underlying-allowance.d.ts
19062
- interface UnderlyingAllowanceQueryConfig {
19063
- owner?: Address;
19064
- query?: Record<string, unknown>;
19065
- }
19066
- declare function underlyingAllowanceQueryOptions(sdk: ZamaSDK, tokenAddress: Address, config: UnderlyingAllowanceQueryConfig): QueryFactoryOptions<bigint, Error, bigint, ReturnType<typeof zamaQueryKeys.underlyingAllowance.scope>>;
19067
- //#endregion
19068
- //#region src/query/pending-unshield.d.ts
19069
- interface PendingUnshieldQueryConfig {
19070
- query?: Record<string, unknown>;
19071
- }
19072
- /**
19073
- * Query options for reading the unwrap tx hash of an unshield that was
19074
- * interrupted between its two phases (returns `null` if none is pending).
19075
- *
19076
- * Backed by {@link ZamaSDK} storage via `WrappedToken.getPendingUnshield()`.
19077
- * `staleTime: 0` so the value reflects storage on mount; the unshield/unwrap
19078
- * mutations also invalidate this key on success.
19079
- */
19080
- declare function pendingUnshieldQueryOptions(sdk: ZamaSDK, tokenAddress: Address, config?: PendingUnshieldQueryConfig): QueryFactoryOptions<Hex | null, Error, Hex | null, ReturnType<typeof zamaQueryKeys.pendingUnshield.token>>;
19081
- //#endregion
19082
- //#region src/query/confidential-is-operator.d.ts
19083
- interface ConfidentialIsOperatorQueryConfig {
19084
- holder?: Address;
19085
- spender?: Address;
19086
- query?: Record<string, unknown>;
18893
+ handleWalletAccountChange(prev?: {
18894
+ address: Address;
18895
+ }, next?: {
18896
+ address: Address;
18897
+ }): Promise<void>;
19087
18898
  }
19088
- declare function confidentialIsOperatorQueryOptions(sdk: ZamaSDK, tokenAddress: Address | undefined, config: ConfidentialIsOperatorQueryConfig): QueryFactoryOptions<boolean, Error, boolean, ReturnType<typeof zamaQueryKeys.confidentialIsOperator.scope>>;
19089
18899
  //#endregion
19090
18900
  //#region src/errors/base.d.ts
19091
18901
  /**
@@ -19588,1283 +19398,1213 @@ declare function matchZamaError<R>(error: unknown, handlers: { [K in ZamaErrorCo
19588
19398
  _?: (error: unknown) => R;
19589
19399
  }): R | undefined;
19590
19400
  //#endregion
19591
- //#region src/token/token.d.ts
19592
- /** Options for {@link Token.batchDecryptBalancesAs}. */
19593
- interface BatchDecryptAsOptions {
19594
- /** The address of the account that delegated decryption rights. */
19595
- delegatorAddress: Address;
19596
- /** Pre-fetched encrypted values. When omitted, they are fetched from the chain. */
19597
- encryptedValues?: EncryptedValue[];
19401
+ //#region src/services/caching-service.d.ts
19402
+ /**
19403
+ * Storage-backed cache for decrypted FHE plaintext values.
19404
+ *
19405
+ * Each entry is keyed by `(requester, contractAddress, handle)` so different
19406
+ * signers cannot read each other's cached decryptions.
19407
+ */
19408
+ declare class CachingService {
19409
+ #private;
19410
+ constructor(storage: GenericStorage, logger: GenericLogger);
19411
+ get(requester: Address, contractAddress: Address, encryptedValue: EncryptedValue): Promise<ClearValue | null>;
19412
+ set(requester: Address, contractAddress: Address, encryptedValue: EncryptedValue, value: ClearValue): Promise<void>;
19413
+ delete(requester: Address, contractAddress: Address, encryptedValue: EncryptedValue): Promise<void>;
19414
+ clearForRequester(requester: Address): Promise<void>;
19415
+ clearAll(): Promise<void>;
19416
+ }
19417
+ //#endregion
19418
+ //#region src/services/delegation-service.d.ts
19419
+ declare class DelegationService {
19420
+ #private;
19421
+ constructor({ provider, router, emitEvent, logger }: {
19422
+ provider: GenericProvider;
19423
+ router: ChainRouter;
19424
+ logger: GenericLogger;
19425
+ emitEvent?: (input: ZamaSDKEventInput, tokenAddress?: Address) => void;
19426
+ });
19427
+ delegateDecryption(signer: GenericSigner, { contractAddress, delegateAddress, delegatorAddress, expirationDate }: {
19428
+ contractAddress: Address;
19429
+ delegateAddress: Address;
19430
+ delegatorAddress: Address;
19431
+ expirationDate?: Date;
19432
+ }): Promise<TransactionResult>;
19433
+ revokeDelegation(signer: GenericSigner, { contractAddress, delegateAddress, delegatorAddress }: {
19434
+ contractAddress: Address;
19435
+ delegateAddress: Address;
19436
+ delegatorAddress: Address;
19437
+ }): Promise<TransactionResult>;
19438
+ isDelegated(params: {
19439
+ contractAddress: Address;
19440
+ delegatorAddress: Address;
19441
+ delegateAddress: Address;
19442
+ }): Promise<boolean>;
19443
+ getDelegationExpiry({ contractAddress, delegatorAddress, delegateAddress }: {
19444
+ contractAddress: Address;
19445
+ delegatorAddress: Address;
19446
+ delegateAddress: Address;
19447
+ }): Promise<bigint>;
19448
+ findInactiveDelegations(contractAddresses: readonly Address[], delegatorAddress: Address, delegateAddress: Address): Promise<Map<Address, DelegationNotFoundError | DelegationExpiredError>>;
19449
+ assertDelegationActive(contractAddress: Address, delegatorAddress: Address, delegateAddress: Address): Promise<void>;
19450
+ }
19451
+ //#endregion
19452
+ //#region src/services/decryption-service.d.ts
19453
+ /** Options shared by the delegated-decrypt entry points. */
19454
+ interface DelegatedDecryptOptions {
19598
19455
  /**
19599
- * The account whose on-chain balance to read. Defaults to the delegator
19600
- * address, which is the common case (the delegator grants permission to
19601
- * decrypt their own balance). Only set this when the account differs
19602
- * from the delegator.
19603
- *
19604
- * Matches the `account` parameter of `confidentialBalanceOf(account)` on-chain.
19456
+ * Ride out the gateway propagation window: when a just-granted delegation
19457
+ * has not yet synced, the delegated decrypt is retried (bounded, ~30s) until
19458
+ * it lands instead of throwing {@link DelegationNotPropagatedError}. Defaults
19459
+ * to `true`. Pass `false` to fail fast on the first not-propagated response.
19605
19460
  */
19606
- accountAddress?: Address;
19607
- /** Maximum number of concurrent decrypt calls. Default: 10. */
19608
- maxConcurrency?: number;
19609
- /** Called when decryption fails for a single token. Return a fallback bigint. */
19610
- onError?: (error: Error, address: Address) => bigint;
19461
+ waitForPropagation?: boolean;
19611
19462
  }
19612
- /** Result of {@link Token.batchBalancesOf}. */
19613
- interface BatchBalancesResult {
19614
- /** Successfully decrypted balances, keyed by token address. */
19615
- results: Map<Address, bigint>;
19616
- /** Per-token errors for tokens that failed to decrypt. */
19617
- errors: Map<Address, ZamaError>;
19463
+ interface BatchDecryptItem {
19464
+ encryptedValue: EncryptedValue;
19465
+ contractAddress: Address;
19466
+ value?: ClearValue;
19467
+ error?: ZamaError;
19468
+ }
19469
+ interface BatchDecryptResult {
19470
+ items: BatchDecryptItem[];
19471
+ }
19472
+ declare class DecryptionService {
19473
+ #private;
19474
+ constructor({ cache, credentialService, delegationService, router, emitEvent }: {
19475
+ cache: CachingService;
19476
+ credentialService: CredentialService;
19477
+ delegationService: DelegationService;
19478
+ router: ChainRouter;
19479
+ emitEvent: (input: ZamaSDKEventInput) => void;
19480
+ });
19481
+ decryptValues(handles: EncryptedInput[], signerAddress: Address, opts?: Pick<FhevmRelayerOptions, "signal" | "timeout">): Promise<Record<EncryptedValue, ClearValue>>;
19482
+ delegatedDecryptValues(encryptedInputs: EncryptedInput[], delegatorAddress: Address, delegateAddress: Address, accountAddress: Address, opts?: DelegatedDecryptOptions): Promise<Record<EncryptedValue, ClearValue>>;
19483
+ delegatedBatchDecryptHandlesAs({ encryptedInputs, delegatorAddress, delegateAddress, accountAddress, maxConcurrency, waitForPropagation }: {
19484
+ encryptedInputs: EncryptedInput[];
19485
+ delegatorAddress: Address;
19486
+ delegateAddress: Address;
19487
+ accountAddress: Address;
19488
+ maxConcurrency?: number;
19489
+ waitForPropagation?: boolean;
19490
+ }): Promise<BatchDecryptResult>;
19618
19491
  }
19492
+ //#endregion
19493
+ //#region src/namespaces/decryption.d.ts
19619
19494
  /**
19620
- * High-level interface for an ERC-7984 confidential token.
19621
- * Hides FHE complexity (encryption, decryption, EIP-712 signing) behind
19622
- * familiar ERC-20-like methods.
19495
+ * Public namespace for FHE decryption — the canonical way to decrypt.
19623
19496
  *
19624
- * For ERC-7984 wrappers (shield/unshield), use {@link WrappedToken} instead —
19625
- * it extends `Token` with wrapper-specific operations.
19497
+ * Exposed as `sdk.decryption`. Prefer these methods over the low-level
19498
+ * `sdk.relayer.decryptValues` / `decryptPublicValues`: they
19499
+ * assemble the credential bundle (transport key pair, EIP-712 permit) for you,
19500
+ * cache results, and wrap relayer errors. Reach for `sdk.relayer.*` only when
19501
+ * you must control credential assembly by hand.
19626
19502
  *
19627
- * Decryption, credentials, caching, and event emission are handled by the
19628
- * owning {@link ZamaSDK} — this class only exposes token-scoped helpers
19629
- * that delegate to `sdk.decryption.decryptValues` and `sdk.permits.grantPermit`.
19503
+ * Owns the SDK-level guards (signer requirement on
19504
+ * `decryptValues` and `delegatedDecryptValues`, empty-array
19505
+ * short-circuit on `decryptPublicValues`, relayer error wrapping) and delegates the
19506
+ * actual work to the internal {@link DecryptionService} or the relayer directly for
19507
+ * `decryptPublicValues`.
19508
+ *
19509
+ * **Mixed signer requirement:** `decryptValues` and
19510
+ * `delegatedDecryptValues` need a configured signer; `decryptPublicValues`
19511
+ * does not. Each method documents its requirement in its JSDoc.
19512
+ *
19513
+ * **Request chunking:** decrypt requests are split internally to stay under
19514
+ * the relayer's 2048-cleartext-bit per-request budget — callers never need to
19515
+ * size batches themselves.
19630
19516
  */
19631
- declare class Token {
19517
+ declare class Decryption {
19632
19518
  #private;
19633
- readonly sdk: ZamaSDK;
19634
- readonly address: Address;
19635
- constructor(sdk: ZamaSDK, address: Address);
19636
- /** Read the token name from the contract. */
19637
- name(): Promise<string>;
19638
- /** Read the token symbol from the contract. */
19639
- symbol(): Promise<string>;
19640
- /** Read the token decimals from the contract. */
19641
- decimals(): Promise<number>;
19642
- /**
19643
- * ERC-165 check for {@link ERC7984_INTERFACE_ID} support.
19644
- *
19645
- * @returns `true` if the contract implements the ERC-7984 confidential token interface.
19646
- */
19647
- isConfidential(): Promise<boolean>;
19519
+ /** @internal */
19520
+ constructor(opts: {
19521
+ signer: GenericSigner | undefined;
19522
+ provider: GenericProvider;
19523
+ router: ChainRouter;
19524
+ decryptionService: DecryptionService | undefined;
19525
+ });
19648
19526
  /**
19649
- * ERC-165 check for IERC7984ERC20Wrapper support.
19527
+ * Decrypt one or more FHE encrypted values. Results are cached — repeated calls
19528
+ * for the same encrypted value skip the relayer round-trip.
19650
19529
  *
19651
- * @returns `true` if the contract implements the ERC-7984 wrapper interface
19652
- * ({@link ERC7984_WRAPPER_INTERFACE_ID}, `0x1f1c62b2`).
19653
- */
19654
- isWrapper(): Promise<boolean>;
19655
- /**
19656
- * Decrypt and return the plaintext balance for the given owner.
19657
- * Acquires FHE credentials via a wallet signature if none are cached.
19530
+ * Zero encrypted values are mapped to `0n` without hitting the relayer.
19531
+ * Events (`DecryptStart/End/Error`) are emitted uniformly.
19532
+ * Relayer errors are wrapped into typed SDK errors.
19658
19533
  *
19659
- * @param owner - Balance owner address.
19660
- * @returns The decrypted plaintext balance as a bigint.
19661
- * @throws if FHE decryption fails. {@link DecryptionFailedError}
19534
+ * @param encryptedInput - Encrypted values to decrypt, each paired with its contract address.
19535
+ * @param options - Per-call `signal` and `timeout` forwarded to the relayer round-trip.
19536
+ * @returns A record mapping each encrypted value to its decrypted clear-text value.
19537
+ * @throws if no signer is configured. {@link SignerNotConfiguredError}
19538
+ * @throws if signer and provider are on different chains. {@link ChainMismatchError}
19662
19539
  *
19663
19540
  * @example
19664
19541
  * ```ts
19665
- * const balance = await token.balanceOf("0xOwner");
19542
+ * const values = await sdk.decryption.decryptValues([
19543
+ * { encryptedValue: balance, contractAddress: cUSDT },
19544
+ * ]);
19545
+ * console.log(values[balance]); // 1000n
19666
19546
  * ```
19667
19547
  */
19668
- balanceOf(owner: Address): Promise<bigint>;
19548
+ decryptValues(encryptedInput: EncryptedInput[], options?: Pick<FhevmRelayerOptions, "signal" | "timeout">): Promise<Record<EncryptedValue, ClearValue>>;
19669
19549
  /**
19670
- * Return the raw encrypted balance without decrypting.
19550
+ * Decrypt one or more FHE encrypted values using delegated credentials.
19671
19551
  *
19672
- * @param owner - Balance owner address.
19673
- * @returns The encrypted balance as a hex string.
19552
+ * Mirrors {@link decryptValues} with delegated credentials — same caching and
19553
+ * zero-value short-circuit. Before reading from cache or calling the relayer,
19554
+ * every non-zero encrypted value's contract must have an active delegation from the
19555
+ * delegator to the connected signer; missing or expired delegations fail fast.
19556
+ *
19557
+ * @param encryptedInputs - FHE encrypted values paired with their contract addresses.
19558
+ * @param delegatorAddress - The address that granted delegation rights.
19559
+ * @param accountAddress - Address used as the cache key's "requester"
19560
+ * dimension. Defaults to `delegatorAddress`. Pass the actual account address
19561
+ * when decrypting on behalf of someone whose balance is stored under a
19562
+ * different address (e.g. `decryptBalanceAs` with an explicit `accountAddress`).
19563
+ * @param options - Delegated-decrypt options. By default the call rides out the
19564
+ * gateway propagation window ({@link DelegatedDecryptOptions.waitForPropagation});
19565
+ * pass `{ waitForPropagation: false }` to fail fast instead.
19566
+ * @returns Map of encrypted value → clear-text value.
19674
19567
  *
19675
19568
  * @example
19676
19569
  * ```ts
19677
- * const encryptedValue = await token.confidentialBalanceOf("0xOwner");
19570
+ * const values = await sdk.decryption.delegatedDecryptValues([
19571
+ * { encryptedValue: balance, contractAddress: tokenAddr },
19572
+ * ], delegatorAddr);
19573
+ * console.log(values[balance]); // 1000n
19678
19574
  * ```
19679
19575
  */
19680
- confidentialBalanceOf(owner: Address): Promise<EncryptedValue>;
19576
+ delegatedDecryptValues(encryptedInputs: EncryptedInput[], delegatorAddress: Address, accountAddress?: Address, options?: DelegatedDecryptOptions): Promise<Record<EncryptedValue, ClearValue>>;
19681
19577
  /**
19682
- * Decrypt the balance of a delegator using delegated decryption credentials.
19683
- * The connected signer acts as the delegatee who has been granted permission
19684
- * by the delegator to decrypt their balance.
19578
+ * Publicly decrypt one or more FHE encrypted values.
19685
19579
  *
19686
- * Clear values are cached in storage keyed by `(account, token, encryptedValue)`.
19687
- * Because every on-chain balance change produces a new encrypted value,
19688
- * stale cache entries are never served. Cache write failures are silently
19689
- * ignored — they do not affect the returned value.
19690
- *
19691
- * @param delegatorAddress - The address of the account that delegated decryption rights.
19692
- * @param accountAddress - The account whose on-chain balance to read. Defaults
19693
- * to the delegator address.
19694
- * @returns The decrypted plaintext balance as a bigint.
19695
- * @throws if no active delegation exists. {@link DelegationNotFoundError}
19696
- * @throws if the delegation has expired. {@link DelegationExpiredError}
19697
- * @throws if delegated decryption fails. {@link DecryptionFailedError}
19698
- *
19699
- * @example
19700
- * ```ts
19701
- * const balance = await token.decryptBalanceAs({
19702
- * delegatorAddress: "0xDelegator",
19703
- * });
19704
- * ```
19705
- */
19706
- decryptBalanceAs({ delegatorAddress, accountAddress }: {
19707
- delegatorAddress: Address;
19708
- accountAddress?: Address;
19709
- }): Promise<bigint>;
19710
- /**
19711
- * Decrypt confidential balances for multiple tokens in parallel, returning
19712
- * successes and per-token errors separately. Pre-authorizes all token
19713
- * addresses in a single wallet signature, then delegates each decrypt to
19714
- * `sdk.decryption.decryptValues`.
19715
- *
19716
- * Tokens that fail to decrypt land in `errors` rather than aborting the
19717
- * whole batch — caller decides how to surface them.
19580
+ * Signer-independent: works without a configured signer.
19581
+ * Returns the decryption proof alongside the clear-text values so callers
19582
+ * can submit on-chain finalization transactions (e.g. `finalizeUnwrap`).
19718
19583
  *
19719
- * @param tokens - Array of {@link Token} instances bound to the same SDK.
19720
- * @param owner - Balance owner address.
19721
- * @returns `{ results, errors }` partitioning the per-token outcomes.
19584
+ * @param encryptedValues - FHE encrypted values to decrypt publicly.
19585
+ * @param options - Per-call `signal` and `timeout` forwarded to the relayer round-trip.
19586
+ * @returns Clear-text values, ABI-encoded values, and the decryption proof.
19722
19587
  *
19723
19588
  * @example
19724
19589
  * ```ts
19725
- * const { results, errors } = await Token.batchBalancesOf(tokens, owner);
19590
+ * const { clearValues, decryptionProof, abiEncodedClearValues } =
19591
+ * await sdk.decryption.decryptPublicValues([encryptedValue]);
19726
19592
  * ```
19727
19593
  */
19728
- static batchBalancesOf(tokens: Token[], owner: Address): Promise<BatchBalancesResult>;
19594
+ decryptPublicValues(encryptedValues: EncryptedValue[], options?: Pick<FhevmRelayerOptions, "signal" | "timeout">): Promise<DecryptPublicValuesResult>;
19729
19595
  /**
19730
- * Batch decrypt confidential balances as a delegate across multiple tokens.
19731
- * Mirrors {@link batchBalancesOf} but uses delegated credentials.
19596
+ * Batch-decrypt delegated encrypted values with per-entry error isolation.
19732
19597
  *
19733
- * **Error handling:** If a per-token decryption fails and no `onError` callback
19734
- * is provided, errors are collected and thrown as an aggregated
19735
- * `DecryptionFailedError`. When the relayer returns no value for an encrypted value,
19736
- * a `DecryptionFailedError` is thrown for that token (never silently returns `0n`).
19737
- * Pass `onError: () => 0n` to opt into the silent zero behavior.
19598
+ * Attempts a single batch request first. If the batch fails with a non-fatal
19599
+ * error (e.g. one entry is invalid), falls back to per-entry decryption so
19600
+ * healthy entries still resolve. Each item in the result carries either a
19601
+ * decrypted value or an error — callers decide how to surface partial failures.
19738
19602
  *
19739
- * @param tokens - Array of Token instances to decrypt balances for.
19740
- * @param options - Delegated decryption configuration.
19741
- * @returns A Map from token address to decrypted balance.
19742
- * @throws if no active delegation exists. {@link DelegationNotFoundError}
19743
- * @throws if the delegation has expired. {@link DelegationExpiredError}
19744
- * @throws if any decryption fails and no `onError` is provided. {@link DecryptionFailedError}
19603
+ * @param encryptedInputs - FHE encrypted values paired with their contract addresses.
19604
+ * @param delegatorAddress - The address that granted delegation rights.
19605
+ * @param accountAddress - The account on whose behalf decryption is performed. Defaults to `delegatorAddress`.
19606
+ * @param maxConcurrency - Maximum parallel decrypt calls during per-entry fallback.
19607
+ * @param waitForPropagation - Ride out the gateway propagation window on the
19608
+ * initial batch attempt (default `true`). See {@link DelegatedDecryptOptions.waitForPropagation}.
19609
+ * @returns Per-entry results, each with a value or an error.
19610
+ * @throws if no signer is configured. {@link SignerNotConfiguredError}
19611
+ * @throws if signer and provider are on different chains. {@link ChainMismatchError}
19745
19612
  *
19746
19613
  * @example
19747
19614
  * ```ts
19748
- * const balances = await Token.batchDecryptBalancesAs(tokens, {
19615
+ * const result = await sdk.decryption.delegatedBatchDecryptValues({
19616
+ * encryptedInputs: [
19617
+ * { encryptedValue: encryptedValue1, contractAddress: tokenA },
19618
+ * { encryptedValue: encryptedValue2, contractAddress: tokenB },
19619
+ * ],
19749
19620
  * delegatorAddress: "0xDelegator",
19750
- * onError: (err, addr) => { console.error(addr, err); return 0n; },
19621
+ * maxConcurrency: 5,
19751
19622
  * });
19623
+ * for (const item of result.items) {
19624
+ * if (item.error) console.error(item.encryptedValue, item.error);
19625
+ * else console.log(item.encryptedValue, item.value);
19626
+ * }
19752
19627
  * ```
19753
19628
  */
19754
- static batchDecryptBalancesAs(tokens: Token[], options: BatchDecryptAsOptions): Promise<Map<Address, bigint>>;
19755
- private static readBalanceHandlesBatch;
19629
+ delegatedBatchDecryptValues({ encryptedInputs, delegatorAddress, accountAddress, maxConcurrency, waitForPropagation }: {
19630
+ encryptedInputs: EncryptedInput[];
19631
+ delegatorAddress: Address;
19632
+ accountAddress?: Address;
19633
+ maxConcurrency?: number;
19634
+ } & DelegatedDecryptOptions): Promise<BatchDecryptResult>;
19635
+ }
19636
+ //#endregion
19637
+ //#region src/namespaces/delegations.d.ts
19638
+ /**
19639
+ * Public namespace for on-chain decryption-delegation management.
19640
+ *
19641
+ * Exposed as `sdk.delegations`. Owns the SDK-level guards (signer requirement, chain
19642
+ * alignment, delegator address resolution from the wallet account) and delegates the
19643
+ * actual work to the internal {@link DelegationService}.
19644
+ *
19645
+ * Delegation operations write to the host chain ACL; after a delegation is mined,
19646
+ * the gateway syncs the ACL state via cross-chain event propagation — usually
19647
+ * within ~10 blocks (a few seconds). Delegated decryption rides out that window
19648
+ * with a bounded internal retry, so callers can decrypt right after granting.
19649
+ */
19650
+ declare class Delegations {
19651
+ #private;
19652
+ /** @internal */
19653
+ constructor(opts: {
19654
+ signer: GenericSigner | undefined;
19655
+ provider: GenericProvider;
19656
+ delegationService: DelegationService;
19657
+ });
19756
19658
  /**
19757
- * Confidential transfer. Encrypts the amount via FHE, then calls the contract.
19659
+ * Delegate decryption rights for a confidential contract to another address.
19660
+ * Calls `ACL.delegateForUserDecryption()` on-chain.
19758
19661
  *
19759
- * By default, the SDK validates the confidential balance before submitting.
19760
- * If a cached plaintext balance exists it is used; otherwise, if credentials
19761
- * are cached, it decrypts on the fly. Set `skipBalanceCheck: true` to bypass
19762
- * this validation (e.g. for smart wallets).
19662
+ * The delegation is recorded on L1 immediately, but the gateway must sync the
19663
+ * ACL state via cross-chain event propagation — usually within ~10 blocks (a
19664
+ * few seconds). You do not need to wait: delegated decryption rides out that
19665
+ * window with a bounded internal retry, so you can decrypt right after this
19666
+ * resolves.
19763
19667
  *
19764
- * @param to - Recipient address.
19765
- * @param amount - Plaintext amount to transfer (encrypted automatically via FHE).
19766
- * @param options - Optional: `skipBalanceCheck` (default `false`).
19668
+ * @param contractAddress - The confidential contract address to delegate on.
19669
+ * @param delegateAddress - Address to delegate decryption rights to.
19670
+ * @param expirationDate - Optional expiration date (defaults to permanent delegation via `uint64.max`).
19767
19671
  * @returns The transaction hash and mined receipt.
19672
+ * @throws if no signer is configured. {@link SignerNotConfiguredError}
19768
19673
  * @throws if signer and provider are on different chains. {@link ChainMismatchError}
19769
- * @throws if the balance is less than `amount`. {@link InsufficientConfidentialBalanceError}
19770
- * @throws if balance validation requires decryption that is not possible. {@link BalanceCheckUnavailableError}
19771
- * @throws if FHE encryption fails. {@link EncryptionFailedError}
19772
- * @throws if the on-chain transfer reverts. {@link TransactionRevertedError}
19773
- *
19774
- * @example
19775
- * ```ts
19776
- * const txHash = await token.confidentialTransfer("0xRecipient", 1000n);
19777
- * ```
19778
- */
19779
- confidentialTransfer(to: Address, amount: bigint, options?: TransferOptions): Promise<TransactionResult>;
19780
- /**
19781
- * Operator encrypted transfer on behalf of another address.
19782
- * The caller must be an approved operator for `from`.
19783
- *
19784
- * @param from - The address to transfer from (caller must be an approved operator).
19785
- * @param to - Recipient address.
19786
- * @param amount - Plaintext amount to transfer (encrypted automatically via FHE).
19787
- * @returns The transaction hash and mined receipt.
19788
- *
19789
- * @example
19790
- * ```ts
19791
- * const txHash = await token.confidentialTransferFrom("0xFrom", "0xTo", 500n);
19792
- * ```
19674
+ * @throws if `expirationDate` is less than 1 hour in the future. {@link DelegationExpirationTooSoonError}
19675
+ * @throws if the delegate equals the connected wallet. {@link DelegationSelfNotAllowedError}
19676
+ * @throws if the delegate equals the contract address. {@link DelegationDelegateEqualsContractError}
19677
+ * @throws if the new expiry equals the current one. {@link DelegationExpiryUnchangedError}
19678
+ * @throws if the delegation transaction reverts. {@link TransactionRevertedError}
19793
19679
  */
19794
- confidentialTransferFrom(from: Address, to: Address, amount: bigint, callbacks?: TransferCallbacks): Promise<TransactionResult>;
19680
+ delegateDecryption({ contractAddress, delegateAddress, expirationDate }: {
19681
+ contractAddress: Address;
19682
+ delegateAddress: Address;
19683
+ expirationDate?: Date;
19684
+ }): Promise<TransactionResult>;
19795
19685
  /**
19796
- * ERC-7984 `confidentialTransferAndCall`: encrypted transfer that also invokes
19797
- * the recipient's receiver hook (`onConfidentialTransferReceived`) in a single
19798
- * transaction. The caller crafts the opaque `data` payload — the SDK does not
19799
- * encode, validate, or interpret it.
19800
- *
19801
- * Balance validation follows the same rules as {@link Token.confidentialTransfer}.
19686
+ * Revoke decryption delegation for a confidential contract.
19687
+ * Calls `ACL.revokeDelegationForUserDecryption()` on-chain.
19802
19688
  *
19803
- * @param to - Recipient address. Must implement the ERC-7984 receiver hook.
19804
- * @param amount - Plaintext amount to transfer (encrypted automatically via FHE).
19805
- * @param data - Opaque bytes forwarded to the recipient's receiver hook.
19806
- * @param options - Optional: `skipBalanceCheck` (default `false`).
19689
+ * @param contractAddress - The confidential contract address to revoke delegation on.
19690
+ * @param delegateAddress - Address to revoke delegation from.
19807
19691
  * @returns The transaction hash and mined receipt.
19808
- *
19692
+ * @throws if no signer is configured. {@link SignerNotConfiguredError}
19809
19693
  * @throws if signer and provider are on different chains. {@link ChainMismatchError}
19810
- * @throws if the balance is less than `amount`. {@link InsufficientConfidentialBalanceError}
19811
- * @throws if balance validation requires decryption that is not possible. {@link BalanceCheckUnavailableError}
19812
- * @throws if FHE encryption fails. {@link EncryptionFailedError}
19813
- * @throws if the on-chain transfer reverts. {@link TransactionRevertedError}
19814
- *
19815
- * @example
19816
- * ```ts
19817
- * const txHash = await token.confidentialTransferAndCall(
19818
- * "0xRecipient",
19819
- * 1000n,
19820
- * "0xabcd", // caller-encoded payload forwarded to the receiver hook
19821
- * );
19822
- * ```
19694
+ * @throws if no delegation exists for this (delegator, delegate, contract) tuple. {@link DelegationNotFoundError}
19695
+ * @throws if the revocation transaction reverts. {@link TransactionRevertedError}
19823
19696
  */
19824
- confidentialTransferAndCall(to: Address, amount: bigint, data: Hex, options?: TransferOptions): Promise<TransactionResult>;
19697
+ revokeDelegation({ contractAddress, delegateAddress }: {
19698
+ contractAddress: Address;
19699
+ delegateAddress: Address;
19700
+ }): Promise<TransactionResult>;
19825
19701
  /**
19826
- * ERC-7984 `confidentialTransferFromAndCall`: operator-initiated encrypted
19827
- * transfer that also invokes the recipient's receiver hook in a single
19828
- * transaction. The caller must be an approved operator for `from` and crafts
19829
- * the opaque `data` payload — the SDK does not encode or interpret it.
19702
+ * Check whether a delegation is active for the given contract address.
19830
19703
  *
19831
- * @param from - The address to transfer from (caller must be an approved operator).
19832
- * @param to - Recipient address. Must implement the ERC-7984 receiver hook.
19833
- * @param amount - Plaintext amount to transfer (encrypted automatically via FHE).
19834
- * @param data - Opaque bytes forwarded to the recipient's receiver hook.
19835
- * @param callbacks - Optional progress callbacks.
19836
- * @returns The transaction hash and mined receipt.
19704
+ * Signer-independent: works without a configured signer.
19837
19705
  *
19838
- * @example
19839
- * ```ts
19840
- * const txHash = await token.confidentialTransferFromAndCall(
19841
- * "0xFrom",
19842
- * "0xRecipient",
19843
- * 500n,
19844
- * "0xabcd",
19845
- * );
19846
- * ```
19706
+ * @param contractAddress - The confidential contract address.
19707
+ * @param delegatorAddress - The address that granted the delegation.
19708
+ * @param delegateAddress - The address that received delegation rights.
19709
+ * @returns `true` if the delegation exists and has not expired.
19847
19710
  */
19848
- confidentialTransferFromAndCall(from: Address, to: Address, amount: bigint, data: Hex, callbacks?: TransferCallbacks): Promise<TransactionResult>;
19711
+ isActive(params: {
19712
+ contractAddress: Address;
19713
+ delegatorAddress: Address;
19714
+ delegateAddress: Address;
19715
+ }): Promise<boolean>;
19849
19716
  /**
19850
- * Set operator approval for the confidential token.
19851
- * Defaults to 1 hour from now if `until` is not specified.
19717
+ * Get the expiration timestamp of a delegation for the given contract.
19852
19718
  *
19853
- * @param operator - The address to set as an operator.
19854
- * @param until - Optional Unix timestamp for approval expiry. Defaults to now + 1 hour.
19855
- * @returns The transaction hash and mined receipt.
19719
+ * Signer-independent: works without a configured signer.
19856
19720
  *
19857
- * @example
19858
- * ```ts
19859
- * const txHash = await token.setOperator("0xOperator");
19860
- * ```
19721
+ * @param contractAddress - The confidential contract address.
19722
+ * @param delegatorAddress - The address that granted the delegation.
19723
+ * @param delegateAddress - The address that received delegation rights.
19724
+ * @returns Unix timestamp as bigint. `0n` = no delegation. `2^64 - 1` = permanent.
19861
19725
  */
19862
- setOperator(operator: Address, until?: number): Promise<TransactionResult>;
19863
- /**
19864
- * Check if a spender is an approved operator for a given holder.
19865
- *
19866
- * @param holder - The token holder address.
19867
- * @param spender - The address to check operator approval for.
19868
- * @returns `true` if the spender is an approved operator for the holder.
19869
- *
19870
- * @example
19871
- * ```ts
19872
- * if (await token.isOperator("0xHolder", "0xSpender")) {
19873
- * // spender can call transferFrom on behalf of holder
19874
- * }
19875
- * ```
19726
+ getExpiry(params: {
19727
+ contractAddress: Address;
19728
+ delegatorAddress: Address;
19729
+ delegateAddress: Address;
19730
+ }): Promise<bigint>;
19731
+ }
19732
+ //#endregion
19733
+ //#region src/namespaces/permits.d.ts
19734
+ /**
19735
+ * Public namespace for permit and transport-key-pair management.
19736
+ *
19737
+ * Exposed as `sdk.permits`. Owns the SDK-level guards (chain alignment, empty-array
19738
+ * short-circuit, decrypt-cache invalidation) and delegates the actual work to the
19739
+ * internal {@link CredentialService}.
19740
+ *
19741
+ * The namespace is named `permits` because the user-facing concept is the signed-permit
19742
+ * store. The transport key pair is invisible plumbing — there is no `getTransportKeyPair()`
19743
+ * surfaced; the key pair exists to sign permits and is created automatically when needed.
19744
+ * {@link clear} wipes both the permit store and the transport key pair (permits
19745
+ * cascade-delete with the key pair).
19746
+ *
19747
+ * When `transportKeyPairScope` is configured (opt-in shared-tenant scope for B2B2C/WaaS
19748
+ * operators), {@link clear} and {@link revokePermits} stay signer-level only — they never
19749
+ * touch the shared key pair. {@link revokeTransportKeyPair} is the distinct,
19750
+ * operator-level operation for that.
19751
+ */
19752
+ declare class Permits {
19753
+ #private;
19754
+ /** @internal */
19755
+ constructor(opts: {
19756
+ signer: GenericSigner | undefined;
19757
+ provider: GenericProvider;
19758
+ cachingService: CachingService;
19759
+ credentialService: CredentialService | undefined;
19760
+ logger: GenericLogger;
19761
+ });
19762
+ /**
19763
+ * Sign and store an EIP-712 permit authorising direct decryption for the
19764
+ * given contract addresses.
19765
+ *
19766
+ * Idempotent: if a permit covering the requested set already exists, no
19767
+ * wallet prompt occurs. Otherwise the SDK chunks the uncovered subset into
19768
+ * groups of ≤10 contracts and prompts once per chunk; partial mid-flight
19769
+ * rejection is preserved (already-signed chunks are persisted before the
19770
+ * next prompt).
19771
+ *
19772
+ * @param contracts - Contract addresses to authorize.
19876
19773
  */
19877
- isOperator(holder: Address, spender: Address): Promise<boolean>;
19774
+ grantPermit(contracts: Address[]): Promise<void>;
19878
19775
  /**
19879
- * Read the on-chain encrypted balance for a given owner.
19776
+ * Sign and store an EIP-712 delegation permit authorising decryption on
19777
+ * behalf of `delegator`. Same idempotence/chunking semantics as {@link grantPermit}.
19880
19778
  *
19881
- * @internal
19779
+ * @param delegator - The address that delegated decryption rights to the connected signer.
19780
+ * @param contracts - Contract addresses to authorize.
19882
19781
  */
19883
- protected readConfidentialBalanceOf(owner: Address): Promise<EncryptedValue>;
19782
+ grantDelegationPermit(delegator: Address, contracts: Address[]): Promise<void>;
19884
19783
  /**
19885
- * Pre-flight check: decrypt the confidential balance and compare against the
19886
- * requested amount. If credentials are cached the decrypt happens silently;
19887
- * if not, throws {@link BalanceCheckUnavailableError} instead of triggering
19888
- * a surprise EIP-712 popup.
19784
+ * Pure store lookup: is there a permit covering `contracts`?
19785
+ * No wallet prompt, no transport key pair generation. Returns `false` when no signer
19786
+ * is configured.
19787
+ */
19788
+ hasPermit(contracts: Address[]): Promise<boolean>;
19789
+ /**
19790
+ * Pure store lookup for a delegation permit. See {@link hasPermit}.
19889
19791
  *
19890
- * @internal
19792
+ * @param delegator - The address that delegated decryption rights to the connected signer.
19793
+ * @param contracts - Contract addresses to check.
19794
+ * @returns `true` if cached delegation permits cover all requested contracts.
19891
19795
  */
19892
- protected assertConfidentialBalance(amount: bigint): Promise<void>;
19796
+ hasDelegationPermit(delegator: Address, contracts: Address[]): Promise<boolean>;
19893
19797
  /**
19894
- * Emit a token-scoped event through the owning {@link ZamaSDK} so that
19895
- * subscribers see a unified stream.
19798
+ * Best-effort transport-key-pair prefetch for the connected signer.
19896
19799
  *
19897
- * @internal
19800
+ * Optional latency optimization: decrypt and permit flows remain correct
19801
+ * without it because they lazily create the transport key pair when needed.
19802
+ *
19803
+ * Silent no-op when no signer is configured or no wallet account is
19804
+ * available. The transport key pair is generated through the relayer dispatcher's
19805
+ * currently active chain — see {@link LifecycleService}, which calls
19806
+ * `switchChain` before fanning the wallet-account change out to listeners,
19807
+ * so any downstream caller (including React adapters) observes the
19808
+ * dispatcher on the wallet chain by the time it invokes warmup.
19809
+ *
19810
+ * Not for pre-warming a shared `transportKeyPairScope`: this call's wallet-account
19811
+ * precondition doesn't conceptually apply to a scope-wide key, and would silently
19812
+ * no-op precisely when an operator is most likely to be calling it (no end-user
19813
+ * connected yet). Use {@link warmTransportKeyPairScope} instead.
19898
19814
  */
19899
- protected emit(input: ZamaSDKEventInput): void;
19815
+ warmTransportKeyPair(): Promise<void>;
19900
19816
  /**
19901
- * Submit a token-scoped write transaction through the shared SDK transaction
19902
- * pipeline. Callers keep pre-flight and operation-specific work local.
19817
+ * Wipe FHE permits for the current signer.
19903
19818
  *
19904
- * @internal
19819
+ * - With no argument: every permit referencing this signer is removed across
19820
+ * all chains and delegators. The transport key pair survives — use {@link clear} to
19821
+ * also wipe the transport key pair.
19822
+ * - With a contract list: every signed permit in the direct-decrypt scope
19823
+ * (current chain) whose immutable payload touches any listed address is
19824
+ * removed. Delegation permits are not touched in this mode.
19825
+ *
19826
+ * @throws if no signer is configured. {@link SignerNotConfiguredError}
19905
19827
  */
19906
- protected submitTransaction(params: {
19907
- operation: TransactionOperation;
19908
- config: WriteContractConfig;
19909
- onSubmitted?: (txHash: Hex) => void;
19910
- }): Promise<TransactionResult>;
19911
- /** Verify all tokens share the same SDK instance and return it. */
19912
- private static assertSameSdk;
19828
+ revokePermits(contracts?: Address[]): Promise<void>;
19829
+ /**
19830
+ * Wipe the transport key pair for the current signer and cascade-delete every permit
19831
+ * (across chains and delegators) referencing it.
19832
+ *
19833
+ * @throws if no signer is configured. {@link SignerNotConfiguredError}
19834
+ */
19835
+ clear(): Promise<void>;
19836
+ /**
19837
+ * Revoke the shared transport key pair for `transportKeyPairScope` (operator-level
19838
+ * action — no wallet account needs to be connected, but a signer must still be
19839
+ * configured on this SDK instance at construction time).
19840
+ *
19841
+ * Deletes the shared key pair; every permit in the scope embeds its public key, so
19842
+ * they're all treated as stale on next access. Signer-level {@link clear} never does
19843
+ * this — it only ever wipes the calling signer's own permits.
19844
+ *
19845
+ * Not best-effort, unlike most credential-store writes: a storage failure rejects
19846
+ * instead of being logged and swallowed. This is the primitive an operator reaches
19847
+ * for on suspected key compromise — a resolved promise must mean the key pair is
19848
+ * actually gone.
19849
+ *
19850
+ * Stops the SDK from reissuing or reusing the deleted key — does not revoke any
19851
+ * permit already issued under it. A permit is a self-contained, bearer-style EIP-712
19852
+ * signature the relayer accepts independently of this SDK; one exfiltrated alongside
19853
+ * the key remains usable until its own `permitTTL` expiry regardless of this call.
19854
+ *
19855
+ * @param scopeId - Must match the configured `transportKeyPairScope`, as a guard
19856
+ * against revoking the wrong scope by mistake.
19857
+ * @throws if no signer is configured. {@link SignerNotConfiguredError}
19858
+ * @throws if no scope is configured, or `scopeId` doesn't match it. {@link ConfigurationError}
19859
+ * @throws if the underlying storage delete fails.
19860
+ */
19861
+ revokeTransportKeyPair(scopeId: string): Promise<void>;
19862
+ /**
19863
+ * Warm the shared transport key pair for `transportKeyPairScope` (operator-level —
19864
+ * no wallet account needs to be connected, but a signer must still be configured on
19865
+ * this SDK instance at construction time) — the pre-warm counterpart to
19866
+ * {@link revokeTransportKeyPair}. Prefer this over {@link warmTransportKeyPair} for a
19867
+ * scoped key pair: unlike that method, this never silently no-ops for lack of a
19868
+ * connected wallet, because a scope-wide key was never tied to one in the first place.
19869
+ *
19870
+ * @param scopeId - Must match the configured `transportKeyPairScope`, as a guard
19871
+ * against warming the wrong scope by mistake.
19872
+ * @throws if no signer is configured. {@link SignerNotConfiguredError}
19873
+ * @throws if no scope is configured, or `scopeId` doesn't match it. {@link ConfigurationError}
19874
+ */
19875
+ warmTransportKeyPairScope(scopeId: string): Promise<void>;
19913
19876
  }
19914
19877
  //#endregion
19915
- //#region src/token/wrapped-token.d.ts
19878
+ //#region src/token/token.d.ts
19879
+ /** Options for {@link Token.batchDecryptBalancesAs}. */
19880
+ interface BatchDecryptAsOptions {
19881
+ /** The address of the account that delegated decryption rights. */
19882
+ delegatorAddress: Address;
19883
+ /** Pre-fetched encrypted values. When omitted, they are fetched from the chain. */
19884
+ encryptedValues?: EncryptedValue[];
19885
+ /**
19886
+ * The account whose on-chain balance to read. Defaults to the delegator
19887
+ * address, which is the common case (the delegator grants permission to
19888
+ * decrypt their own balance). Only set this when the account differs
19889
+ * from the delegator.
19890
+ *
19891
+ * Matches the `account` parameter of `confidentialBalanceOf(account)` on-chain.
19892
+ */
19893
+ accountAddress?: Address;
19894
+ /** Maximum number of concurrent decrypt calls. Default: 10. */
19895
+ maxConcurrency?: number;
19896
+ /** Called when decryption fails for a single token. Return a fallback bigint. */
19897
+ onError?: (error: Error, address: Address) => bigint;
19898
+ }
19899
+ /** Result of {@link Token.batchBalancesOf}. */
19900
+ interface BatchBalancesResult {
19901
+ /** Successfully decrypted balances, keyed by token address. */
19902
+ results: Map<Address, bigint>;
19903
+ /** Per-token errors for tokens that failed to decrypt. */
19904
+ errors: Map<Address, ZamaError>;
19905
+ }
19916
19906
  /**
19917
- * Confidential ERC-20 wrapper (ERC-7984 ERC20Wrapper).
19907
+ * High-level interface for an ERC-7984 confidential token.
19908
+ * Hides FHE complexity (encryption, decryption, EIP-712 signing) behind
19909
+ * familiar ERC-20-like methods.
19918
19910
  *
19919
- * Extends {@link Token} with wrapper-specific operations:
19920
- * - `shield` / `unshield` — convert between the underlying ERC-20 and confidential balance
19921
- * - `unwrap` / `unwrapAll` / `finalizeUnwrap` — low-level two-phase primitives
19922
- * - `underlying` / `allowance` — wrapper reads
19911
+ * For ERC-7984 wrappers (shield/unshield), use {@link WrappedToken} instead —
19912
+ * it extends `Token` with wrapper-specific operations.
19923
19913
  *
19924
- * `WrappedToken.address` is the wrapper contract address itself — the wrapper
19925
- * IS the confidential token.
19914
+ * Decryption, credentials, caching, and event emission are handled by the
19915
+ * owning {@link ZamaSDK} — this class only exposes token-scoped helpers
19916
+ * that delegate to `sdk.decryption.decryptValues` and `sdk.permits.grantPermit`.
19926
19917
  */
19927
- declare class WrappedToken extends Token {
19918
+ declare class Token {
19928
19919
  #private;
19920
+ readonly sdk: ZamaSDK;
19921
+ readonly address: Address;
19922
+ constructor(sdk: ZamaSDK, address: Address);
19923
+ /** Read the token name from the contract. */
19924
+ name(): Promise<string>;
19925
+ /** Read the token symbol from the contract. */
19926
+ symbol(): Promise<string>;
19927
+ /** Read the token decimals from the contract. */
19928
+ decimals(): Promise<number>;
19929
19929
  /**
19930
- * Read the underlying ERC-20 token address from the wrapper contract.
19930
+ * ERC-165 check for {@link ERC7984_INTERFACE_ID} support.
19931
19931
  *
19932
- * @returns The underlying ERC-20 token address.
19933
- */
19934
- underlying(): Promise<Address>;
19935
- /**
19936
- * Check whether the underlying ERC-20 supports ERC-1363 (payable token).
19937
- * Result is cached per WrappedToken instance (negative results included):
19938
- * once we know an underlying does not support ERC-1363, subsequent shields
19939
- * go straight to the `approve` + `wrap` path without re-probing.
19932
+ * @returns `true` if the contract implements the ERC-7984 confidential token interface.
19940
19933
  */
19941
- isPayable(): Promise<boolean>;
19934
+ isConfidential(): Promise<boolean>;
19942
19935
  /**
19943
- * Read the ERC-20 allowance granted by `owner` to this wrapper for the
19944
- * underlying token.
19936
+ * ERC-165 check for IERC7984ERC20Wrapper support.
19945
19937
  *
19946
- * @param owner - The owner address whose allowance to read.
19947
- * @returns The current allowance as a bigint.
19938
+ * @returns `true` if the contract implements the ERC-7984 wrapper interface
19939
+ * ({@link ERC7984_WRAPPER_INTERFACE_ID}, `0x1f1c62b2`).
19948
19940
  */
19949
- allowance(owner: Address): Promise<bigint>;
19941
+ isWrapper(): Promise<boolean>;
19950
19942
  /**
19951
- * Shield public ERC-20 tokens into confidential tokens.
19952
- *
19953
- * The execution path is decided automatically by ERC-165 introspection on
19954
- * the underlying ERC-20:
19955
- * - **`transferAndCall`** (single tx): when the underlying supports
19956
- * ERC-1363, no approval is required — the wrapper's `onTransferReceived`
19957
- * callback mints confidential tokens directly. `approvalStrategy` is
19958
- * **ignored** on this path. See {@link ShieldPath}.
19959
- * - **`approveAndWrap`** (two-tx fallback): otherwise, an `approve` is
19960
- * followed by a `wrap`. Approval is controlled by `approvalStrategy`
19961
- * (`"exact"` by default, `"max"` for unlimited, `"skip"` to opt out).
19962
- *
19963
- * The ERC-20 balance is validated before submitting (public read, no
19964
- * signing required) so the call works for all wallet types, including
19965
- * smart wallets.
19943
+ * Decrypt and return the plaintext balance for the given owner.
19944
+ * Acquires FHE credentials via a wallet signature if none are cached.
19966
19945
  *
19967
- * @param amount - The plaintext amount to shield.
19968
- * @param options - Optional: `approvalStrategy`, `to`, callbacks.
19969
- * @returns The transaction hash and mined receipt.
19970
- * @throws if signer and provider are on different chains. {@link ChainMismatchError}
19971
- * @throws if the ERC-20 balance is less than `amount`. {@link InsufficientERC20BalanceError}
19972
- * @throws if the ERC-20 approval or shield transaction reverts. {@link TransactionRevertedError}
19946
+ * @param owner - Balance owner address.
19947
+ * @returns The decrypted plaintext balance as a bigint.
19948
+ * @throws if FHE decryption fails. {@link DecryptionFailedError}
19973
19949
  *
19974
19950
  * @example
19975
19951
  * ```ts
19976
- * const txHash = await wrappedToken.shield(1000n);
19952
+ * const balance = await token.balanceOf("0xOwner");
19977
19953
  * ```
19978
19954
  */
19979
- shield(amount: bigint, options?: ShieldOptions): Promise<TransactionResult>;
19955
+ balanceOf(owner: Address): Promise<bigint>;
19980
19956
  /**
19981
- * Approve this wrapper contract to spend the underlying ERC-20.
19982
- * Defaults to max uint256. Resets to zero first if there's an existing
19983
- * non-zero allowance (required by tokens like USDT).
19957
+ * Return the raw encrypted balance without decrypting.
19984
19958
  *
19985
- * @param amount - Optional approval amount. Defaults to max uint256.
19986
- * @returns The transaction hash and mined receipt.
19959
+ * @param owner - Balance owner address.
19960
+ * @returns The encrypted balance as a hex string.
19987
19961
  *
19988
19962
  * @example
19989
19963
  * ```ts
19990
- * await wrappedToken.approveUnderlying(); // max approval
19991
- * await wrappedToken.approveUnderlying(1000n); // exact amount
19964
+ * const encryptedValue = await token.confidentialBalanceOf("0xOwner");
19992
19965
  * ```
19993
19966
  */
19994
- approveUnderlying(amount?: bigint): Promise<TransactionResult>;
19967
+ confidentialBalanceOf(owner: Address): Promise<EncryptedValue>;
19995
19968
  /**
19996
- * Unshield a specific amount and finalize in one call.
19997
- * Orchestrates: unshield → wait for receipt → parse event → finalize.
19969
+ * Decrypt the balance of a delegator using delegated decryption credentials.
19970
+ * The connected signer acts as the delegatee who has been granted permission
19971
+ * by the delegator to decrypt their balance.
19998
19972
  *
19999
- * By default, the SDK validates the confidential balance before submitting.
20000
- * Set `skipBalanceCheck: true` to bypass this validation (e.g. for smart wallets).
19973
+ * Clear values are cached in storage keyed by `(account, token, encryptedValue)`.
19974
+ * Because every on-chain balance change produces a new encrypted value,
19975
+ * stale cache entries are never served. Cache write failures are silently
19976
+ * ignored — they do not affect the returned value.
20001
19977
  *
20002
- * @param amount - The plaintext amount to unshield.
20003
- * @param options - Optional: `skipBalanceCheck` (default `false`), callbacks.
20004
- * @returns The finalize transaction hash and mined receipt.
19978
+ * @param delegatorAddress - The address of the account that delegated decryption rights.
19979
+ * @param accountAddress - The account whose on-chain balance to read. Defaults
19980
+ * to the delegator address.
19981
+ * @returns The decrypted plaintext balance as a bigint.
19982
+ * @throws if no active delegation exists. {@link DelegationNotFoundError}
19983
+ * @throws if the delegation has expired. {@link DelegationExpiredError}
19984
+ * @throws if delegated decryption fails. {@link DecryptionFailedError}
20005
19985
  *
20006
19986
  * @example
20007
19987
  * ```ts
20008
- * const txHash = await wrappedToken.unshield(500n);
19988
+ * const balance = await token.decryptBalanceAs({
19989
+ * delegatorAddress: "0xDelegator",
19990
+ * });
20009
19991
  * ```
20010
19992
  */
20011
- unshield(amount: bigint, options?: UnshieldOptions): Promise<TransactionResult>;
19993
+ decryptBalanceAs({ delegatorAddress, accountAddress }: {
19994
+ delegatorAddress: Address;
19995
+ accountAddress?: Address;
19996
+ }): Promise<bigint>;
20012
19997
  /**
20013
- * Unshield the entire balance and finalize in one call.
20014
- * Orchestrates: unshieldAll → wait for receipt → parse event → finalize.
19998
+ * Decrypt confidential balances for multiple tokens in parallel, returning
19999
+ * successes and per-token errors separately. Pre-authorizes all token
20000
+ * addresses in a single wallet signature, then delegates each decrypt to
20001
+ * `sdk.decryption.decryptValues`.
20015
20002
  *
20016
- * @param callbacks - Optional progress callbacks for each phase.
20017
- * @returns The finalize transaction hash and mined receipt.
20018
- * @throws if the balance is zero. {@link DecryptionFailedError}
20003
+ * Tokens that fail to decrypt land in `errors` rather than aborting the
20004
+ * whole batch — caller decides how to surface them.
20005
+ *
20006
+ * @param tokens - Array of {@link Token} instances bound to the same SDK.
20007
+ * @param owner - Balance owner address.
20008
+ * @returns `{ results, errors }` partitioning the per-token outcomes.
20019
20009
  *
20020
20010
  * @example
20021
20011
  * ```ts
20022
- * const txHash = await wrappedToken.unshieldAll();
20012
+ * const { results, errors } = await Token.batchBalancesOf(tokens, owner);
20023
20013
  * ```
20024
20014
  */
20025
- unshieldAll(callbacks?: UnshieldCallbacks): Promise<TransactionResult>;
20015
+ static batchBalancesOf(tokens: Token[], owner: Address): Promise<BatchBalancesResult>;
20026
20016
  /**
20027
- * Resume an in-progress unshield from an existing unwrap tx hash.
20028
- * Useful when the user already submitted the unwrap but the finalize step
20029
- * was interrupted (e.g. page reload, network error).
20017
+ * Batch decrypt confidential balances as a delegate across multiple tokens.
20018
+ * Mirrors {@link batchBalancesOf} but uses delegated credentials.
20030
20019
  *
20031
- * @param unwrapTxHash - The transaction hash of the previously submitted unwrap.
20032
- * @param callbacks - Optional progress callbacks.
20033
- * @returns The finalize transaction hash and mined receipt.
20020
+ * **Error handling:** If a per-token decryption fails and no `onError` callback
20021
+ * is provided, errors are collected and thrown as an aggregated
20022
+ * `DecryptionFailedError`. When the relayer returns no value for an encrypted value,
20023
+ * a `DecryptionFailedError` is thrown for that token (never silently returns `0n`).
20024
+ * Pass `onError: () => 0n` to opt into the silent zero behavior.
20025
+ *
20026
+ * @param tokens - Array of Token instances to decrypt balances for.
20027
+ * @param options - Delegated decryption configuration.
20028
+ * @returns A Map from token address to decrypted balance.
20029
+ * @throws if no active delegation exists. {@link DelegationNotFoundError}
20030
+ * @throws if the delegation has expired. {@link DelegationExpiredError}
20031
+ * @throws if any decryption fails and no `onError` is provided. {@link DecryptionFailedError}
20034
20032
  *
20035
20033
  * @example
20036
20034
  * ```ts
20037
- * const txHash = await wrappedToken.resumeUnshield(previousUnwrapTxHash);
20035
+ * const balances = await Token.batchDecryptBalancesAs(tokens, {
20036
+ * delegatorAddress: "0xDelegator",
20037
+ * onError: (err, addr) => { console.error(addr, err); return 0n; },
20038
+ * });
20038
20039
  * ```
20039
20040
  */
20040
- resumeUnshield(unwrapTxHash: Hex, callbacks?: UnshieldCallbacks): Promise<TransactionResult>;
20041
+ static batchDecryptBalancesAs(tokens: Token[], options: BatchDecryptAsOptions): Promise<Map<Address, bigint>>;
20042
+ private static readBalanceHandlesBatch;
20041
20043
  /**
20042
- * Return the unwrap tx hash of an unshield that was interrupted between its
20043
- * two phases, or `null` if none is pending for this wrapper.
20044
+ * Confidential transfer. Encrypts the amount via FHE, then calls the contract.
20044
20045
  *
20045
- * The SDK persists this automatically when {@link unshield}/{@link unshieldAll}
20046
- * submit phase 1, and clears it once phase 2 finalizes. Use the returned hash
20047
- * to surface a "resume" affordance, then pass it to {@link resumeUnshield}.
20048
- * Resuming is intentionally caller-driven — auto-resuming on load would fire a
20049
- * wallet transaction unprompted.
20046
+ * By default, the SDK validates the confidential balance before submitting.
20047
+ * If a cached plaintext balance exists it is used; otherwise, if credentials
20048
+ * are cached, it decrypts on the fly. Set `skipBalanceCheck: true` to bypass
20049
+ * this validation (e.g. for smart wallets).
20050
20050
  *
20051
- * @returns The pending unwrap tx hash, or `null`.
20051
+ * @param to - Recipient address.
20052
+ * @param amount - Plaintext amount to transfer (encrypted automatically via FHE).
20053
+ * @param options - Optional: `skipBalanceCheck` (default `false`).
20054
+ * @returns The transaction hash and mined receipt.
20055
+ * @throws if signer and provider are on different chains. {@link ChainMismatchError}
20056
+ * @throws if the balance is less than `amount`. {@link InsufficientConfidentialBalanceError}
20057
+ * @throws if balance validation requires decryption that is not possible. {@link BalanceCheckUnavailableError}
20058
+ * @throws if FHE encryption fails. {@link EncryptionFailedError}
20059
+ * @throws if the on-chain transfer reverts. {@link TransactionRevertedError}
20052
20060
  *
20053
20061
  * @example
20054
20062
  * ```ts
20055
- * const unwrapTxHash = await wrappedToken.getPendingUnshield();
20056
- * if (unwrapTxHash) await wrappedToken.resumeUnshield(unwrapTxHash);
20063
+ * const txHash = await token.confidentialTransfer("0xRecipient", 1000n);
20057
20064
  * ```
20058
20065
  */
20059
- getPendingUnshield(): Promise<Hex | null>;
20066
+ confidentialTransfer(to: Address, amount: bigint, options?: TransferOptions): Promise<TransactionResult>;
20060
20067
  /**
20061
- * Request an unwrap for a specific amount. Encrypts the amount first.
20062
- * Call {@link finalizeUnwrap} after the request is processed on-chain.
20068
+ * Operator encrypted transfer on behalf of another address.
20069
+ * The caller must be an approved operator for `from`.
20063
20070
  *
20064
- * @param amount - The plaintext amount to unwrap (encrypted automatically).
20071
+ * @param from - The address to transfer from (caller must be an approved operator).
20072
+ * @param to - Recipient address.
20073
+ * @param amount - Plaintext amount to transfer (encrypted automatically via FHE).
20065
20074
  * @returns The transaction hash and mined receipt.
20066
20075
  *
20067
20076
  * @example
20068
20077
  * ```ts
20069
- * const txHash = await wrappedToken.unwrap(500n);
20078
+ * const txHash = await token.confidentialTransferFrom("0xFrom", "0xTo", 500n);
20070
20079
  * ```
20071
20080
  */
20072
- unwrap(amount: bigint): Promise<TransactionResult>;
20081
+ confidentialTransferFrom(from: Address, to: Address, amount: bigint, callbacks?: TransferCallbacks): Promise<TransactionResult>;
20073
20082
  /**
20074
- * Request an unwrap for the entire confidential balance.
20075
- * Uses the on-chain encrypted balance directly (no encryption needed).
20076
- * Throws if the balance is zero.
20083
+ * ERC-7984 `confidentialTransferAndCall`: encrypted transfer that also invokes
20084
+ * the recipient's receiver hook (`onConfidentialTransferReceived`) in a single
20085
+ * transaction. The caller crafts the opaque `data` payload — the SDK does not
20086
+ * encode, validate, or interpret it.
20087
+ *
20088
+ * Balance validation follows the same rules as {@link Token.confidentialTransfer}.
20077
20089
  *
20090
+ * @param to - Recipient address. Must implement the ERC-7984 receiver hook.
20091
+ * @param amount - Plaintext amount to transfer (encrypted automatically via FHE).
20092
+ * @param data - Opaque bytes forwarded to the recipient's receiver hook.
20093
+ * @param options - Optional: `skipBalanceCheck` (default `false`).
20078
20094
  * @returns The transaction hash and mined receipt.
20079
- * @throws if the balance is zero. {@link DecryptionFailedError}
20095
+ *
20096
+ * @throws if signer and provider are on different chains. {@link ChainMismatchError}
20097
+ * @throws if the balance is less than `amount`. {@link InsufficientConfidentialBalanceError}
20098
+ * @throws if balance validation requires decryption that is not possible. {@link BalanceCheckUnavailableError}
20099
+ * @throws if FHE encryption fails. {@link EncryptionFailedError}
20100
+ * @throws if the on-chain transfer reverts. {@link TransactionRevertedError}
20080
20101
  *
20081
20102
  * @example
20082
20103
  * ```ts
20083
- * const txHash = await wrappedToken.unwrapAll();
20104
+ * const txHash = await token.confidentialTransferAndCall(
20105
+ * "0xRecipient",
20106
+ * 1000n,
20107
+ * "0xabcd", // caller-encoded payload forwarded to the receiver hook
20108
+ * );
20084
20109
  * ```
20085
20110
  */
20086
- unwrapAll(): Promise<TransactionResult>;
20111
+ confidentialTransferAndCall(to: Address, amount: bigint, data: Hex, options?: TransferOptions): Promise<TransactionResult>;
20087
20112
  /**
20088
- * Complete an unwrap by providing the public decryption proof.
20089
- * Call this after an unshield request has been processed on-chain.
20113
+ * ERC-7984 `confidentialTransferFromAndCall`: operator-initiated encrypted
20114
+ * transfer that also invokes the recipient's receiver hook in a single
20115
+ * transaction. The caller must be an approved operator for `from` and crafts
20116
+ * the opaque `data` payload — the SDK does not encode or interpret it.
20090
20117
  *
20091
- * @param unwrapRequestId - `unwrapRequestId` from the `UnwrapRequested` event.
20118
+ * @param from - The address to transfer from (caller must be an approved operator).
20119
+ * @param to - Recipient address. Must implement the ERC-7984 receiver hook.
20120
+ * @param amount - Plaintext amount to transfer (encrypted automatically via FHE).
20121
+ * @param data - Opaque bytes forwarded to the recipient's receiver hook.
20122
+ * @param callbacks - Optional progress callbacks.
20092
20123
  * @returns The transaction hash and mined receipt.
20093
20124
  *
20094
20125
  * @example
20095
20126
  * ```ts
20096
- * const event = findUnwrapRequested(receipt.logs);
20097
- * const txHash = await wrappedToken.finalizeUnwrap(event.unwrapRequestId);
20127
+ * const txHash = await token.confidentialTransferFromAndCall(
20128
+ * "0xFrom",
20129
+ * "0xRecipient",
20130
+ * 500n,
20131
+ * "0xabcd",
20132
+ * );
20098
20133
  * ```
20099
20134
  */
20100
- finalizeUnwrap(unwrapRequestId: EncryptedValue): Promise<TransactionResult>;
20101
- }
20102
- //#endregion
20103
- //#region src/query/confidential-balance.d.ts
20104
- interface ConfidentialBalanceQueryConfig {
20105
- tokenAddress: Address;
20106
- account?: Address;
20107
- query?: Record<string, unknown>;
20108
- }
20109
- /** Query options for a single confidential token balance. Auto-gated on `account`. */
20110
- declare function confidentialBalanceQueryOptions(token: Token, config: ConfidentialBalanceQueryConfig, signerContext?: SignerQueryContext): QueryFactoryOptions<bigint, Error, bigint, ReturnType<typeof zamaQueryKeys.confidentialBalance.owner>>;
20111
- //#endregion
20112
- //#region src/query/confidential-balances.d.ts
20113
- interface ConfidentialBalancesQueryConfig {
20114
- account?: Address;
20115
- query?: Record<string, unknown>;
20116
- }
20117
- declare function confidentialBalancesQueryOptions(tokens: Token[], config?: ConfidentialBalancesQueryConfig, signerContext?: SignerQueryContext): QueryFactoryOptions<BatchBalancesResult, Error, BatchBalancesResult, ReturnType<typeof zamaQueryKeys.confidentialBalances.tokens>>;
20118
- //#endregion
20119
- //#region src/query/wrappers-registry.d.ts
20120
- interface WrappersRegistryQueryConfig {
20121
- registryAddress: Address | undefined;
20122
- query?: Record<string, unknown>;
20123
- }
20124
- declare function tokenPairsQueryOptions(sdk: ZamaSDK, config: WrappersRegistryQueryConfig): QueryFactoryOptions<readonly TokenWrapperPair[], Error, readonly TokenWrapperPair[], ReturnType<typeof zamaQueryKeys.wrappersRegistry.tokenPairs>>;
20125
- interface ConfidentialTokenAddressQueryConfig extends WrappersRegistryQueryConfig {
20126
- tokenAddress?: Address;
20127
- }
20128
- declare function confidentialTokenAddressQueryOptions(sdk: ZamaSDK, config: ConfidentialTokenAddressQueryConfig): QueryFactoryOptions<readonly [boolean, Address], Error, readonly [boolean, Address], ReturnType<typeof zamaQueryKeys.wrappersRegistry.confidentialTokenAddress>>;
20129
- interface TokenAddressQueryConfig extends WrappersRegistryQueryConfig {
20130
- confidentialTokenAddress?: Address;
20131
- }
20132
- declare function tokenAddressQueryOptions(sdk: ZamaSDK, config: TokenAddressQueryConfig): QueryFactoryOptions<readonly [boolean, Address], Error, readonly [boolean, Address], ReturnType<typeof zamaQueryKeys.wrappersRegistry.tokenAddress>>;
20133
- declare function tokenPairsLengthQueryOptions(sdk: ZamaSDK, config: WrappersRegistryQueryConfig): QueryFactoryOptions<bigint, Error, bigint, ReturnType<typeof zamaQueryKeys.wrappersRegistry.tokenPairsLength>>;
20134
- interface TokenPairsSliceQueryConfig extends WrappersRegistryQueryConfig {
20135
- fromIndex?: bigint;
20136
- toIndex?: bigint;
20137
- }
20138
- declare function tokenPairsSliceQueryOptions(sdk: ZamaSDK, config: TokenPairsSliceQueryConfig): QueryFactoryOptions<readonly TokenWrapperPair[], Error, readonly TokenWrapperPair[], ReturnType<typeof zamaQueryKeys.wrappersRegistry.tokenPairsSlice>>;
20139
- interface TokenPairQueryConfig extends WrappersRegistryQueryConfig {
20140
- index?: bigint;
20141
- }
20142
- declare function tokenPairQueryOptions(sdk: ZamaSDK, config: TokenPairQueryConfig): QueryFactoryOptions<TokenWrapperPair, Error, TokenWrapperPair, ReturnType<typeof zamaQueryKeys.wrappersRegistry.tokenPair>>;
20143
- interface IsConfidentialTokenValidQueryConfig extends WrappersRegistryQueryConfig {
20144
- confidentialTokenAddress?: Address;
20145
- }
20146
- declare function isConfidentialTokenValidQueryOptions(sdk: ZamaSDK, config: IsConfidentialTokenValidQueryConfig): QueryFactoryOptions<boolean, Error, boolean, ReturnType<typeof zamaQueryKeys.wrappersRegistry.isConfidentialTokenValid>>;
20147
- interface ListPairsQueryConfig {
20148
- /**
20149
- * The registry address for this chain — used as a query key discriminator.
20150
- * The registry instance already knows how to resolve the address for the
20151
- * current chain; this field just keeps the TanStack Query cache isolated
20152
- * per registry contract.
20153
- */
20154
- registryAddress: Address | undefined;
20155
- page?: number;
20156
- pageSize?: number;
20157
- metadata?: boolean;
20158
- query?: Record<string, unknown>;
20159
- }
20160
- /**
20161
- * Query options for paginated listing of token wrapper pairs.
20162
- *
20163
- * Accepts a {@link WrappersRegistry} instance rather than a raw provider so that the
20164
- * class-level TTL cache is shared across multiple `queryFn` executions. Pass
20165
- * `sdk.registry` (the ZamaSDK lazy singleton) to ensure a single shared cache.
20166
- */
20167
- declare function listPairsQueryOptions(registry: WrappersRegistry, config: ListPairsQueryConfig): QueryFactoryOptions<PaginatedResult<TokenWrapperPair | TokenWrapperPairWithMetadata>, Error, PaginatedResult<TokenWrapperPair | TokenWrapperPairWithMetadata>, ReturnType<typeof zamaQueryKeys.wrappersRegistry.listPairs>>;
20168
- //#endregion
20169
- //#region src/query/shield.d.ts
20170
- /** Variables for {@link shieldMutationOptions}. */
20171
- interface ShieldParams extends ShieldOptions {
20172
- amount: bigint;
20173
- }
20174
- declare function shieldMutationOptions(token: WrappedToken): MutationFactoryOptions<readonly ["zama.shield", Address], ShieldParams, TransactionResult>;
20175
- //#endregion
20176
- //#region src/query/transfer.d.ts
20177
- /** Variables for {@link confidentialTransferMutationOptions}. */
20178
- interface ConfidentialTransferParams extends TransferOptions {
20179
- to: Address;
20180
- amount: bigint;
20181
- }
20182
- declare function confidentialTransferMutationOptions(token: Token): MutationFactoryOptions<readonly ["zama.confidentialTransfer", Address], ConfidentialTransferParams, TransactionResult>;
20183
- //#endregion
20184
- //#region src/query/transfer-and-call.d.ts
20185
- /** Variables for {@link confidentialTransferAndCallMutationOptions}. */
20186
- interface ConfidentialTransferAndCallParams extends TransferOptions {
20187
- to: Address;
20188
- amount: bigint;
20189
- /** Opaque bytes forwarded to the recipient's ERC-7984 receiver hook. */
20190
- data: Hex;
20191
- }
20192
- declare function confidentialTransferAndCallMutationOptions(token: Token): MutationFactoryOptions<readonly ["zama.confidentialTransferAndCall", Address], ConfidentialTransferAndCallParams, TransactionResult>;
20193
- //#endregion
20194
- //#region src/query/transfer-from.d.ts
20195
- /** Variables for {@link confidentialTransferFromMutationOptions}. */
20196
- interface ConfidentialTransferFromParams {
20197
- from: Address;
20198
- to: Address;
20199
- amount: bigint;
20200
- /** Optional progress callbacks for the multi-step transfer flow. */
20201
- callbacks?: TransferCallbacks;
20202
- }
20203
- declare function confidentialTransferFromMutationOptions(token: Token): MutationFactoryOptions<readonly ["zama.confidentialTransferFrom", Address], ConfidentialTransferFromParams, TransactionResult>;
20204
- //#endregion
20205
- //#region src/query/transfer-from-and-call.d.ts
20206
- /** Variables for {@link confidentialTransferFromAndCallMutationOptions}. */
20207
- interface ConfidentialTransferFromAndCallParams {
20208
- from: Address;
20209
- to: Address;
20210
- amount: bigint;
20211
- /** Opaque bytes forwarded to the recipient's ERC-7984 receiver hook. */
20212
- data: Hex;
20213
- /** Optional progress callbacks for the multi-step transfer flow. */
20214
- callbacks?: TransferCallbacks;
20215
- }
20216
- declare function confidentialTransferFromAndCallMutationOptions(token: Token): MutationFactoryOptions<readonly ["zama.confidentialTransferFromAndCall", Address], ConfidentialTransferFromAndCallParams, TransactionResult>;
20217
- //#endregion
20218
- //#region src/query/set-operator.d.ts
20219
- /** Variables for {@link confidentialSetOperatorMutationOptions}. */
20220
- interface ConfidentialSetOperatorParams {
20221
- operator: Address;
20222
- until?: number;
20223
- }
20224
- declare function confidentialSetOperatorMutationOptions(token: Token): MutationFactoryOptions<readonly ["zama.confidentialSetOperator", Address], ConfidentialSetOperatorParams, TransactionResult>;
20225
- //#endregion
20226
- //#region src/query/approve-underlying.d.ts
20227
- /** Variables for {@link approveUnderlyingMutationOptions}. */
20228
- interface ApproveUnderlyingParams {
20229
- amount?: bigint;
20230
- }
20231
- declare function approveUnderlyingMutationOptions(token: WrappedToken): MutationFactoryOptions<readonly ["zama.approveUnderlying", Address], ApproveUnderlyingParams, TransactionResult>;
20232
- //#endregion
20233
- //#region src/query/unshield.d.ts
20234
- /** Variables for {@link unshieldMutationOptions}. */
20235
- interface UnshieldParams extends UnshieldOptions {
20236
- amount: bigint;
20237
- }
20238
- declare function unshieldMutationOptions(token: WrappedToken): MutationFactoryOptions<readonly ["zama.unshield", Address], UnshieldParams, TransactionResult>;
20239
- //#endregion
20240
- //#region src/query/unshield-all.d.ts
20241
- /** Variables for {@link unshieldAllMutationOptions}. */
20242
- interface UnshieldAllParams extends UnshieldCallbacks {}
20243
- declare function unshieldAllMutationOptions(token: WrappedToken): MutationFactoryOptions<readonly ["zama.unshieldAll", Address], UnshieldAllParams | void, TransactionResult>;
20244
- //#endregion
20245
- //#region src/query/resume-unshield.d.ts
20246
- /** Variables for {@link resumeUnshieldMutationOptions}. */
20247
- interface ResumeUnshieldParams extends UnshieldCallbacks {
20248
- unwrapTxHash: Hex;
20249
- }
20250
- declare function resumeUnshieldMutationOptions(token: WrappedToken): MutationFactoryOptions<readonly ["zama.resumeUnshield", Address], ResumeUnshieldParams, TransactionResult>;
20251
- //#endregion
20252
- //#region src/query/unwrap.d.ts
20253
- /** Variables for {@link unwrapMutationOptions}. */
20254
- interface UnwrapParams {
20255
- amount: bigint;
20256
- }
20257
- declare function unwrapMutationOptions(token: WrappedToken): MutationFactoryOptions<readonly ["zama.unwrap", Address], UnwrapParams, TransactionResult>;
20258
- //#endregion
20259
- //#region src/query/unwrap-all.d.ts
20260
- declare function unwrapAllMutationOptions(token: WrappedToken): MutationFactoryOptions<readonly ["zama.unwrapAll", Address], void, TransactionResult>;
20261
- //#endregion
20262
- //#region src/query/finalize-unwrap.d.ts
20263
- /** Variables for {@link finalizeUnwrapMutationOptions}. */
20264
- type FinalizeUnwrapParams = {
20265
- /** Identifier from an `UnwrapRequested` event. */
20266
- unwrapRequestId: EncryptedValue;
20267
- };
20268
- declare function finalizeUnwrapMutationOptions(token: WrappedToken): MutationFactoryOptions<readonly ["zama.finalizeUnwrap", Address], FinalizeUnwrapParams, TransactionResult>;
20269
- //#endregion
20270
- //#region src/query/encrypt.d.ts
20271
- declare function encryptMutationOptions(sdk: ZamaSDK): MutationFactoryOptions<readonly ["zama.encrypt"], EncryptParams, EncryptResult>;
20272
- //#endregion
20273
- //#region src/query/user-decrypt.d.ts
20274
- interface EncryptedInput {
20275
- encryptedValue: EncryptedValue;
20276
- contractAddress: Address;
20277
- }
20278
- /** Decrypted clear values keyed by encrypted handle. */
20279
- type DecryptResult = Readonly<Record<EncryptedValue, ClearValue>>;
20280
- declare function decryptValuesQueryOptions(sdk: ZamaSDK, encryptedInputs: EncryptedInput[], signerContext?: SignerQueryContext): QueryFactoryOptions<DecryptResult, Error, DecryptResult, ReturnType<typeof zamaQueryKeys.decryption.encryptedInputs>>;
20281
- //#endregion
20282
- //#region src/query/delegated-decrypt.d.ts
20283
- interface DelegatedDecryptValuesMutationParams {
20284
- encryptedInputs: EncryptedInput[];
20285
- delegatorAddress: Address;
20286
- }
20287
- declare function delegatedDecryptValuesMutationOptions(sdk: ZamaSDK): MutationFactoryOptions<readonly ["zama.delegatedDecryptValues"], DelegatedDecryptValuesMutationParams, Readonly<Record<EncryptedValue, ClearValue>>>;
20288
- //#endregion
20289
- //#region src/query/public-decrypt.d.ts
20290
- declare function decryptPublicValuesMutationOptions(sdk: ZamaSDK): MutationFactoryOptions<readonly ["zama.decryptPublicValues"], EncryptedValue[], DecryptPublicValuesResult>;
20291
- //#endregion
20292
- //#region src/query/grant-permit.d.ts
20293
- declare function grantPermitMutationOptions(sdk: ZamaSDK): MutationFactoryOptions<readonly ["zama.grantPermit"], Address[], void>;
20294
- //#endregion
20295
- //#region src/query/has-permit.d.ts
20296
- interface HasPermitQueryConfig {
20297
- /** Contract addresses to check credentials against. */
20298
- contractAddresses: Address[];
20299
- /**
20300
- * Standard TanStack query options. `hasPermit` intentionally overrides cache
20301
- * timing because permit state is wallet-local, not server state: every fetch
20302
- * should read the SDK credential service directly.
20303
- */
20304
- query?: Record<string, unknown>;
20305
- }
20306
- declare function hasPermitQueryOptions(sdk: ZamaSDK, config: HasPermitQueryConfig, signerContext?: SignerQueryContext): QueryFactoryOptions<boolean, Error, boolean, ReturnType<typeof zamaQueryKeys.hasPermit.scope>>;
20307
- //#endregion
20308
- //#region src/query/revoke-permits.d.ts
20309
- /** TanStack Query mutation factory for {@link Permits.revokePermits}. */
20310
- declare function revokePermitsMutationOptions(sdk: ZamaSDK): MutationFactoryOptions<readonly ["zama.revokePermits"], Address[] | void, void>;
20311
- //#endregion
20312
- //#region src/query/clear-credentials.d.ts
20313
- /** TanStack Query mutation factory for {@link Permits.clear}. */
20314
- declare function clearCredentialsMutationOptions(sdk: ZamaSDK): MutationFactoryOptions<readonly ["zama.clearCredentials"], void, void>;
20315
- //#endregion
20316
- //#region src/query/delegate-decryption.d.ts
20317
- /** Variables for {@link delegateDecryptionMutationOptions}. */
20318
- interface DelegateDecryptionParams {
20319
- delegateAddress: Address;
20320
- expirationDate?: Date;
20321
- }
20322
- declare function delegateDecryptionMutationOptions(sdk: ZamaSDK, contractAddress: Address): MutationFactoryOptions<readonly ["zama.delegateDecryption", Address], DelegateDecryptionParams, TransactionResult>;
20323
- //#endregion
20324
- //#region src/query/decrypt-balance-as.d.ts
20325
- /** Variables for {@link decryptBalanceAsMutationOptions}. */
20326
- interface DecryptBalanceAsParams {
20327
- delegatorAddress: Address;
20328
- accountAddress?: Address;
20329
- }
20330
- declare function decryptBalanceAsMutationOptions(token: Token): MutationFactoryOptions<readonly ["zama.decryptBalanceAs", Address], DecryptBalanceAsParams, bigint>;
20331
- //#endregion
20332
- //#region src/query/batch-decrypt-balances-as.d.ts
20333
- /** Variables for {@link batchDecryptBalancesAsMutationOptions}. */
20334
- type BatchDecryptBalancesAsParams = BatchDecryptAsOptions;
20335
- declare function batchDecryptBalancesAsMutationOptions(tokens: Token[]): MutationFactoryOptions<readonly ["zama.batchDecryptBalancesAs", ...Address[]], BatchDecryptBalancesAsParams, Map<Address, bigint>>;
20336
- //#endregion
20337
- //#region src/query/revoke-delegation.d.ts
20338
- /** Variables for {@link revokeDelegationMutationOptions}. */
20339
- interface RevokeDelegationParams {
20340
- delegateAddress: Address;
20341
- }
20342
- declare function revokeDelegationMutationOptions(sdk: ZamaSDK, contractAddress: Address): MutationFactoryOptions<readonly ["zama.revokeDelegation", Address], RevokeDelegationParams, TransactionResult>;
20343
- //#endregion
20344
- //#region src/query/delegation-status.d.ts
20345
- interface DelegationStatusData {
20346
- isActive: boolean;
20347
- expiryTimestamp: bigint;
20348
- }
20349
- interface DelegationStatusQueryConfig {
20350
- contractAddress: Address | undefined;
20351
- delegatorAddress?: Address;
20352
- delegateAddress?: Address;
20353
- query?: Record<string, unknown>;
20354
- }
20355
- declare function delegationStatusQueryOptions(sdk: ZamaSDK, config: DelegationStatusQueryConfig): QueryFactoryOptions<DelegationStatusData, Error, DelegationStatusData, ReturnType<typeof zamaQueryKeys.delegationStatus.scope>>;
20356
- //#endregion
20357
- //#region src/credentials/credential-service.d.ts
20358
- /** Configuration for {@link CredentialService}. TTLs are pre-validated by the caller. */
20359
- interface CredentialServiceConfig {
20360
- router: ChainRouter;
20361
- signer: GenericSigner;
20362
- /** Transport key pair lifetime in seconds. Pre-validated. */
20363
- transportKeyPairTTL: number;
20364
- /** Permit lifetime in days. Pre-validated. */
20365
- permitTTL: number;
20366
- /** Backing storage for transport key pairs (and permits if `permitStorage` is omitted). */
20367
- storage: GenericStorage;
20368
- /** Optional dedicated storage for permits; defaults to `storage`. */
20369
- permitStorage?: GenericStorage;
20370
- /** SDK-wide logger for credential-path diagnostics. */
20371
- logger: GenericLogger;
20372
- }
20373
- /**
20374
- * Single facade coordinating the keypair vault and the permission store.
20375
- *
20376
- * `CredentialService` is the only credentials object held by `ZamaSDK`. It accepts identity
20377
- * transitions via `handleWalletAccountChange`.
20378
- */
20379
- declare class CredentialService {
20380
- #private;
20381
- constructor(config: CredentialServiceConfig);
20135
+ confidentialTransferFromAndCall(from: Address, to: Address, amount: bigint, data: Hex, callbacks?: TransferCallbacks): Promise<TransactionResult>;
20382
20136
  /**
20383
- * Resolve a keypair and permissions covering `contracts`, minimizing wallet
20384
- * prompts by reusing or widening existing permits where possible. Empty
20385
- * `contracts` warms the keypair without prompting.
20137
+ * Set operator approval for the confidential token.
20138
+ * Defaults to 1 hour from now if `until` is not specified.
20386
20139
  *
20387
- * @returns The resolved keypair and permits covering the requested contracts.
20388
- * @throws if the user rejects a wallet signature prompt. {@link SigningRejectedError}
20389
- * @throws if signing fails for any other reason. {@link SigningFailedError}
20390
- */
20391
- grantPermit(contracts: readonly Address[], delegator?: Address): Promise<SerializedTransportKeyPairWithPermissions>;
20392
- /**
20393
- * Pure store lookup: are stored permits sufficient to cover `contracts`? No wallet prompt.
20140
+ * @param operator - The address to set as an operator.
20141
+ * @param until - Optional Unix timestamp for approval expiry. Defaults to now + 1 hour.
20142
+ * @returns The transaction hash and mined receipt.
20394
20143
  *
20395
- * @returns `true` if cached permits cover all requested contracts (vacuously
20396
- * true for an empty list); `false` if no keypair exists or coverage is
20397
- * incomplete.
20144
+ * @example
20145
+ * ```ts
20146
+ * const txHash = await token.setOperator("0xOperator");
20147
+ * ```
20398
20148
  */
20399
- hasPermit(contracts: readonly Address[], delegator?: Address): Promise<boolean>;
20149
+ setOperator(operator: Address, until?: number): Promise<TransactionResult>;
20400
20150
  /**
20401
- * Wipe FHE permits for the current signer.
20151
+ * Check if a spender is an approved operator for a given holder.
20402
20152
  *
20403
- * - With no argument: every permit referencing this signer is removed across
20404
- * all chains and delegators. The keypair survives — use
20405
- * {@link clearCredentials} to also wipe the keypair.
20406
- * - With a contract list: every signed permit in the direct-decrypt scope
20407
- * (current chain) whose immutable payload touches any listed address is
20408
- * removed. Delegated permits are not touched in this mode.
20153
+ * @param holder - The token holder address.
20154
+ * @param spender - The address to check operator approval for.
20155
+ * @returns `true` if the spender is an approved operator for the holder.
20409
20156
  *
20410
- * @throws if reading the signer address fails. {@link SigningFailedError}
20157
+ * @example
20158
+ * ```ts
20159
+ * if (await token.isOperator("0xHolder", "0xSpender")) {
20160
+ * // spender can call transferFrom on behalf of holder
20161
+ * }
20162
+ * ```
20411
20163
  */
20412
- revokePermits(contracts?: readonly Address[]): Promise<void>;
20164
+ isOperator(holder: Address, spender: Address): Promise<boolean>;
20413
20165
  /**
20414
- * Wipe the keypair for the current signer and cascade-delete every
20415
- * permission referencing it across all chains and delegators.
20166
+ * Read the on-chain encrypted balance for a given owner.
20416
20167
  *
20417
- * @throws if reading the signer address fails. {@link SigningFailedError}
20168
+ * @internal
20418
20169
  */
20419
- clearCredentials(): Promise<void>;
20170
+ protected readConfidentialBalanceOf(owner: Address): Promise<EncryptedValue>;
20420
20171
  /**
20421
- * Warm the signer transport key pair cache for a known address.
20172
+ * Pre-flight check: decrypt the confidential balance and compare against the
20173
+ * requested amount. If credentials are cached the decrypt happens silently;
20174
+ * if not, throws {@link BalanceCheckUnavailableError} instead of triggering
20175
+ * a surprise EIP-712 popup.
20422
20176
  *
20423
- * Best-effort prefetch primitive: correctness still comes from `grantPermit`,
20424
- * which lazily creates the transport key pair when needed. Errors (storage failure,
20425
- * relayer 4xx, missing Worker in SSR) are **not** swallowed here — the caller
20426
- * decides whether to log, ignore, or surface them.
20177
+ * @internal
20427
20178
  */
20428
- warmTransportKeyPair(address: Address): Promise<void>;
20179
+ protected assertConfidentialBalance(amount: bigint): Promise<void>;
20429
20180
  /**
20430
- * Apply a wallet account transition.
20181
+ * Emit a token-scoped event through the owning {@link ZamaSDK} so that
20182
+ * subscribers see a unified stream.
20431
20183
  *
20432
- * Address change clears persisted credentials for the previous account.
20433
- * Chain-only changes keep credentials intact because permits are chain-scoped
20434
- * already and stale decrypt plaintext is cleared by `ZamaSDK`.
20184
+ * @internal
20435
20185
  */
20436
- handleWalletAccountChange(prev?: {
20437
- address: Address;
20438
- }, next?: {
20439
- address: Address;
20440
- }): Promise<void>;
20441
- }
20442
- //#endregion
20443
- //#region src/services/caching-service.d.ts
20444
- /**
20445
- * Storage-backed cache for decrypted FHE plaintext values.
20446
- *
20447
- * Each entry is keyed by `(requester, contractAddress, handle)` so different
20448
- * signers cannot read each other's cached decryptions.
20449
- */
20450
- declare class CachingService {
20451
- #private;
20452
- constructor(storage: GenericStorage, logger: GenericLogger);
20453
- get(requester: Address, contractAddress: Address, encryptedValue: EncryptedValue): Promise<ClearValue | null>;
20454
- set(requester: Address, contractAddress: Address, encryptedValue: EncryptedValue, value: ClearValue): Promise<void>;
20455
- delete(requester: Address, contractAddress: Address, encryptedValue: EncryptedValue): Promise<void>;
20456
- clearForRequester(requester: Address): Promise<void>;
20457
- clearAll(): Promise<void>;
20458
- }
20459
- //#endregion
20460
- //#region src/services/delegation-service.d.ts
20461
- declare class DelegationService {
20462
- #private;
20463
- constructor({ provider, router, emitEvent, logger }: {
20464
- provider: GenericProvider;
20465
- router: ChainRouter;
20466
- logger: GenericLogger;
20467
- emitEvent?: (input: ZamaSDKEventInput, tokenAddress?: Address) => void;
20468
- });
20469
- delegateDecryption(signer: GenericSigner, { contractAddress, delegateAddress, delegatorAddress, expirationDate }: {
20470
- contractAddress: Address;
20471
- delegateAddress: Address;
20472
- delegatorAddress: Address;
20473
- expirationDate?: Date;
20474
- }): Promise<TransactionResult>;
20475
- revokeDelegation(signer: GenericSigner, { contractAddress, delegateAddress, delegatorAddress }: {
20476
- contractAddress: Address;
20477
- delegateAddress: Address;
20478
- delegatorAddress: Address;
20479
- }): Promise<TransactionResult>;
20480
- isDelegated(params: {
20481
- contractAddress: Address;
20482
- delegatorAddress: Address;
20483
- delegateAddress: Address;
20484
- }): Promise<boolean>;
20485
- getDelegationExpiry({ contractAddress, delegatorAddress, delegateAddress }: {
20486
- contractAddress: Address;
20487
- delegatorAddress: Address;
20488
- delegateAddress: Address;
20489
- }): Promise<bigint>;
20490
- findInactiveDelegations(contractAddresses: readonly Address[], delegatorAddress: Address, delegateAddress: Address): Promise<Map<Address, DelegationNotFoundError | DelegationExpiredError>>;
20491
- assertDelegationActive(contractAddress: Address, delegatorAddress: Address, delegateAddress: Address): Promise<void>;
20492
- }
20493
- //#endregion
20494
- //#region src/services/decryption-service.d.ts
20495
- /** Options shared by the delegated-decrypt entry points. */
20496
- interface DelegatedDecryptOptions {
20186
+ protected emit(input: ZamaSDKEventInput): void;
20497
20187
  /**
20498
- * Ride out the gateway propagation window: when a just-granted delegation
20499
- * has not yet synced, the delegated decrypt is retried (bounded, ~30s) until
20500
- * it lands instead of throwing {@link DelegationNotPropagatedError}. Defaults
20501
- * to `true`. Pass `false` to fail fast on the first not-propagated response.
20188
+ * Submit a token-scoped write transaction through the shared SDK transaction
20189
+ * pipeline. Callers keep pre-flight and operation-specific work local.
20190
+ *
20191
+ * @internal
20502
20192
  */
20503
- waitForPropagation?: boolean;
20504
- }
20505
- interface BatchDecryptItem {
20506
- encryptedValue: EncryptedValue;
20507
- contractAddress: Address;
20508
- value?: ClearValue;
20509
- error?: ZamaError;
20510
- }
20511
- interface BatchDecryptResult {
20512
- items: BatchDecryptItem[];
20513
- }
20514
- declare class DecryptionService {
20515
- #private;
20516
- constructor({ cache, credentialService, delegationService, router, emitEvent }: {
20517
- cache: CachingService;
20518
- credentialService: CredentialService;
20519
- delegationService: DelegationService;
20520
- router: ChainRouter;
20521
- emitEvent: (input: ZamaSDKEventInput) => void;
20522
- });
20523
- decryptValues(handles: EncryptedInput[], signerAddress: Address, opts?: Pick<FhevmRelayerOptions, "signal" | "timeout">): Promise<Record<EncryptedValue, ClearValue>>;
20524
- delegatedDecryptValues(encryptedInputs: EncryptedInput[], delegatorAddress: Address, delegateAddress: Address, accountAddress: Address, opts?: DelegatedDecryptOptions): Promise<Record<EncryptedValue, ClearValue>>;
20525
- delegatedBatchDecryptHandlesAs({ encryptedInputs, delegatorAddress, delegateAddress, accountAddress, maxConcurrency, waitForPropagation }: {
20526
- encryptedInputs: EncryptedInput[];
20527
- delegatorAddress: Address;
20528
- delegateAddress: Address;
20529
- accountAddress: Address;
20530
- maxConcurrency?: number;
20531
- waitForPropagation?: boolean;
20532
- }): Promise<BatchDecryptResult>;
20193
+ protected submitTransaction(params: {
20194
+ operation: TransactionOperation;
20195
+ config: WriteContractConfig;
20196
+ onSubmitted?: (txHash: Hex) => void;
20197
+ }): Promise<TransactionResult>;
20198
+ /** Verify all tokens share the same SDK instance and return it. */
20199
+ private static assertSameSdk;
20533
20200
  }
20534
20201
  //#endregion
20535
- //#region src/namespaces/decryption.d.ts
20202
+ //#region src/token/wrapped-token.d.ts
20536
20203
  /**
20537
- * Public namespace for FHE decryption — the canonical way to decrypt.
20538
- *
20539
- * Exposed as `sdk.decryption`. Prefer these methods over the low-level
20540
- * `sdk.relayer.decryptValues` / `decryptPublicValues`: they
20541
- * assemble the credential bundle (transport key pair, EIP-712 permit) for you,
20542
- * cache results, and wrap relayer errors. Reach for `sdk.relayer.*` only when
20543
- * you must control credential assembly by hand.
20544
- *
20545
- * Owns the SDK-level guards (signer requirement on
20546
- * `decryptValues` and `delegatedDecryptValues`, empty-array
20547
- * short-circuit on `decryptPublicValues`, relayer error wrapping) and delegates the
20548
- * actual work to the internal {@link DecryptionService} or the relayer directly for
20549
- * `decryptPublicValues`.
20204
+ * Confidential ERC-20 wrapper (ERC-7984 ERC20Wrapper).
20550
20205
  *
20551
- * **Mixed signer requirement:** `decryptValues` and
20552
- * `delegatedDecryptValues` need a configured signer; `decryptPublicValues`
20553
- * does not. Each method documents its requirement in its JSDoc.
20206
+ * Extends {@link Token} with wrapper-specific operations:
20207
+ * - `shield` / `unshield` — convert between the underlying ERC-20 and confidential balance
20208
+ * - `unwrap` / `unwrapAll` / `finalizeUnwrap` — low-level two-phase primitives
20209
+ * - `underlying` / `allowance` — wrapper reads
20554
20210
  *
20555
- * **Request chunking:** decrypt requests are split internally to stay under
20556
- * the relayer's 2048-cleartext-bit per-request budget — callers never need to
20557
- * size batches themselves.
20211
+ * `WrappedToken.address` is the wrapper contract address itself — the wrapper
20212
+ * IS the confidential token.
20558
20213
  */
20559
- declare class Decryption {
20214
+ declare class WrappedToken extends Token {
20560
20215
  #private;
20561
- /** @internal */
20562
- constructor(opts: {
20563
- signer: GenericSigner | undefined;
20564
- provider: GenericProvider;
20565
- router: ChainRouter;
20566
- decryptionService: DecryptionService | undefined;
20567
- });
20568
20216
  /**
20569
- * Decrypt one or more FHE encrypted values. Results are cached — repeated calls
20570
- * for the same encrypted value skip the relayer round-trip.
20217
+ * Read the underlying ERC-20 token address from the wrapper contract.
20218
+ *
20219
+ * @returns The underlying ERC-20 token address.
20220
+ */
20221
+ underlying(): Promise<Address>;
20222
+ /**
20223
+ * Check whether the underlying ERC-20 supports ERC-1363 (payable token).
20224
+ * Result is cached per WrappedToken instance (negative results included):
20225
+ * once we know an underlying does not support ERC-1363, subsequent shields
20226
+ * go straight to the `approve` + `wrap` path without re-probing.
20227
+ */
20228
+ isPayable(): Promise<boolean>;
20229
+ /**
20230
+ * Read the ERC-20 allowance granted by `owner` to this wrapper for the
20231
+ * underlying token.
20232
+ *
20233
+ * @param owner - The owner address whose allowance to read.
20234
+ * @returns The current allowance as a bigint.
20235
+ */
20236
+ allowance(owner: Address): Promise<bigint>;
20237
+ /**
20238
+ * Shield public ERC-20 tokens into confidential tokens.
20239
+ *
20240
+ * The execution path is decided automatically by ERC-165 introspection on
20241
+ * the underlying ERC-20:
20242
+ * - **`transferAndCall`** (single tx): when the underlying supports
20243
+ * ERC-1363, no approval is required — the wrapper's `onTransferReceived`
20244
+ * callback mints confidential tokens directly. `approvalStrategy` is
20245
+ * **ignored** on this path. See {@link ShieldPath}.
20246
+ * - **`approveAndWrap`** (two-tx fallback): otherwise, an `approve` is
20247
+ * followed by a `wrap`. Approval is controlled by `approvalStrategy`
20248
+ * (`"exact"` by default, `"max"` for unlimited, `"skip"` to opt out).
20249
+ *
20250
+ * The ERC-20 balance is validated before submitting (public read, no
20251
+ * signing required) so the call works for all wallet types, including
20252
+ * smart wallets.
20253
+ *
20254
+ * @param amount - The plaintext amount to shield.
20255
+ * @param options - Optional: `approvalStrategy`, `to`, callbacks.
20256
+ * @returns The transaction hash and mined receipt.
20257
+ * @throws if signer and provider are on different chains. {@link ChainMismatchError}
20258
+ * @throws if the ERC-20 balance is less than `amount`. {@link InsufficientERC20BalanceError}
20259
+ * @throws if the ERC-20 approval or shield transaction reverts. {@link TransactionRevertedError}
20260
+ *
20261
+ * @example
20262
+ * ```ts
20263
+ * const txHash = await wrappedToken.shield(1000n);
20264
+ * ```
20265
+ */
20266
+ shield(amount: bigint, options?: ShieldOptions): Promise<TransactionResult>;
20267
+ /**
20268
+ * Approve this wrapper contract to spend the underlying ERC-20.
20269
+ * Defaults to max uint256. Resets to zero first if there's an existing
20270
+ * non-zero allowance (required by tokens like USDT).
20571
20271
  *
20572
- * Zero encrypted values are mapped to `0n` without hitting the relayer.
20573
- * Events (`DecryptStart/End/Error`) are emitted uniformly.
20574
- * Relayer errors are wrapped into typed SDK errors.
20272
+ * @param amount - Optional approval amount. Defaults to max uint256.
20273
+ * @returns The transaction hash and mined receipt.
20575
20274
  *
20576
- * @param encryptedInput - Encrypted values to decrypt, each paired with its contract address.
20577
- * @param options - Per-call `signal` and `timeout` forwarded to the relayer round-trip.
20578
- * @returns A record mapping each encrypted value to its decrypted clear-text value.
20579
- * @throws if no signer is configured. {@link SignerNotConfiguredError}
20580
- * @throws if signer and provider are on different chains. {@link ChainMismatchError}
20275
+ * @example
20276
+ * ```ts
20277
+ * await wrappedToken.approveUnderlying(); // max approval
20278
+ * await wrappedToken.approveUnderlying(1000n); // exact amount
20279
+ * ```
20280
+ */
20281
+ approveUnderlying(amount?: bigint): Promise<TransactionResult>;
20282
+ /**
20283
+ * Unshield a specific amount and finalize in one call.
20284
+ * Orchestrates: unshield → wait for receipt → parse event → finalize.
20285
+ *
20286
+ * By default, the SDK validates the confidential balance before submitting.
20287
+ * Set `skipBalanceCheck: true` to bypass this validation (e.g. for smart wallets).
20288
+ *
20289
+ * @param amount - The plaintext amount to unshield.
20290
+ * @param options - Optional: `skipBalanceCheck` (default `false`), callbacks.
20291
+ * @returns The finalize transaction hash and mined receipt.
20581
20292
  *
20582
20293
  * @example
20583
20294
  * ```ts
20584
- * const values = await sdk.decryption.decryptValues([
20585
- * { encryptedValue: balance, contractAddress: cUSDT },
20586
- * ]);
20587
- * console.log(values[balance]); // 1000n
20295
+ * const txHash = await wrappedToken.unshield(500n);
20588
20296
  * ```
20589
20297
  */
20590
- decryptValues(encryptedInput: EncryptedInput[], options?: Pick<FhevmRelayerOptions, "signal" | "timeout">): Promise<Record<EncryptedValue, ClearValue>>;
20298
+ unshield(amount: bigint, options?: UnshieldOptions): Promise<TransactionResult>;
20591
20299
  /**
20592
- * Decrypt one or more FHE encrypted values using delegated credentials.
20300
+ * Unshield the entire balance and finalize in one call.
20301
+ * Orchestrates: unshieldAll → wait for receipt → parse event → finalize.
20593
20302
  *
20594
- * Mirrors {@link decryptValues} with delegated credentials — same caching and
20595
- * zero-value short-circuit. Before reading from cache or calling the relayer,
20596
- * every non-zero encrypted value's contract must have an active delegation from the
20597
- * delegator to the connected signer; missing or expired delegations fail fast.
20303
+ * @param callbacks - Optional progress callbacks for each phase.
20304
+ * @returns The finalize transaction hash and mined receipt.
20305
+ * @throws if the balance is zero. {@link DecryptionFailedError}
20598
20306
  *
20599
- * @param encryptedInputs - FHE encrypted values paired with their contract addresses.
20600
- * @param delegatorAddress - The address that granted delegation rights.
20601
- * @param accountAddress - Address used as the cache key's "requester"
20602
- * dimension. Defaults to `delegatorAddress`. Pass the actual account address
20603
- * when decrypting on behalf of someone whose balance is stored under a
20604
- * different address (e.g. `decryptBalanceAs` with an explicit `accountAddress`).
20605
- * @param options - Delegated-decrypt options. By default the call rides out the
20606
- * gateway propagation window ({@link DelegatedDecryptOptions.waitForPropagation});
20607
- * pass `{ waitForPropagation: false }` to fail fast instead.
20608
- * @returns Map of encrypted value → clear-text value.
20307
+ * @example
20308
+ * ```ts
20309
+ * const txHash = await wrappedToken.unshieldAll();
20310
+ * ```
20311
+ */
20312
+ unshieldAll(callbacks?: UnshieldCallbacks): Promise<TransactionResult>;
20313
+ /**
20314
+ * Resume an in-progress unshield from an existing unwrap tx hash.
20315
+ * Useful when the user already submitted the unwrap but the finalize step
20316
+ * was interrupted (e.g. page reload, network error).
20317
+ *
20318
+ * @param unwrapTxHash - The transaction hash of the previously submitted unwrap.
20319
+ * @param callbacks - Optional progress callbacks.
20320
+ * @returns The finalize transaction hash and mined receipt.
20609
20321
  *
20610
20322
  * @example
20611
20323
  * ```ts
20612
- * const values = await sdk.decryption.delegatedDecryptValues([
20613
- * { encryptedValue: balance, contractAddress: tokenAddr },
20614
- * ], delegatorAddr);
20615
- * console.log(values[balance]); // 1000n
20324
+ * const txHash = await wrappedToken.resumeUnshield(previousUnwrapTxHash);
20616
20325
  * ```
20617
20326
  */
20618
- delegatedDecryptValues(encryptedInputs: EncryptedInput[], delegatorAddress: Address, accountAddress?: Address, options?: DelegatedDecryptOptions): Promise<Record<EncryptedValue, ClearValue>>;
20327
+ resumeUnshield(unwrapTxHash: Hex, callbacks?: UnshieldCallbacks): Promise<TransactionResult>;
20619
20328
  /**
20620
- * Publicly decrypt one or more FHE encrypted values.
20329
+ * Return the unwrap tx hash of an unshield that was interrupted between its
20330
+ * two phases, or `null` if none is pending for this wrapper.
20621
20331
  *
20622
- * Signer-independent: works without a configured signer.
20623
- * Returns the decryption proof alongside the clear-text values so callers
20624
- * can submit on-chain finalization transactions (e.g. `finalizeUnwrap`).
20332
+ * The SDK persists this automatically when {@link unshield}/{@link unshieldAll}
20333
+ * submit phase 1, and clears it once phase 2 finalizes. Use the returned hash
20334
+ * to surface a "resume" affordance, then pass it to {@link resumeUnshield}.
20335
+ * Resuming is intentionally caller-driven — auto-resuming on load would fire a
20336
+ * wallet transaction unprompted.
20625
20337
  *
20626
- * @param encryptedValues - FHE encrypted values to decrypt publicly.
20627
- * @param options - Per-call `signal` and `timeout` forwarded to the relayer round-trip.
20628
- * @returns Clear-text values, ABI-encoded values, and the decryption proof.
20338
+ * @returns The pending unwrap tx hash, or `null`.
20629
20339
  *
20630
20340
  * @example
20631
20341
  * ```ts
20632
- * const { clearValues, decryptionProof, abiEncodedClearValues } =
20633
- * await sdk.decryption.decryptPublicValues([encryptedValue]);
20342
+ * const unwrapTxHash = await wrappedToken.getPendingUnshield();
20343
+ * if (unwrapTxHash) await wrappedToken.resumeUnshield(unwrapTxHash);
20634
20344
  * ```
20635
20345
  */
20636
- decryptPublicValues(encryptedValues: EncryptedValue[], options?: Pick<FhevmRelayerOptions, "signal" | "timeout">): Promise<DecryptPublicValuesResult>;
20346
+ getPendingUnshield(): Promise<Hex | null>;
20637
20347
  /**
20638
- * Batch-decrypt delegated encrypted values with per-entry error isolation.
20348
+ * Request an unwrap for a specific amount. Encrypts the amount first.
20349
+ * Pass the result's `unwrapRequestId` to {@link finalizeUnwrap} once the
20350
+ * request is processed on-chain.
20639
20351
  *
20640
- * Attempts a single batch request first. If the batch fails with a non-fatal
20641
- * error (e.g. one entry is invalid), falls back to per-entry decryption so
20642
- * healthy entries still resolve. Each item in the result carries either a
20643
- * decrypted value or an error — callers decide how to surface partial failures.
20352
+ * @param amount - The plaintext amount to unwrap (encrypted automatically).
20353
+ * @returns The tx hash, mined receipt, and the `unwrapRequestId` for `finalizeUnwrap`.
20644
20354
  *
20645
- * @param encryptedInputs - FHE encrypted values paired with their contract addresses.
20646
- * @param delegatorAddress - The address that granted delegation rights.
20647
- * @param accountAddress - The account on whose behalf decryption is performed. Defaults to `delegatorAddress`.
20648
- * @param maxConcurrency - Maximum parallel decrypt calls during per-entry fallback.
20649
- * @param waitForPropagation - Ride out the gateway propagation window on the
20650
- * initial batch attempt (default `true`). See {@link DelegatedDecryptOptions.waitForPropagation}.
20651
- * @returns Per-entry results, each with a value or an error.
20652
- * @throws if no signer is configured. {@link SignerNotConfiguredError}
20653
- * @throws if signer and provider are on different chains. {@link ChainMismatchError}
20355
+ * @example
20356
+ * ```ts
20357
+ * const result = await wrappedToken.unwrap(500n);
20358
+ * await wrappedToken.finalizeUnwrap(result.unwrapRequestId);
20359
+ * ```
20360
+ */
20361
+ unwrap(amount: bigint): Promise<UnwrapResult>;
20362
+ /**
20363
+ * Request an unwrap for the entire confidential balance.
20364
+ * Uses the on-chain encrypted balance directly (no encryption needed).
20365
+ * Throws if the balance is zero.
20366
+ *
20367
+ * @returns The tx hash, mined receipt, and the `unwrapRequestId` for `finalizeUnwrap`.
20368
+ * @throws if the balance is zero. {@link DecryptionFailedError}
20654
20369
  *
20655
20370
  * @example
20656
20371
  * ```ts
20657
- * const result = await sdk.decryption.delegatedBatchDecryptValues({
20658
- * encryptedInputs: [
20659
- * { encryptedValue: encryptedValue1, contractAddress: tokenA },
20660
- * { encryptedValue: encryptedValue2, contractAddress: tokenB },
20661
- * ],
20662
- * delegatorAddress: "0xDelegator",
20663
- * maxConcurrency: 5,
20664
- * });
20665
- * for (const item of result.items) {
20666
- * if (item.error) console.error(item.encryptedValue, item.error);
20667
- * else console.log(item.encryptedValue, item.value);
20668
- * }
20372
+ * const result = await wrappedToken.unwrapAll();
20373
+ * await wrappedToken.finalizeUnwrap(result.unwrapRequestId);
20669
20374
  * ```
20670
20375
  */
20671
- delegatedBatchDecryptValues({ encryptedInputs, delegatorAddress, accountAddress, maxConcurrency, waitForPropagation }: {
20672
- encryptedInputs: EncryptedInput[];
20673
- delegatorAddress: Address;
20674
- accountAddress?: Address;
20675
- maxConcurrency?: number;
20676
- } & DelegatedDecryptOptions): Promise<BatchDecryptResult>;
20376
+ unwrapAll(): Promise<UnwrapResult>;
20377
+ /**
20378
+ * Complete an unwrap by fetching the public decryption proof and finalizing.
20379
+ * Call this once the unwrap request has been processed on-chain.
20380
+ *
20381
+ * @param unwrapRequestId - The `unwrapRequestId` from an {@link UnwrapResult}
20382
+ * (`result.unwrapRequestId`) returned by {@link unwrap} / {@link unwrapAll},
20383
+ * or one decoded from an `UnwrapRequested` event (e.g. when finalizing
20384
+ * across sessions).
20385
+ * @returns The transaction hash and mined receipt.
20386
+ *
20387
+ * @example
20388
+ * ```ts
20389
+ * const { unwrapRequestId } = await wrappedToken.unwrap(500n);
20390
+ * await wrappedToken.finalizeUnwrap(unwrapRequestId);
20391
+ * ```
20392
+ */
20393
+ finalizeUnwrap(unwrapRequestId: EncryptedValue): Promise<TransactionResult>;
20677
20394
  }
20678
20395
  //#endregion
20679
- //#region src/namespaces/delegations.d.ts
20396
+ //#region src/wrappers-registry.d.ts
20680
20397
  /**
20681
- * Public namespace for on-chain decryption-delegation management.
20398
+ * Default wrappers registry addresses for known chains.
20399
+ * Only includes chains where a registry is deployed (excludes Hardhat).
20682
20400
  *
20683
- * Exposed as `sdk.delegations`. Owns the SDK-level guards (signer requirement, chain
20684
- * alignment, delegator address resolution from the wallet account) and delegates the
20685
- * actual work to the internal {@link DelegationService}.
20401
+ * @deprecated Read `registryAddress` from the chain presets instead (e.g.
20402
+ * `sepolia.registryAddress`). Will be removed in the next major version.
20403
+ */
20404
+ declare const DefaultRegistryAddresses: Record<number, Address>;
20405
+ /** Configuration for {@link WrappersRegistry}. */
20406
+ interface WrappersRegistryConfig {
20407
+ /** Read-only chain provider used for every registry lookup. */
20408
+ provider: GenericProvider;
20409
+ /**
20410
+ * Per-chain registry address overrides, merged on top of
20411
+ * {@link DefaultRegistryAddresses}. Use this to supply a registry
20412
+ * address for custom or local chains (e.g. Hardhat).
20413
+ *
20414
+ * @example
20415
+ * ```ts
20416
+ * new WrappersRegistry({
20417
+ * provider,
20418
+ * registryAddresses: { [31337]: "0xYourHardhatRegistry" },
20419
+ * });
20420
+ * ```
20421
+ */
20422
+ registryAddresses?: Record<number, Address>;
20423
+ /**
20424
+ * How long cached registry results remain valid, in seconds.
20425
+ * Default: `86400` (24 hours).
20426
+ */
20427
+ registryTTL?: number;
20428
+ }
20429
+ /** Options for {@link WrappersRegistry.listPairs}. */
20430
+ interface ListPairsOptions {
20431
+ /** Page number (1-indexed). Default: `1`. */
20432
+ page?: number;
20433
+ /** Number of items per page. Default: `100`. */
20434
+ pageSize?: number;
20435
+ /**
20436
+ * When `true`, fetches on-chain metadata (name, symbol, decimals) for both
20437
+ * the ERC-20 and confidential token, plus totalSupply for the ERC-20.
20438
+ * Default: `false`.
20439
+ */
20440
+ metadata?: boolean;
20441
+ }
20442
+ /**
20443
+ * High-level interface for the on-chain token wrappers registry.
20686
20444
  *
20687
- * Delegation operations write to the host chain ACL; after a delegation is mined,
20688
- * the gateway syncs the ACL state via cross-chain event propagation — usually
20689
- * within ~10 blocks (a few seconds). Delegated decryption rides out that window
20690
- * with a bounded internal retry, so callers can decrypt right after granting.
20445
+ * Uses the configured {@link GenericProvider} to resolve the correct registry
20446
+ * contract address for the current chain and exposes typed read helpers for
20447
+ * every registry query. Results are cached in memory with a configurable TTL
20448
+ * (default 24 hours).
20449
+ *
20450
+ * @example
20451
+ * ```ts
20452
+ * const registry = new WrappersRegistry({ provider });
20453
+ *
20454
+ * // Paginated listing
20455
+ * const page1 = await registry.listPairs({ page: 1, pageSize: 20 });
20456
+ *
20457
+ * // Structured lookups
20458
+ * const result = await registry.getConfidentialToken(erc20Address);
20459
+ * if (result) console.log(result.confidentialTokenAddress);
20460
+ *
20461
+ * // Force refresh
20462
+ * registry.refresh();
20463
+ * ```
20691
20464
  */
20692
- declare class Delegations {
20465
+ declare class WrappersRegistry {
20693
20466
  #private;
20694
- /** @internal */
20695
- constructor(opts: {
20696
- signer: GenericSigner | undefined;
20697
- provider: GenericProvider;
20698
- delegationService: DelegationService;
20699
- });
20467
+ readonly provider: GenericProvider;
20468
+ constructor(config: WrappersRegistryConfig);
20469
+ /**
20470
+ * Synchronous lookup of the registry address for a given chain ID.
20471
+ * Returns `undefined` if no address is configured for that chain.
20472
+ */
20473
+ getAddress(chainId: number): Address | undefined;
20474
+ /**
20475
+ * Force-invalidate the in-memory cache. The next call to any read method
20476
+ * will fetch fresh data from the chain.
20477
+ */
20478
+ refresh(): void;
20700
20479
  /**
20701
- * Delegate decryption rights for a confidential contract to another address.
20702
- * Calls `ACL.delegateForUserDecryption()` on-chain.
20703
- *
20704
- * The delegation is recorded on L1 immediately, but the gateway must sync the
20705
- * ACL state via cross-chain event propagation — usually within ~10 blocks (a
20706
- * few seconds). You do not need to wait: delegated decryption rides out that
20707
- * window with a bounded internal retry, so you can decrypt right after this
20708
- * resolves.
20709
- *
20710
- * @param contractAddress - The confidential contract address to delegate on.
20711
- * @param delegateAddress - Address to delegate decryption rights to.
20712
- * @param expirationDate - Optional expiration date (defaults to permanent delegation via `uint64.max`).
20713
- * @returns The transaction hash and mined receipt.
20714
- * @throws if no signer is configured. {@link SignerNotConfiguredError}
20715
- * @throws if signer and provider are on different chains. {@link ChainMismatchError}
20716
- * @throws if `expirationDate` is less than 1 hour in the future. {@link DelegationExpirationTooSoonError}
20717
- * @throws if the delegate equals the connected wallet. {@link DelegationSelfNotAllowedError}
20718
- * @throws if the delegate equals the contract address. {@link DelegationDelegateEqualsContractError}
20719
- * @throws if the new expiry equals the current one. {@link DelegationExpiryUnchangedError}
20720
- * @throws if the delegation transaction reverts. {@link TransactionRevertedError}
20480
+ * The cache TTL in milliseconds.
20481
+ * Exposed so query option factories can set a matching `staleTime`.
20721
20482
  */
20722
- delegateDecryption({ contractAddress, delegateAddress, expirationDate }: {
20723
- contractAddress: Address;
20724
- delegateAddress: Address;
20725
- expirationDate?: Date;
20726
- }): Promise<TransactionResult>;
20483
+ get ttlMs(): number;
20727
20484
  /**
20728
- * Revoke decryption delegation for a confidential contract.
20729
- * Calls `ACL.revokeDelegationForUserDecryption()` on-chain.
20485
+ * Resolve the registry contract address for the current chain.
20730
20486
  *
20731
- * @param contractAddress - The confidential contract address to revoke delegation on.
20732
- * @param delegateAddress - Address to revoke delegation from.
20733
- * @returns The transaction hash and mined receipt.
20734
- * @throws if no signer is configured. {@link SignerNotConfiguredError}
20735
- * @throws if signer and provider are on different chains. {@link ChainMismatchError}
20736
- * @throws if no delegation exists for this (delegator, delegate, contract) tuple. {@link DelegationNotFoundError}
20737
- * @throws if the revocation transaction reverts. {@link TransactionRevertedError}
20487
+ * Priority: `registryAddresses[chainId]` \> built-in default.
20488
+ *
20489
+ * @returns The registry contract address for the connected chain.
20490
+ * @throws if no address is configured for the chain. {@link ConfigurationError}
20738
20491
  */
20739
- revokeDelegation({ contractAddress, delegateAddress }: {
20740
- contractAddress: Address;
20741
- delegateAddress: Address;
20742
- }): Promise<TransactionResult>;
20492
+ getRegistryAddress(): Promise<Address>;
20743
20493
  /**
20744
- * Check whether a delegation is active for the given contract address.
20494
+ * List token wrapper pairs with page-based pagination.
20745
20495
  *
20746
- * Signer-independent: works without a configured signer.
20496
+ * Internally maps to `getTokenConfidentialTokenPairsSlice` on-chain.
20747
20497
  *
20748
- * @param contractAddress - The confidential contract address.
20749
- * @param delegatorAddress - The address that granted the delegation.
20750
- * @param delegateAddress - The address that received delegation rights.
20751
- * @returns `true` if the delegation exists and has not expired.
20498
+ * @param options - Pagination and enrichment options.
20499
+ * @returns A {@link PaginatedResult} of pairs.
20500
+ *
20501
+ * @example
20502
+ * ```ts
20503
+ * const result = await registry.listPairs({ page: 1, pageSize: 20 });
20504
+ * console.log(`${result.total} pairs, showing page ${result.page}`);
20505
+ *
20506
+ * // With on-chain metadata
20507
+ * const withMeta = await registry.listPairs({ metadata: true, pageSize: 10 });
20508
+ * for (const pair of withMeta.items) {
20509
+ * console.log(pair.underlying.symbol, "→", pair.confidential.symbol);
20510
+ * }
20511
+ * ```
20752
20512
  */
20753
- isActive(params: {
20754
- contractAddress: Address;
20755
- delegatorAddress: Address;
20756
- delegateAddress: Address;
20757
- }): Promise<boolean>;
20513
+ listPairs(options: ListPairsOptions & {
20514
+ metadata: true;
20515
+ }): Promise<PaginatedResult<TokenWrapperPairWithMetadata>>;
20516
+ listPairs(options?: ListPairsOptions): Promise<PaginatedResult<TokenWrapperPair>>;
20758
20517
  /**
20759
- * Get the expiration timestamp of a delegation for the given contract.
20518
+ * Look up the confidential token for a given plain ERC-20 address.
20760
20519
  *
20761
- * Signer-independent: works without a configured signer.
20520
+ * @param tokenAddress - The plain ERC-20 token address.
20521
+ * @returns The lookup result, or `null` if the token has never been registered.
20522
+ * **Note:** revoked tokens (registered then invalidated) return a non-null result
20523
+ * with `isValid: false`. Check `result.isValid` explicitly rather than using
20524
+ * `if (result)` to guard against processing revoked tokens.
20762
20525
  *
20763
- * @param contractAddress - The confidential contract address.
20764
- * @param delegatorAddress - The address that granted the delegation.
20765
- * @param delegateAddress - The address that received delegation rights.
20766
- * @returns Unix timestamp as bigint. `0n` = no delegation. `2^64 - 1` = permanent.
20526
+ * @example
20527
+ * ```ts
20528
+ * const result = await registry.getConfidentialToken(usdcAddress);
20529
+ * if (result?.isValid) {
20530
+ * console.log(result.confidentialTokenAddress);
20531
+ * }
20532
+ * ```
20767
20533
  */
20768
- getExpiry(params: {
20769
- contractAddress: Address;
20770
- delegatorAddress: Address;
20771
- delegateAddress: Address;
20772
- }): Promise<bigint>;
20773
- }
20774
- //#endregion
20775
- //#region src/namespaces/permits.d.ts
20776
- /**
20777
- * Public namespace for permit and transport-key-pair management.
20778
- *
20779
- * Exposed as `sdk.permits`. Owns the SDK-level guards (chain alignment, empty-array
20780
- * short-circuit, decrypt-cache invalidation) and delegates the actual work to the
20781
- * internal {@link CredentialService}.
20782
- *
20783
- * The namespace is named `permits` because the user-facing concept is the signed-permit
20784
- * store. The transport key pair is invisible plumbing — there is no `getTransportKeyPair()`
20785
- * surfaced; the key pair exists to sign permits and is created automatically when needed.
20786
- * {@link clear} wipes both the permit store and the transport key pair (permits
20787
- * cascade-delete with the key pair).
20788
- */
20789
- declare class Permits {
20790
- #private;
20791
- /** @internal */
20792
- constructor(opts: {
20793
- signer: GenericSigner | undefined;
20794
- provider: GenericProvider;
20795
- cachingService: CachingService;
20796
- credentialService: CredentialService | undefined;
20797
- logger: GenericLogger;
20798
- });
20534
+ getConfidentialToken(tokenAddress: Address): Promise<{
20535
+ confidentialTokenAddress: Address;
20536
+ isValid: boolean;
20537
+ } | null>;
20799
20538
  /**
20800
- * Sign and store an EIP-712 permit authorising direct decryption for the
20801
- * given contract addresses.
20539
+ * Reverse lookup — find the plain ERC-20 for a given confidential token.
20802
20540
  *
20803
- * Idempotent: if a permit covering the requested set already exists, no
20804
- * wallet prompt occurs. Otherwise the SDK chunks the uncovered subset into
20805
- * groups of ≤10 contracts and prompts once per chunk; partial mid-flight
20806
- * rejection is preserved (already-signed chunks are persisted before the
20807
- * next prompt).
20541
+ * @param confidentialTokenAddress - The confidential token address.
20542
+ * @returns The lookup result, or `null` if no pair is registered.
20808
20543
  *
20809
- * @param contracts - Contract addresses to authorize.
20544
+ * @example
20545
+ * ```ts
20546
+ * const result = await registry.getUnderlyingToken(cUsdcAddress);
20547
+ * if (result) {
20548
+ * console.log(result.tokenAddress, result.isValid);
20549
+ * }
20550
+ * ```
20810
20551
  */
20811
- grantPermit(contracts: Address[]): Promise<void>;
20552
+ getUnderlyingToken(confidentialTokenAddress: Address): Promise<{
20553
+ tokenAddress: Address;
20554
+ isValid: boolean;
20555
+ } | null>;
20812
20556
  /**
20813
- * Sign and store an EIP-712 delegation permit authorising decryption on
20814
- * behalf of `delegator`. Same idempotence/chunking semantics as {@link grantPermit}.
20557
+ * Fetch all token wrapper pairs from the registry.
20815
20558
  *
20816
- * @param delegator - The address that delegated decryption rights to the connected signer.
20817
- * @param contracts - Contract addresses to authorize.
20559
+ * @returns All registered `TokenWrapperPair` entries.
20818
20560
  */
20819
- grantDelegationPermit(delegator: Address, contracts: Address[]): Promise<void>;
20561
+ getTokenPairs(): Promise<readonly TokenWrapperPair[]>;
20820
20562
  /**
20821
- * Pure store lookup: is there a permit covering `contracts`?
20822
- * No wallet prompt, no transport key pair generation. Returns `false` when no signer
20823
- * is configured.
20563
+ * Get the total number of token wrapper pairs.
20564
+ *
20565
+ * @returns The count as a bigint.
20824
20566
  */
20825
- hasPermit(contracts: Address[]): Promise<boolean>;
20567
+ getTokenPairsLength(): Promise<bigint>;
20826
20568
  /**
20827
- * Pure store lookup for a delegation permit. See {@link hasPermit}.
20569
+ * Fetch a range of token wrapper pairs (paginated by index).
20828
20570
  *
20829
- * @param delegator - The address that delegated decryption rights to the connected signer.
20830
- * @param contracts - Contract addresses to check.
20831
- * @returns `true` if cached delegation permits cover all requested contracts.
20571
+ * @param fromIndex - Start index (inclusive).
20572
+ * @param toIndex - End index (exclusive).
20573
+ * @returns The slice of `TokenWrapperPair` entries.
20832
20574
  */
20833
- hasDelegationPermit(delegator: Address, contracts: Address[]): Promise<boolean>;
20575
+ getTokenPairsSlice(fromIndex: bigint, toIndex: bigint): Promise<readonly TokenWrapperPair[]>;
20834
20576
  /**
20835
- * Best-effort transport-key-pair prefetch for the connected signer.
20836
- *
20837
- * Optional latency optimization: decrypt and permit flows remain correct
20838
- * without it because they lazily create the transport key pair when needed.
20577
+ * Fetch a single token wrapper pair by index.
20839
20578
  *
20840
- * Silent no-op when no signer is configured or no wallet account is
20841
- * available. The transport key pair is generated through the relayer dispatcher's
20842
- * currently active chain — see {@link LifecycleService}, which calls
20843
- * `switchChain` before fanning the wallet-account change out to listeners,
20844
- * so any downstream caller (including React adapters) observes the
20845
- * dispatcher on the wallet chain by the time it invokes warmup.
20579
+ * @param index - Zero-based pair index.
20580
+ * @returns The `TokenWrapperPair` at that index.
20846
20581
  */
20847
- warmTransportKeyPair(): Promise<void>;
20582
+ getTokenPair(index: bigint): Promise<TokenWrapperPair>;
20848
20583
  /**
20849
- * Wipe FHE permits for the current signer.
20584
+ * Look up the confidential token address for a given plain ERC-20 token.
20850
20585
  *
20851
- * - With no argument: every permit referencing this signer is removed across
20852
- * all chains and delegators. The transport key pair survives — use {@link clear} to
20853
- * also wipe the transport key pair.
20854
- * - With a contract list: every signed permit in the direct-decrypt scope
20855
- * (current chain) whose immutable payload touches any listed address is
20856
- * removed. Delegation permits are not touched in this mode.
20586
+ * @param tokenAddress - The plain ERC-20 token address.
20587
+ * @returns A tuple `[isValid, confidentialTokenAddress]`. `isValid` is `true` only for a
20588
+ * registered, non-revoked wrapper. The address is the zero address when no pair is registered.
20589
+ * A non-zero address with `isValid=false` means the wrapper was registered but later revoked.
20590
+ */
20591
+ getConfidentialTokenAddress(tokenAddress: Address): Promise<readonly [boolean, Address]>;
20592
+ /**
20593
+ * Reverse lookup — find the plain ERC-20 for a given confidential token.
20857
20594
  *
20858
- * @throws if no signer is configured. {@link SignerNotConfiguredError}
20595
+ * @param confidentialTokenAddress - The confidential token address.
20596
+ * @returns A tuple `[isValid, tokenAddress]`. `isValid` is `true` only for a registered,
20597
+ * non-revoked wrapper. The address is the zero address when no pair is registered.
20598
+ * A non-zero address with `isValid=false` means the wrapper was registered but later revoked.
20859
20599
  */
20860
- revokePermits(contracts?: Address[]): Promise<void>;
20600
+ getTokenAddress(confidentialTokenAddress: Address): Promise<readonly [boolean, Address]>;
20861
20601
  /**
20862
- * Wipe the transport key pair for the current signer and cascade-delete every permit
20863
- * (across chains and delegators) referencing it.
20602
+ * Check whether a confidential token is registered and valid.
20864
20603
  *
20865
- * @throws if no signer is configured. {@link SignerNotConfiguredError}
20604
+ * @param confidentialTokenAddress - The confidential token address to check.
20605
+ * @returns `true` if the token is a known valid wrapper in the registry.
20866
20606
  */
20867
- clear(): Promise<void>;
20607
+ isConfidentialTokenValid(confidentialTokenAddress: Address): Promise<boolean>;
20868
20608
  }
20869
20609
  //#endregion
20870
20610
  //#region src/zama-sdk.d.ts
@@ -21025,5 +20765,74 @@ declare class ZamaSDK {
21025
20765
  [Symbol.dispose](): void;
21026
20766
  }
21027
20767
  //#endregion
21028
- export { confidentialTransferMutationOptions as $, TokenWrapperPairWithMetadata as $n, DelegationSelfNotAllowedError as $t, encryptMutationOptions as A, tokenMetadataQueryOptions as An, isOperatorContract as Ar, SignerRequiredError as At, UnshieldParams as B, invalidateAfterUnwrap as Bn, createConfig as Br, InsufficientConfidentialBalanceError as Bt, grantPermitMutationOptions as C, TotalSupplyQueryConfig as Cn, symbolContract as Cr, BatchDecryptAsOptions as Ct, DecryptResult as D, isWrapperQueryOptions as Dn, confidentialTransferFromContract as Dr, SigningFailedError as Dt, delegatedDecryptValuesMutationOptions as E, isConfidentialQueryOptions as En, confidentialTransferContract as Er, TransactionRevertedError as Et, unwrapMutationOptions as F, invalidateAfterSetOperator as Fn, unwrapFromBalanceContract as Fr, ConfigurationError as Ft, confidentialSetOperatorMutationOptions as G, SignerQueryContext as Gn, DelegationContractIsSelfError as Gt, ApproveUnderlyingParams as H, invalidateWagmiBalanceQueries as Hn, DecryptionFailedError as Ht, ResumeUnshieldParams as I, invalidateAfterShield as In, wrapContract as Ir, RelayerRequestFailedError as It, ConfidentialTransferFromParams as J, StrippedQueryOptionKeys as Jn, DelegationExpirationTooSoonError as Jt, ConfidentialTransferFromAndCallParams as K, MutationFactoryOptions as Kn, DelegationCooldownError as Kt, resumeUnshieldMutationOptions as L, invalidateAfterTransfer as Ln, ResolvedChainRelayer as Lr, BalanceCheckUnavailableError as Lt, finalizeUnwrapMutationOptions as M, QueryFilterLike as Mn, setOperatorContract as Mr, WalletNotConnectedError as Mt, unwrapAllMutationOptions as N, QueryLike as Nn, underlyingContract as Nr, RpcRateLimitError as Nt, EncryptedInput as O, TokenMetadata as On, finalizeUnwrapContract as Or, SigningRejectedError as Ot, UnwrapParams as P, invalidateAfterApproveUnderlying as Pn, unwrapContract as Pr, NotEntitledError as Pt, ConfidentialTransferParams as Q, TokenWrapperPair as Qn, DelegationNotPropagatedError as Qt, UnshieldAllParams as R, invalidateAfterUnshield as Rn, resolveChainRelayers as Rr, BalanceErrorDetails as Rt, hasPermitQueryOptions as S, StoredTransportKeyPair as Sn, nameContract as Sr, BatchBalancesResult as St, DelegatedDecryptValuesMutationParams as T, IsConfidentialQueryConfig as Tn, confidentialTotalSupplyContract as Tr, matchZamaError as Tt, approveUnderlyingMutationOptions as U, invalidateWalletLifecycleQueries as Un, EncryptionFailedError as Ut, unshieldMutationOptions as V, invalidateBalanceQueries as Vn, InsufficientERC20BalanceError as Vt, ConfidentialSetOperatorParams as W, zamaQueryKeys as Wn, AclPausedError as Wt, ConfidentialTransferAndCallParams as X, hashFn as Xn, DelegationExpiryUnchangedError as Xt, confidentialTransferFromMutationOptions as Y, filterQueryOptions as Yn, DelegationExpiredError as Yt, confidentialTransferAndCallMutationOptions as Z, PaginatedResult as Zn, DelegationNotFoundError as Zt, DelegateDecryptionParams as _, ListPairsOptions as _n, supportsInterfaceContract as _r, ConfidentialBalancesQueryConfig as _t, BatchDecryptItem as a, ZamaErrorCode as an, getTokenPairsSliceContract as ar, TokenAddressQueryConfig as at, revokePermitsMutationOptions as b, Permission as bn, balanceOfContract as br, confidentialBalanceQueryOptions as bt, DelegationStatusData as c, ConfidentialIsOperatorQueryConfig as cn, getDelegationExpiryContract as cr, WrappersRegistryQueryConfig as ct, RevokeDelegationParams as d, pendingUnshieldQueryOptions as dn, transferAndCallContract as dr, listPairsQueryOptions as dt, InvalidTransportKeyPairError as en, getConfidentialTokenAddressContract as er, ShieldParams as et, revokeDelegationMutationOptions as f, UnderlyingAllowanceQueryConfig as fn, ERC1363_INTERFACE_ID as fr, tokenAddressQueryOptions as ft, decryptBalanceAsMutationOptions as g, DefaultRegistryAddresses as gn, isConfidentialWrapperContract as gr, tokenPairsSliceQueryOptions as gt, DecryptBalanceAsParams as h, wrapperDiscoveryQueryOptions as hn, isConfidentialTokenContract as hr, tokenPairsQueryOptions as ht, Decryption as i, ZamaError as in, getTokenPairsLengthContract as ir, ListPairsQueryConfig as it, FinalizeUnwrapParams as j, QueryClientLike as jn, rateContract as jr, WalletAccountNotReadyError as jt, decryptValuesQueryOptions as k, TokenMetadataQueryConfig as kn, inferredTotalSupplyContract as kr, SignerNotConfiguredError as kt, DelegationStatusQueryConfig as l, confidentialIsOperatorQueryOptions as ln, isHandleDelegatedContract as lr, confidentialTokenAddressQueryOptions as lt, batchDecryptBalancesAsMutationOptions as m, WrapperDiscoveryQueryConfig as mn, ERC7984_WRAPPER_INTERFACE_ID as mr, tokenPairsLengthQueryOptions as mt, Permits as n, TransportKeyPairExpiredError as nn, getTokenPairContract as nr, ConfidentialTokenAddressQueryConfig as nt, BatchDecryptResult as o, isRetryable as on, isConfidentialTokenValidContract as or, TokenPairQueryConfig as ot, BatchDecryptBalancesAsParams as p, underlyingAllowanceQueryOptions as pn, ERC7984_INTERFACE_ID as pr, tokenPairQueryOptions as pt, confidentialTransferFromAndCallMutationOptions as q, QueryFactoryOptions as qn, DelegationDelegateEqualsContractError as qt, Delegations as r, ChainMismatchError as rn, getTokenPairsContract as rr, IsConfidentialTokenValidQueryConfig as rt, DelegatedDecryptOptions as s, retryAfterSeconds as sn, delegateForUserDecryptionContract as sr, TokenPairsSliceQueryConfig as st, ZamaSDK as t, NoCiphertextError as tn, getTokenAddressContract as tr, shieldMutationOptions as tt, delegationStatusQueryOptions as u, PendingUnshieldQueryConfig as un, revokeDelegationContract as ur, isConfidentialTokenValidQueryOptions as ut, delegateDecryptionMutationOptions as v, WrappersRegistry as vn, allowanceContract as vr, confidentialBalancesQueryOptions as vt, decryptPublicValuesMutationOptions as w, totalSupplyQueryOptions as wn, confidentialBalanceOfContract as wr, Token as wt, HasPermitQueryConfig as x, SerializedTransportKeyPair as xn, decimalsContract as xr, WrappedToken as xt, clearCredentialsMutationOptions as y, WrappersRegistryConfig as yn, approveContract as yr, ConfidentialBalanceQueryConfig as yt, unshieldAllMutationOptions as z, invalidateAfterUnshieldSettled as zn, resolveStorage as zr, ERC20ReadFailedError as zt };
21029
- //# sourceMappingURL=zama-sdk-aaLl2ZlA.d.ts.map
20768
+ //#region src/utils/handles.d.ts
20769
+ declare const ZERO_ENCRYPTED_VALUE: "0x0000000000000000000000000000000000000000000000000000000000000000";
20770
+ /**
20771
+ * Check whether an encrypted value represents the zero value.
20772
+ */
20773
+ declare function isEncryptedValueZero(encryptedValue: string): boolean;
20774
+ //#endregion
20775
+ //#region src/storage/memory-storage.d.ts
20776
+ /** In-memory credential store. Credentials are lost on page reload. */
20777
+ declare class MemoryStorage implements GenericStorage {
20778
+ #private;
20779
+ get<T = unknown>(key: string): Promise<T | null>;
20780
+ set<T = unknown>(key: string, value: T): Promise<void>;
20781
+ delete(key: string): Promise<void>;
20782
+ }
20783
+ /** Default singleton for application-wide use. */
20784
+ declare const memoryStorage: MemoryStorage;
20785
+ //#endregion
20786
+ //#region src/storage/indexeddb-storage.d.ts
20787
+ /**
20788
+ * IndexedDB-backed {@link GenericStorage}.
20789
+ *
20790
+ * Stores keypair and permit objects keyed by a hashed wallet address. The
20791
+ * SDK delegates security to the storage backend — values are persisted
20792
+ * verbatim with no SDK-layer encryption.
20793
+ */
20794
+ declare class IndexedDBStorage implements GenericStorage {
20795
+ #private;
20796
+ constructor(dbName?: string, dbVersion?: number, storeName?: string);
20797
+ get<T = unknown>(key: string): Promise<T | null>;
20798
+ set<T = unknown>(key: string, value: T): Promise<void>;
20799
+ delete(key: string): Promise<void>;
20800
+ clear(): Promise<void>;
20801
+ }
20802
+ /** Default singleton for application-wide use. */
20803
+ declare const indexedDBStorage: IndexedDBStorage;
20804
+ //#endregion
20805
+ //#region src/storage/chrome-session-storage.d.ts
20806
+ /**
20807
+ * {@link GenericStorage} backed by `chrome.storage.session`.
20808
+ *
20809
+ * Use this in MV3 web extensions so the wallet signature survives
20810
+ * service worker restarts and is shared across popup, background,
20811
+ * and content script contexts.
20812
+ *
20813
+ * @example
20814
+ * ```ts
20815
+ * import { ZamaSDK, indexedDBStorage, chromeSessionStorage } from "@zama-fhe/sdk";
20816
+ * import { createConfig } from "@zama-fhe/sdk/viem";
20817
+ *
20818
+ * const config = createConfig({
20819
+ * chains: [mySepolia],
20820
+ * publicClient,
20821
+ * walletClient,
20822
+ * relayers: { [mySepolia.id]: web() },
20823
+ * storage: indexedDBStorage, // encrypted transport key pair — persistent
20824
+ * permitStorage: chromeSessionStorage, // signed permits — ephemeral
20825
+ * });
20826
+ * const sdk = new ZamaSDK(config);
20827
+ * ```
20828
+ */
20829
+ declare class ChromeSessionStorage implements GenericStorage {
20830
+ get<T = unknown>(key: string): Promise<T | null>;
20831
+ set(key: string, value: unknown): Promise<void>;
20832
+ delete(key: string): Promise<void>;
20833
+ }
20834
+ /** Default singleton for application-wide use. */
20835
+ declare const chromeSessionStorage: ChromeSessionStorage;
20836
+ //#endregion
20837
+ export { DelegationNotPropagatedError as $, rateContract as $t, SignerNotConfiguredError as A, getDelegationExpiryContract as At, ERC20ReadFailedError as B, allowanceContract as Bt, BatchDecryptItem as C, getTokenAddressContract as Ct, TransactionRevertedError as D, getTokenPairsSliceContract as Dt, matchZamaError as E, getTokenPairsLengthContract as Et, NotEntitledError as F, ERC7984_INTERFACE_ID as Ft, AclPausedError as G, symbolContract as Gt, InsufficientERC20BalanceError as H, balanceOfContract as Ht, ConfigurationError as I, ERC7984_WRAPPER_INTERFACE_ID as It, DelegationDelegateEqualsContractError as J, confidentialTransferContract as Jt, DelegationContractIsSelfError as K, confidentialBalanceOfContract as Kt, RelayerRequestFailedError as L, isConfidentialTokenContract as Lt, WalletAccountNotReadyError as M, revokeDelegationContract as Mt, WalletNotConnectedError as N, transferAndCallContract as Nt, SigningFailedError as O, isConfidentialTokenValidContract as Ot, RpcRateLimitError as P, ERC1363_INTERFACE_ID as Pt, DelegationNotFoundError as Q, isOperatorContract as Qt, BalanceCheckUnavailableError as R, isConfidentialWrapperContract as Rt, Decryption as S, getConfidentialTokenAddressContract as St, DelegatedDecryptOptions as T, getTokenPairsContract as Tt, DecryptionFailedError as U, decimalsContract as Ut, InsufficientConfidentialBalanceError as V, approveContract as Vt, EncryptionFailedError as W, nameContract as Wt, DelegationExpiredError as X, finalizeUnwrapContract as Xt, DelegationExpirationTooSoonError as Y, confidentialTransferFromContract as Yt, DelegationExpiryUnchangedError as Z, inferredTotalSupplyContract as Zt, BatchBalancesResult as _, MutationFactoryOptions as _t, IndexedDBStorage as a, ResolvedChainRelayer as an, ZamaError as at, Permits as b, TokenWrapperPair as bt, memoryStorage as c, createConfig as cn, retryAfterSeconds as ct, ZamaSDK as d, StoredTransportKeyPair as dt, setOperatorContract as en, DelegationSelfNotAllowedError as et, DefaultRegistryAddresses as f, DecryptResult as ft, WrappedToken as g, zamaQueryKeys as gt, WrappersRegistryConfig as h, SignerQueryContext as ht, chromeSessionStorage as i, wrapContract as in, ChainMismatchError as it, SignerRequiredError as j, isHandleDelegatedContract as jt, SigningRejectedError as k, delegateForUserDecryptionContract as kt, ZERO_ENCRYPTED_VALUE as l, Permission as lt, WrappersRegistry as m, decryptValuesQueryOptions as mt, Hex$1 as n, unwrapContract as nn, NoCiphertextError as nt, indexedDBStorage as o, resolveChainRelayers as on, ZamaErrorCode as ot, ListPairsOptions as p, EncryptedInput as pt, DelegationCooldownError as q, confidentialTotalSupplyContract as qt, ChromeSessionStorage as r, unwrapFromBalanceContract as rn, TransportKeyPairExpiredError as rt, MemoryStorage as s, resolveStorage as sn, isRetryable as st, Address$1 as t, underlyingContract as tn, InvalidTransportKeyPairError as tt, isEncryptedValueZero as u, SerializedTransportKeyPair as ut, BatchDecryptAsOptions as v, QueryFactoryOptions as vt, BatchDecryptResult as w, getTokenPairContract as wt, Delegations as x, TokenWrapperPairWithMetadata as xt, Token as y, PaginatedResult as yt, BalanceErrorDetails as z, supportsInterfaceContract as zt };
20838
+ //# sourceMappingURL=index-ajJV2C-B.d.ts.map