@zama-fhe/sdk 3.4.0-alpha.9 → 3.4.0

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.
Files changed (73) hide show
  1. package/dist/cjs/base-signer.cjs +1 -1
  2. package/dist/cjs/base-signer.cjs.map +1 -1
  3. package/dist/cjs/ethers/index.cjs +1 -1
  4. package/dist/cjs/ethers/index.cjs.map +1 -1
  5. package/dist/cjs/fhevm-relayer.cjs +1 -1
  6. package/dist/cjs/fhevm-relayer.cjs.map +1 -1
  7. package/dist/cjs/index.cjs +1 -1
  8. package/dist/cjs/index.cjs.map +1 -1
  9. package/dist/cjs/node/index.cjs.map +1 -1
  10. package/dist/cjs/query/index.cjs +1 -1
  11. package/dist/cjs/query/index.cjs.map +1 -1
  12. package/dist/cjs/relayer.cjs +1 -1
  13. package/dist/cjs/relayer.cjs.map +1 -1
  14. package/dist/cjs/sdk-events.cjs +2 -0
  15. package/dist/cjs/sdk-events.cjs.map +1 -0
  16. package/dist/cjs/token.cjs +1 -1
  17. package/dist/cjs/token.cjs.map +1 -1
  18. package/dist/cjs/viem/index.cjs +1 -1
  19. package/dist/cjs/viem/index.cjs.map +1 -1
  20. package/dist/esm/{base-signer-Ds8CoYy0.d.ts → base-signer-BvL-jMNO.d.ts} +15 -2
  21. package/dist/esm/base-signer-YpkEmlp2.js +2 -0
  22. package/dist/esm/base-signer-YpkEmlp2.js.map +1 -0
  23. package/dist/esm/chains/index.d.ts +1 -1
  24. package/dist/esm/cleartext/index.d.ts +2 -2
  25. package/dist/esm/cleartext/index.js +1 -1
  26. package/dist/esm/{cleartext-_RCZVPOe.d.ts → cleartext-CxlICeUh.d.ts} +2 -2
  27. package/dist/esm/{cleartext-DfX0GUj1.js → cleartext-Qqh5JohW.js} +2 -2
  28. package/dist/esm/{cleartext-DfX0GUj1.js.map → cleartext-Qqh5JohW.js.map} +1 -1
  29. package/dist/esm/ethers/index.d.ts +53 -5
  30. package/dist/esm/ethers/index.js +1 -1
  31. package/dist/esm/ethers/index.js.map +1 -1
  32. package/dist/esm/fhevm-relayer-4Zd4QkKq.js +2 -0
  33. package/dist/esm/fhevm-relayer-4Zd4QkKq.js.map +1 -0
  34. package/dist/esm/{zama-sdk-BhD6nWLL.d.ts → index-DLaQtvYu.d.ts} +1253 -1780
  35. package/dist/esm/index-DNofJMCK.d.ts +61 -0
  36. package/dist/esm/{index-doNE2KoX.d.ts → index-S6_V7aAH.d.ts} +10 -1
  37. package/dist/esm/index.d.ts +8 -79
  38. package/dist/esm/index.js +1 -1
  39. package/dist/esm/index.js.map +1 -1
  40. package/dist/esm/node/index.d.ts +5 -5
  41. package/dist/esm/node/index.js +1 -1
  42. package/dist/esm/node/index.js.map +1 -1
  43. package/dist/esm/query/index.d.ts +522 -3
  44. package/dist/esm/query/index.js +1 -1
  45. package/dist/esm/query/index.js.map +1 -1
  46. package/dist/esm/relayer-BWHOLVcG.js +2 -0
  47. package/dist/esm/relayer-BWHOLVcG.js.map +1 -0
  48. package/dist/esm/sdk-events-D68bJ5jT.js +2 -0
  49. package/dist/esm/sdk-events-D68bJ5jT.js.map +1 -0
  50. package/dist/esm/token-Bn8I7xAu.js +2 -0
  51. package/dist/esm/token-Bn8I7xAu.js.map +1 -0
  52. package/dist/esm/{types-Tk8PiPCk.d.ts → types-BEz-VgR_.d.ts} +6 -3
  53. package/dist/esm/{types-CELdIAFG.d.ts → types-CWPSTRF6.d.ts} +98 -146
  54. package/dist/esm/{types-DlSUyFe2.d.ts → types-Dr7AmEs1.d.ts} +3 -3
  55. package/dist/esm/viem/index.d.ts +34 -5
  56. package/dist/esm/viem/index.js +1 -1
  57. package/dist/esm/viem/index.js.map +1 -1
  58. package/dist/esm/web/index.d.ts +2 -2
  59. package/dist/esm/web/index.js +1 -1
  60. package/package.json +3 -3
  61. package/dist/cjs/wrappers-registry.cjs +0 -2
  62. package/dist/cjs/wrappers-registry.cjs.map +0 -1
  63. package/dist/esm/base-signer-9CqICeQ8.js +0 -2
  64. package/dist/esm/base-signer-9CqICeQ8.js.map +0 -1
  65. package/dist/esm/fhevm-relayer-Bb_-KFJA.js +0 -2
  66. package/dist/esm/fhevm-relayer-Bb_-KFJA.js.map +0 -1
  67. package/dist/esm/index-9Cn2VKDw.d.ts +0 -329
  68. package/dist/esm/relayer-DLlyoabr.js +0 -2
  69. package/dist/esm/relayer-DLlyoabr.js.map +0 -1
  70. package/dist/esm/token-BBGMtloT.js +0 -2
  71. package/dist/esm/token-BBGMtloT.js.map +0 -1
  72. package/dist/esm/wrappers-registry-B1GuTt5t.js +0 -2
  73. package/dist/esm/wrappers-registry-B1GuTt5t.js.map +0 -1
@@ -1,10 +1,10 @@
1
- import { u as FheChain } from "./index-doNE2KoX.js";
2
- import { C as ChainRouter, Ft as TransactionResult, Gt as FhevmRelayerOptions, Ht as EncryptResult, It as ClearValue, Kt as FhevmRelayerSDK, Lt as DecryptPublicValuesResult, Q as ShieldOptions, R as TransactionOperation, Ut as EncryptedValue, Vt as EncryptParams, at as TransferCallbacks, c as GenericStorage, d as WalletAccount, et as TransferOptions, i as ZamaConfig, l as GenericProvider, n as RelayerConfig, nt as UnwrapResult, o as ZamaConfigGeneric, ot as UnshieldCallbacks, p as WalletAccountListener, q as ZamaSDKEventInput, rt as WrapOptions, s as GenericLogger, tt as UnshieldOptions, u as GenericSigner, x as WriteContractConfig } from "./types-CELdIAFG.js";
3
- import "./cleartext-_RCZVPOe.js";
4
- import "./types-DlSUyFe2.js";
5
- import "./types-Tk8PiPCk.js";
6
- import "./index-9Cn2VKDw.js";
7
- import { Address, Hex } from "viem";
1
+ import { u as FheChain } from "./index-S6_V7aAH.js";
2
+ import { $ as UnshieldOptions, Bt as EncryptResult, Ft as DecryptPublicValuesResult, Nt as TransactionResult, Pt as ClearValue, Q as TransferOptions, Vt as EncryptedValue, Wt as FhevmRelayerOptions, X as ShieldOptions, c as GenericStorage, d as WalletAccount, et as UnwrapResult, i as ZamaConfig, it as UnshieldCallbacks, l as GenericProvider, o as ZamaConfigGeneric, qt as RelayerSDK, rt as TransferCallbacks, tt as WrapOptions, u as GenericSigner, zt as EncryptParams } from "./types-CWPSTRF6.js";
3
+ import "./cleartext-CxlICeUh.js";
4
+ import "./types-Dr7AmEs1.js";
5
+ import "./base-signer-BvL-jMNO.js";
6
+ import "./types-BEz-VgR_.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
@@ -33,17 +33,6 @@ import { MutationFunctionContext, QueryKey, QueryObserverOptions, skipToken } fr
33
33
  */
34
34
  declare function createConfig<const TChains extends readonly [FheChain, ...FheChain[]]>(params: ZamaConfigGeneric<TChains>): ZamaConfig;
35
35
  //#endregion
36
- //#region src/config/resolve.d.ts
37
- declare function resolveStorage(storage?: GenericStorage | undefined, permitStorage?: GenericStorage | undefined): {
38
- storage: GenericStorage;
39
- permitStorage: GenericStorage;
40
- };
41
- interface ResolvedChainRelayer {
42
- chain: FheChain;
43
- relayerConfig: RelayerConfig;
44
- }
45
- declare function resolveChainRelayers(chains: readonly FheChain[], relayers: Readonly<Record<number, RelayerConfig>>): Map<number, ResolvedChainRelayer>;
46
- //#endregion
47
36
  //#region src/contracts/confidential-wrapper.d.ts
48
37
  /**
49
38
  * Returns the contract config to read an encrypted balance.
@@ -17089,19 +17078,25 @@ declare function isHandleDelegatedContract(aclAddress: Address, delegatorAddress
17089
17078
  };
17090
17079
  //#endregion
17091
17080
  //#region src/contracts/wrappers-registry.d.ts
17081
+ /** A registered plain-token / confidential-token pairing from the wrappers registry. */
17092
17082
  interface TokenWrapperPair {
17083
+ /** Address of the underlying public ERC-20 token. */
17093
17084
  readonly tokenAddress: Address;
17085
+ /** Address of the paired confidential (ERC-7984) token. */
17094
17086
  readonly confidentialTokenAddress: Address;
17087
+ /** Whether the pairing is currently valid (registered and not revoked). */
17095
17088
  readonly isValid: boolean;
17096
17089
  }
17097
17090
  /** Extended pair with on-chain metadata for both tokens. */
17098
17091
  interface TokenWrapperPairWithMetadata extends TokenWrapperPair {
17092
+ /** On-chain metadata of the underlying public ERC-20 token. */
17099
17093
  readonly underlying: {
17100
17094
  readonly name: string;
17101
17095
  readonly symbol: string;
17102
17096
  readonly decimals: number;
17103
17097
  readonly totalSupply: bigint;
17104
17098
  };
17099
+ /** On-chain metadata of the confidential token. */
17105
17100
  readonly confidential: {
17106
17101
  readonly name: string;
17107
17102
  readonly symbol: string;
@@ -17110,9 +17105,13 @@ interface TokenWrapperPairWithMetadata extends TokenWrapperPair {
17110
17105
  }
17111
17106
  /** Paginated result set modelled after standard API pagination. */
17112
17107
  interface PaginatedResult<T> {
17108
+ /** Items on the current page. */
17113
17109
  readonly items: readonly T[];
17110
+ /** Total number of items across all pages. */
17114
17111
  readonly total: number;
17112
+ /** One-based index of the current page. */
17115
17113
  readonly page: number;
17114
+ /** Maximum number of items per page. */
17116
17115
  readonly pageSize: number;
17117
17116
  }
17118
17117
  /**
@@ -18459,50 +18458,25 @@ declare function isConfidentialTokenValidContract(registry: Address, confidentia
18459
18458
  readonly args: readonly [`0x${string}`];
18460
18459
  };
18461
18460
  //#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>;
18461
+ //#region src/query/factory-types.d.ts
18479
18462
  /**
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.
18463
+ * TanStack Query options object returned by the SDK's `*QueryOptions` factories:
18464
+ * `QueryObserverOptions` with `queryKey` and `queryFn` required and the
18465
+ * cache-internal keys (`queryHash`, `queryKeyHashFn`, `throwOnError`) removed.
18487
18466
  */
18488
- declare function hashFn(queryKey: readonly unknown[]): string;
18489
- //#endregion
18490
- //#region src/query/factory-types.d.ts
18491
- type RequiredBy<T, K extends keyof T> = Omit<T, K> & Required<Pick<T, K>>;
18492
- 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"> & {
18467
+ type QueryFactoryOptions<TQueryFnData = unknown, TError = Error, TData = TQueryFnData, TQueryKey extends QueryKey = QueryKey> = Omit<Omit<QueryObserverOptions<TQueryFnData, TError, TData, TQueryFnData, TQueryKey>, "queryKey"> & Required<Pick<QueryObserverOptions<TQueryFnData, TError, TData, TQueryFnData, TQueryKey>, "queryKey">>, "queryFn" | "queryHash" | "queryKeyHashFn" | "throwOnError"> & {
18493
18468
  queryFn: Exclude<QueryObserverOptions<TQueryFnData, TError, TData, TQueryFnData, TQueryKey>["queryFn"], typeof skipToken | undefined>;
18494
18469
  };
18470
+ /** TanStack Query mutation options object returned by the SDK's `*MutationOptions` factories. */
18495
18471
  interface MutationFactoryOptions<TMutationKey extends readonly unknown[], TVariables, TData, TOnMutateResult = unknown> {
18472
+ /** Cache key identifying the mutation. */
18496
18473
  mutationKey: TMutationKey;
18474
+ /** Runs the mutation for the given variables. */
18497
18475
  mutationFn: (variables: TVariables) => Promise<TData>;
18476
+ /** Optional callback invoked after the mutation succeeds. */
18498
18477
  onSuccess?: (data: TData, variables: TVariables, onMutateResult: TOnMutateResult, context: MutationFunctionContext) => void;
18499
18478
  }
18500
18479
  //#endregion
18501
- //#region src/query/signer-query-context.d.ts
18502
- interface SignerQueryContext {
18503
- walletAccount?: WalletAccount;
18504
- }
18505
- //#endregion
18506
18480
  //#region src/query/query-keys.d.ts
18507
18481
  /**
18508
18482
  * Canonical query-key namespace for `@zama-fhe/sdk/query`.
@@ -18706,533 +18680,171 @@ declare const zamaQueryKeys: {
18706
18680
  };
18707
18681
  };
18708
18682
  //#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 invalidateAfterWrap(queryClient: QueryClientLike, tokenAddress: Address): void;
18723
- declare function invalidateBalanceQueries(queryClient: QueryClientLike, tokenAddress: Address): void;
18724
- declare function invalidateAfterShield(queryClient: QueryClientLike, tokenAddress: Address): void;
18725
- declare function invalidateAfterUnshield(queryClient: QueryClientLike, tokenAddress: Address): void;
18726
- declare function invalidateAfterUnshieldSettled(queryClient: QueryClientLike, tokenAddress: Address): void;
18727
- declare function invalidateAfterTransfer(queryClient: QueryClientLike, tokenAddress: Address): void;
18728
- declare function invalidateAfterApproveUnderlying(queryClient: QueryClientLike, tokenAddress: Address): void;
18729
- declare function invalidateAfterSetOperator(queryClient: QueryClientLike, tokenAddress: Address): void;
18730
- declare function invalidateWagmiBalanceQueries(queryClient: QueryClientLike): void;
18731
- declare function invalidateWalletLifecycleQueries(queryClient: QueryClientLike): void;
18732
- //#endregion
18733
- //#region src/query/token-metadata.d.ts
18734
- /** ERC-20 token metadata returned by {@link tokenMetadataQueryOptions}. */
18735
- interface TokenMetadata {
18736
- name: string;
18737
- symbol: string;
18738
- decimals: number;
18739
- }
18740
- interface TokenMetadataQueryConfig {
18741
- query?: Record<string, unknown>;
18742
- }
18743
- declare function tokenMetadataQueryOptions(sdk: ZamaSDK, tokenAddress: Address, config?: TokenMetadataQueryConfig): QueryFactoryOptions<TokenMetadata, Error, TokenMetadata, ReturnType<typeof zamaQueryKeys.tokenMetadata.token>>;
18744
- //#endregion
18745
- //#region src/query/is-confidential.d.ts
18746
- interface IsConfidentialQueryConfig {
18747
- query?: Record<string, unknown>;
18683
+ //#region src/query/signer-query-context.d.ts
18684
+ /** Connected-wallet context threaded into query factories to scope cache keys and gate signer-dependent queries. */
18685
+ interface SignerQueryContext {
18686
+ /** Connected wallet account; queries that need a signer stay disabled until it is set. */
18687
+ walletAccount?: WalletAccount;
18748
18688
  }
18749
- declare function isConfidentialQueryOptions(sdk: ZamaSDK, tokenAddress: Address, config?: IsConfidentialQueryConfig): QueryFactoryOptions<boolean, Error, boolean, ReturnType<typeof zamaQueryKeys.isConfidential.token>>;
18750
- declare function isWrapperQueryOptions(sdk: ZamaSDK, tokenAddress: Address, config?: IsConfidentialQueryConfig): QueryFactoryOptions<boolean, Error, boolean, ReturnType<typeof zamaQueryKeys.isWrapper.token>>;
18751
18689
  //#endregion
18752
- //#region src/query/total-supply.d.ts
18753
- interface TotalSupplyQueryConfig {
18754
- query?: Record<string, unknown>;
18690
+ //#region src/query/user-decrypt.d.ts
18691
+ /** A single encrypted value to decrypt, paired with the contract that owns it. */
18692
+ interface EncryptedInput {
18693
+ /** Encrypted handle to decrypt. */
18694
+ encryptedValue: EncryptedValue;
18695
+ /** Address of the contract the encrypted value belongs to. */
18696
+ contractAddress: Address;
18755
18697
  }
18756
- declare function totalSupplyQueryOptions(sdk: ZamaSDK, tokenAddress: Address, config?: TotalSupplyQueryConfig): QueryFactoryOptions<bigint, Error, bigint, ReturnType<typeof zamaQueryKeys.totalSupply.token>>;
18698
+ /** Decrypted clear values keyed by encrypted handle. */
18699
+ type DecryptResult = Readonly<Record<EncryptedValue, ClearValue>>;
18700
+ /** Builds TanStack Query options for decrypting a batch of encrypted handles into their clear values. */
18701
+ declare function decryptValuesQueryOptions(sdk: ZamaSDK, encryptedInputs: EncryptedInput[], signerContext?: SignerQueryContext): QueryFactoryOptions<DecryptResult, Error, DecryptResult, ReturnType<typeof zamaQueryKeys.decryption.encryptedInputs>>;
18757
18702
  //#endregion
18758
- //#region src/schemas/primitives.d.ts
18759
- declare const checksummedTag: unique symbol;
18760
- /** An EVM address that has been put through `getAddress` (EIP-55 checksum form). */
18761
- type ChecksummedAddress = Address & {
18762
- readonly [checksummedTag]: true;
18703
+ //#region src/errors/base.d.ts
18704
+ /**
18705
+ * Typed error codes thrown by the SDK.
18706
+ * Use `error.code` or `instanceof` to programmatically handle specific failure modes.
18707
+ *
18708
+ * @example
18709
+ * ```ts
18710
+ * try {
18711
+ * await token.confidentialTransfer("0xTo", 100n);
18712
+ * } catch (e) {
18713
+ * if (e instanceof SigningRejectedError) {
18714
+ * // User rejected the wallet signature
18715
+ * }
18716
+ * }
18717
+ * ```
18718
+ */
18719
+ declare const ZamaErrorCode: {
18720
+ /** User rejected the wallet signature prompt. */
18721
+ readonly SigningRejected: "SIGNING_REJECTED";
18722
+ /** Wallet signature failed for a reason other than rejection. */
18723
+ readonly SigningFailed: "SIGNING_FAILED";
18724
+ /** FHE encryption failed. */
18725
+ readonly EncryptionFailed: "ENCRYPTION_FAILED";
18726
+ /** FHE decryption failed. */
18727
+ readonly DecryptionFailed: "DECRYPTION_FAILED";
18728
+ /** On-chain transaction reverted. */
18729
+ readonly TransactionReverted: "TRANSACTION_REVERTED";
18730
+ /** Transport key pair has expired and needs regeneration. */
18731
+ readonly TransportKeyPairExpired: "KEYPAIR_EXPIRED";
18732
+ /** Relayer rejected transport key pair (stale, expired, or malformed). */
18733
+ readonly InvalidTransportKeyPair: "INVALID_KEYPAIR";
18734
+ /** No FHE ciphertext exists for this account (never shielded). */
18735
+ readonly NoCiphertext: "NO_CIPHERTEXT";
18736
+ /** Relayer HTTP request failed. */
18737
+ readonly RelayerRequestFailed: "RELAYER_REQUEST_FAILED";
18738
+ /** The configured signer/account is not entitled (ACL) to decrypt this encrypted value. Don't retry — wait for a grant. */
18739
+ readonly NotEntitled: "NOT_ENTITLED";
18740
+ /** The consumer's RPC provider rate-limited an on-chain read (e.g. HTTP 429 / JSON-RPC -32005). Retryable. */
18741
+ readonly RpcRateLimited: "RPC_RATE_LIMITED";
18742
+ /** SDK configuration is invalid (e.g. forbidden chain ID, unsupported type). */
18743
+ readonly Configuration: "CONFIGURATION";
18744
+ /** Delegation cannot target self (delegate === msg.sender). */
18745
+ readonly DelegationSelfNotAllowed: "DELEGATION_SELF_NOT_ALLOWED";
18746
+ /** Only one delegate/revoke per (delegator, delegate, contract) per block. */
18747
+ readonly DelegationCooldown: "DELEGATION_COOLDOWN";
18748
+ /** No active delegation found for this (delegator, delegate, contract) tuple. */
18749
+ readonly DelegationNotFound: "DELEGATION_NOT_FOUND";
18750
+ /** The delegation has expired. */
18751
+ readonly DelegationExpired: "DELEGATION_EXPIRED";
18752
+ /** Confidential (cToken) balance is insufficient for the requested operation. */
18753
+ readonly InsufficientConfidentialBalance: "INSUFFICIENT_CONFIDENTIAL_BALANCE";
18754
+ /** ERC-20 balance is insufficient for the requested shield amount. */
18755
+ readonly InsufficientERC20Balance: "INSUFFICIENT_ERC20_BALANCE";
18756
+ /** ERC-20 allowance granted to the wrapper is insufficient for the requested wrap amount. */
18757
+ readonly InsufficientAllowance: "INSUFFICIENT_ALLOWANCE";
18758
+ /** Balance validation could not be performed (no cached credentials and decryption not possible). */
18759
+ readonly BalanceCheckUnavailable: "BALANCE_CHECK_UNAVAILABLE";
18760
+ /** Public ERC-20 read (e.g. balanceOf) failed due to a network or contract error. */
18761
+ readonly ERC20ReadFailed: "ERC20_READ_FAILED";
18762
+ /** The new expiration date equals the current one — no on-chain change needed. */
18763
+ readonly DelegationExpiryUnchanged: "DELEGATION_EXPIRY_UNCHANGED";
18764
+ /** Delegate address cannot be the contract address. */
18765
+ readonly DelegationDelegateEqualsContract: "DELEGATION_DELEGATE_EQUALS_CONTRACT";
18766
+ /** Contract address cannot be the sender address. */
18767
+ readonly DelegationContractIsSelf: "DELEGATION_CONTRACT_IS_SELF";
18768
+ /** The ACL contract is paused. */
18769
+ readonly AclPaused: "ACL_PAUSED";
18770
+ /** Expiration date is too soon (must be at least 1 hour in the future). */
18771
+ readonly DelegationExpirationTooSoon: "DELEGATION_EXPIRATION_TOO_SOON";
18772
+ /** Delegation exists on-chain but hasn't propagated to the gateway yet. */
18773
+ readonly DelegationNotPropagated: "DELEGATION_NOT_PROPAGATED";
18774
+ /** Signer and provider are connected to different chains. */
18775
+ readonly ChainMismatch: "CHAIN_MISMATCH";
18776
+ /** Operation requires a signer but none is configured. */
18777
+ readonly SignerNotConfigured: "SIGNER_NOT_CONFIGURED";
18778
+ /** Operation requires a connected wallet account. */
18779
+ readonly WalletNotConnected: "WALLET_NOT_CONNECTED";
18780
+ /** Wallet account discovery is still resolving. */
18781
+ readonly WalletAccountNotReady: "WALLET_ACCOUNT_NOT_READY";
18763
18782
  };
18764
- //#endregion
18765
- //#region src/credentials/schemas.d.ts
18766
- declare const StoredTransportKeyPairSchema: z.ZodMiniObject<{
18767
- publicKey: z.ZodMiniCustom<`0x${string}`, `0x${string}`>;
18768
- privateKey: z.ZodMiniCustom<`0x${string}`, `0x${string}`>;
18769
- createdAt: z.ZodMiniNumberFormat;
18770
- expiresAt: z.ZodMiniNumberFormat;
18771
- }, z.core.$strip>;
18772
- declare const PermissionSchema: z.ZodMiniObject<{
18773
- keypairPublicKey: z.ZodMiniCustom<`0x${string}`, `0x${string}`>;
18774
- contractAddresses: z.ZodMiniArray<z.ZodMiniPipe<z.ZodMiniCustom<`0x${string}`, `0x${string}`>, z.ZodMiniTransform<ChecksummedAddress, `0x${string}`>>>;
18775
- serializedPermit: z.ZodMiniObject<{
18776
- version: z.ZodMiniNumberFormat;
18777
- eip712: z.ZodMiniObject<{
18778
- domain: z.ZodMiniRecord<z.ZodMiniString<string>, z.ZodMiniUnknown>;
18779
- primaryType: z.ZodMiniOptional<z.ZodMiniString<string>>;
18780
- types: z.ZodMiniRecord<z.ZodMiniString<string>, z.ZodMiniArray<z.ZodMiniObject<{
18781
- name: z.ZodMiniString<string>;
18782
- type: z.ZodMiniString<string>;
18783
- }, z.core.$strip>>>;
18784
- message: z.ZodMiniRecord<z.ZodMiniString<string>, z.ZodMiniUnknown>;
18785
- }, z.core.$strip>;
18786
- signature: z.ZodMiniCustom<`0x${string}`, `0x${string}`>;
18787
- signerAddress: z.ZodMiniPipe<z.ZodMiniCustom<`0x${string}`, `0x${string}`>, z.ZodMiniTransform<ChecksummedAddress, `0x${string}`>>;
18788
- }, z.core.$strip>;
18789
- startTimestamp: z.ZodMiniNumberFormat;
18790
- durationDays: z.ZodMiniNumberFormat;
18791
- }, z.core.$strip>;
18792
- //#endregion
18793
- //#region src/credentials/types.d.ts
18783
+ /** Union of all {@link ZamaErrorCode} string values. */
18784
+ type ZamaErrorCode = (typeof ZamaErrorCode)[keyof typeof ZamaErrorCode];
18794
18785
  /**
18795
- * Serialized transport key pair — ML-KEM public + private key as hex, the shape
18796
- * we persist and hand to the decrypt path. Mirrors `@fhevm/sdk`'s
18797
- * `serializeTransportKeyPair` output; the private half is plaintext, so treat it
18798
- * as sensitive.
18786
+ * Base error thrown by all SDK operations.
18787
+ * Carries a {@link ZamaErrorCode} for programmatic error handling.
18788
+ * Prefer catching specific subclasses (e.g. {@link EncryptionFailedError}).
18799
18789
  */
18800
- interface SerializedTransportKeyPair {
18801
- publicKey: Hex;
18802
- privateKey: Hex;
18790
+ declare class ZamaError extends Error {
18791
+ /** Machine-readable error code. */
18792
+ readonly code: ZamaErrorCode;
18793
+ /**
18794
+ * Whether the operation that threw this error is safe to retry. Defaults to
18795
+ * {@link RETRYABLE_BY_CODE}'s entry for `code`; only {@link RelayerRequestFailedError}
18796
+ * overrides it per-instance (its retryability depends on the HTTP status).
18797
+ * Prefer {@link isRetryable} over reading this directly, so a new `unknown`
18798
+ * caught value doesn't need an `instanceof ZamaError` check first.
18799
+ */
18800
+ readonly retryable: boolean;
18801
+ constructor(code: ZamaErrorCode, message: string, options?: ErrorOptions & {
18802
+ retryable?: boolean;
18803
+ });
18803
18804
  }
18804
- /** Persisted transport key pair entry with a bounded lifetime. */
18805
- type StoredTransportKeyPair = z.infer<typeof StoredTransportKeyPairSchema>;
18806
18805
  /**
18807
- * A signed EIP-712 permit binding a signer (and optional delegator) to a set of
18808
- * contract addresses for a bounded time window. Wraps the serialized `@fhevm/sdk`
18809
- * permit ({@link SerializedPermit}) alongside the scope/coverage metadata the
18810
- * permission store indexes on.
18806
+ * True if `error` is a {@link ZamaError} whose failure is transient and safe to
18807
+ * retry (rate-limited, back-pressured, a delegation still propagating or in
18808
+ * its per-block cooldown, or a wallet account still resolving).
18809
+ * Compiler-guaranteed to stay in sync with the
18810
+ * taxonomy: every {@link ZamaError} subclass declares its own retryability via
18811
+ * {@link ZamaError.retryable}, so a consumer never has to hardcode a set of
18812
+ * retryable codes.
18813
+ *
18814
+ * @example
18815
+ * ```ts
18816
+ * try {
18817
+ * await sdk.decryption.decryptValues([{ encryptedValue, contractAddress }]);
18818
+ * } catch (e) {
18819
+ * if (isRetryable(e)) {
18820
+ * // back off and retry (see retryAfterSeconds for a server-suggested delay)
18821
+ * } else {
18822
+ * throw e; // terminal — surface it
18823
+ * }
18824
+ * }
18825
+ * ```
18811
18826
  */
18812
- type Permission = z.infer<typeof PermissionSchema>;
18827
+ declare function isRetryable(error: unknown): error is ZamaError & {
18828
+ retryable: true;
18829
+ };
18813
18830
  /**
18814
- * Credentials resolved for a decrypt operation: the transport key pair plus the
18815
- * permits covering the requested contracts. A live, in-memory bundle — not a
18816
- * storage record. {@link resolvePermit} extracts one {@link ResolvedPermit} from
18817
- * it per contract.
18831
+ * The server-suggested retry delay, in **seconds**, for a retryable
18832
+ * {@link ZamaError} — unifying the `retryAfter` field that today lives on
18833
+ * {@link RelayerRequestFailedError} and {@link RpcRateLimitError} only.
18834
+ * `undefined` when the error isn't retryable, or is retryable but carries no
18835
+ * server-driven delay (e.g. {@link DelegationNotPropagatedError} — retry that
18836
+ * with your own backoff).
18818
18837
  */
18819
- interface SerializedTransportKeyPairWithPermissions {
18820
- readonly keypair: SerializedTransportKeyPair;
18821
- readonly permissions: readonly Permission[];
18822
- }
18838
+ declare function retryAfterSeconds(error: unknown): number | undefined;
18823
18839
  //#endregion
18824
- //#region src/wrappers-registry.d.ts
18825
- /**
18826
- * Default wrappers registry addresses for known chains.
18827
- * Only includes chains where a registry is deployed (excludes Hardhat).
18828
- *
18829
- * @deprecated Read `registryAddress` from the chain presets instead (e.g.
18830
- * `sepolia.registryAddress`). Will be removed in the next major version.
18831
- */
18832
- declare const DefaultRegistryAddresses: Record<number, Address>;
18833
- /** Configuration for {@link WrappersRegistry}. */
18834
- interface WrappersRegistryConfig {
18835
- /** Read-only chain provider used for every registry lookup. */
18836
- provider: GenericProvider;
18837
- /**
18838
- * Per-chain registry address overrides, merged on top of
18839
- * {@link DefaultRegistryAddresses}. Use this to supply a registry
18840
- * address for custom or local chains (e.g. Hardhat).
18841
- *
18842
- * @example
18843
- * ```ts
18844
- * new WrappersRegistry({
18845
- * provider,
18846
- * registryAddresses: { [31337]: "0xYourHardhatRegistry" },
18847
- * });
18848
- * ```
18849
- */
18850
- registryAddresses?: Record<number, Address>;
18851
- /**
18852
- * How long cached registry results remain valid, in seconds.
18853
- * Default: `86400` (24 hours).
18854
- */
18855
- registryTTL?: number;
18856
- }
18857
- /** Options for {@link WrappersRegistry.listPairs}. */
18858
- interface ListPairsOptions {
18859
- /** Page number (1-indexed). Default: `1`. */
18860
- page?: number;
18861
- /** Number of items per page. Default: `100`. */
18862
- pageSize?: number;
18863
- /**
18864
- * When `true`, fetches on-chain metadata (name, symbol, decimals) for both
18865
- * the ERC-20 and confidential token, plus totalSupply for the ERC-20.
18866
- * Default: `false`.
18867
- */
18868
- metadata?: boolean;
18869
- }
18840
+ //#region src/errors/chain.d.ts
18870
18841
  /**
18871
- * High-level interface for the on-chain token wrappers registry.
18842
+ * Thrown when the signer and provider are connected to different chains at the
18843
+ * start of a write operation.
18872
18844
  *
18873
- * Uses the configured {@link GenericProvider} to resolve the correct registry
18874
- * contract address for the current chain and exposes typed read helpers for
18875
- * every registry query. Results are cached in memory with a configurable TTL
18876
- * (default 24 hours).
18877
- *
18878
- * @example
18879
- * ```ts
18880
- * const registry = new WrappersRegistry({ provider });
18881
- *
18882
- * // Paginated listing
18883
- * const page1 = await registry.listPairs({ page: 1, pageSize: 20 });
18884
- *
18885
- * // Structured lookups
18886
- * const result = await registry.getConfidentialToken(erc20Address);
18887
- * if (result) console.log(result.confidentialTokenAddress);
18888
- *
18889
- * // Force refresh
18890
- * registry.refresh();
18891
- * ```
18892
- */
18893
- declare class WrappersRegistry {
18894
- #private;
18895
- readonly provider: GenericProvider;
18896
- constructor(config: WrappersRegistryConfig);
18897
- /**
18898
- * Synchronous lookup of the registry address for a given chain ID.
18899
- * Returns `undefined` if no address is configured for that chain.
18900
- */
18901
- getAddress(chainId: number): Address | undefined;
18902
- /**
18903
- * Force-invalidate the in-memory cache. The next call to any read method
18904
- * will fetch fresh data from the chain.
18905
- */
18906
- refresh(): void;
18907
- /**
18908
- * The cache TTL in milliseconds.
18909
- * Exposed so query option factories can set a matching `staleTime`.
18910
- */
18911
- get ttlMs(): number;
18912
- /**
18913
- * Resolve the registry contract address for the current chain.
18914
- *
18915
- * Priority: `registryAddresses[chainId]` \> built-in default.
18916
- *
18917
- * @returns The registry contract address for the connected chain.
18918
- * @throws if no address is configured for the chain. {@link ConfigurationError}
18919
- */
18920
- getRegistryAddress(): Promise<Address>;
18921
- /**
18922
- * List token wrapper pairs with page-based pagination.
18923
- *
18924
- * Internally maps to `getTokenConfidentialTokenPairsSlice` on-chain.
18925
- *
18926
- * @param options - Pagination and enrichment options.
18927
- * @returns A {@link PaginatedResult} of pairs.
18928
- *
18929
- * @example
18930
- * ```ts
18931
- * const result = await registry.listPairs({ page: 1, pageSize: 20 });
18932
- * console.log(`${result.total} pairs, showing page ${result.page}`);
18933
- *
18934
- * // With on-chain metadata
18935
- * const withMeta = await registry.listPairs({ metadata: true, pageSize: 10 });
18936
- * for (const pair of withMeta.items) {
18937
- * console.log(pair.underlying.symbol, "→", pair.confidential.symbol);
18938
- * }
18939
- * ```
18940
- */
18941
- listPairs(options: ListPairsOptions & {
18942
- metadata: true;
18943
- }): Promise<PaginatedResult<TokenWrapperPairWithMetadata>>;
18944
- listPairs(options?: ListPairsOptions): Promise<PaginatedResult<TokenWrapperPair>>;
18945
- /**
18946
- * Look up the confidential token for a given plain ERC-20 address.
18947
- *
18948
- * @param tokenAddress - The plain ERC-20 token address.
18949
- * @returns The lookup result, or `null` if the token has never been registered.
18950
- * **Note:** revoked tokens (registered then invalidated) return a non-null result
18951
- * with `isValid: false`. Check `result.isValid` explicitly rather than using
18952
- * `if (result)` to guard against processing revoked tokens.
18953
- *
18954
- * @example
18955
- * ```ts
18956
- * const result = await registry.getConfidentialToken(usdcAddress);
18957
- * if (result?.isValid) {
18958
- * console.log(result.confidentialTokenAddress);
18959
- * }
18960
- * ```
18961
- */
18962
- getConfidentialToken(tokenAddress: Address): Promise<{
18963
- confidentialTokenAddress: Address;
18964
- isValid: boolean;
18965
- } | null>;
18966
- /**
18967
- * Reverse lookup — find the plain ERC-20 for a given confidential token.
18968
- *
18969
- * @param confidentialTokenAddress - The confidential token address.
18970
- * @returns The lookup result, or `null` if no pair is registered.
18971
- *
18972
- * @example
18973
- * ```ts
18974
- * const result = await registry.getUnderlyingToken(cUsdcAddress);
18975
- * if (result) {
18976
- * console.log(result.tokenAddress, result.isValid);
18977
- * }
18978
- * ```
18979
- */
18980
- getUnderlyingToken(confidentialTokenAddress: Address): Promise<{
18981
- tokenAddress: Address;
18982
- isValid: boolean;
18983
- } | null>;
18984
- /**
18985
- * Fetch all token wrapper pairs from the registry.
18986
- *
18987
- * @returns All registered `TokenWrapperPair` entries.
18988
- */
18989
- getTokenPairs(): Promise<readonly TokenWrapperPair[]>;
18990
- /**
18991
- * Get the total number of token wrapper pairs.
18992
- *
18993
- * @returns The count as a bigint.
18994
- */
18995
- getTokenPairsLength(): Promise<bigint>;
18996
- /**
18997
- * Fetch a range of token wrapper pairs (paginated by index).
18998
- *
18999
- * @param fromIndex - Start index (inclusive).
19000
- * @param toIndex - End index (exclusive).
19001
- * @returns The slice of `TokenWrapperPair` entries.
19002
- */
19003
- getTokenPairsSlice(fromIndex: bigint, toIndex: bigint): Promise<readonly TokenWrapperPair[]>;
19004
- /**
19005
- * Fetch a single token wrapper pair by index.
19006
- *
19007
- * @param index - Zero-based pair index.
19008
- * @returns The `TokenWrapperPair` at that index.
19009
- */
19010
- getTokenPair(index: bigint): Promise<TokenWrapperPair>;
19011
- /**
19012
- * Look up the confidential token address for a given plain ERC-20 token.
19013
- *
19014
- * @param tokenAddress - The plain ERC-20 token address.
19015
- * @returns A tuple `[isValid, confidentialTokenAddress]`. `isValid` is `true` only for a
19016
- * registered, non-revoked wrapper. The address is the zero address when no pair is registered.
19017
- * A non-zero address with `isValid=false` means the wrapper was registered but later revoked.
19018
- */
19019
- getConfidentialTokenAddress(tokenAddress: Address): Promise<readonly [boolean, Address]>;
19020
- /**
19021
- * Reverse lookup — find the plain ERC-20 for a given confidential token.
19022
- *
19023
- * @param confidentialTokenAddress - The confidential token address.
19024
- * @returns A tuple `[isValid, tokenAddress]`. `isValid` is `true` only for a registered,
19025
- * non-revoked wrapper. The address is the zero address when no pair is registered.
19026
- * A non-zero address with `isValid=false` means the wrapper was registered but later revoked.
19027
- */
19028
- getTokenAddress(confidentialTokenAddress: Address): Promise<readonly [boolean, Address]>;
19029
- /**
19030
- * Check whether a confidential token is registered and valid.
19031
- *
19032
- * @param confidentialTokenAddress - The confidential token address to check.
19033
- * @returns `true` if the token is a known valid wrapper in the registry.
19034
- */
19035
- isConfidentialTokenValid(confidentialTokenAddress: Address): Promise<boolean>;
19036
- }
19037
- //#endregion
19038
- //#region src/query/wrapper-discovery.d.ts
19039
- interface WrapperDiscoveryQueryConfig {
19040
- /**
19041
- * Address of any confidential token you control.
19042
- * Used to scope the query cache key and to gate whether the query
19043
- * is enabled — it does not affect which wrapper the registry returns.
19044
- */
19045
- tokenAddress?: Address;
19046
- /**
19047
- * The ERC-20 token address to discover the confidential wrapper for.
19048
- * The registry is resolved automatically from chain config.
19049
- */
19050
- erc20Address?: Address;
19051
- /**
19052
- * The resolved registry contract address for the current chain.
19053
- * Included in the query key so that switching chains invalidates
19054
- * stale cached results. Pass `undefined` when the chain ID is not
19055
- * yet known — the query will be disabled.
19056
- */
19057
- registryAddress?: Address;
19058
- query?: Record<string, unknown>;
19059
- }
19060
- declare function wrapperDiscoveryQueryOptions(registry: WrappersRegistry, config: WrapperDiscoveryQueryConfig): QueryFactoryOptions<Address | null, Error, Address | null, ReturnType<typeof zamaQueryKeys.wrapperDiscovery.token>>;
19061
- //#endregion
19062
- //#region src/query/underlying-allowance.d.ts
19063
- interface UnderlyingAllowanceQueryConfig {
19064
- owner?: Address;
19065
- query?: Record<string, unknown>;
19066
- }
19067
- declare function underlyingAllowanceQueryOptions(sdk: ZamaSDK, tokenAddress: Address, config: UnderlyingAllowanceQueryConfig): QueryFactoryOptions<bigint, Error, bigint, ReturnType<typeof zamaQueryKeys.underlyingAllowance.scope>>;
19068
- //#endregion
19069
- //#region src/query/pending-unshield.d.ts
19070
- interface PendingUnshieldQueryConfig {
19071
- query?: Record<string, unknown>;
19072
- }
19073
- /**
19074
- * Query options for reading the unwrap tx hash of an unshield that was
19075
- * interrupted between its two phases (returns `null` if none is pending).
19076
- *
19077
- * Backed by {@link ZamaSDK} storage via `WrappedToken.getPendingUnshield()`.
19078
- * `staleTime: 0` so the value reflects storage on mount; the unshield/unwrap
19079
- * mutations also invalidate this key on success.
19080
- */
19081
- declare function pendingUnshieldQueryOptions(sdk: ZamaSDK, tokenAddress: Address, config?: PendingUnshieldQueryConfig): QueryFactoryOptions<Hex | null, Error, Hex | null, ReturnType<typeof zamaQueryKeys.pendingUnshield.token>>;
19082
- //#endregion
19083
- //#region src/query/confidential-is-operator.d.ts
19084
- interface ConfidentialIsOperatorQueryConfig {
19085
- holder?: Address;
19086
- spender?: Address;
19087
- query?: Record<string, unknown>;
19088
- }
19089
- declare function confidentialIsOperatorQueryOptions(sdk: ZamaSDK, tokenAddress: Address | undefined, config: ConfidentialIsOperatorQueryConfig): QueryFactoryOptions<boolean, Error, boolean, ReturnType<typeof zamaQueryKeys.confidentialIsOperator.scope>>;
19090
- //#endregion
19091
- //#region src/errors/base.d.ts
19092
- /**
19093
- * Typed error codes thrown by the SDK.
19094
- * Use `error.code` or `instanceof` to programmatically handle specific failure modes.
19095
- *
19096
- * @example
19097
- * ```ts
19098
- * try {
19099
- * await token.confidentialTransfer("0xTo", 100n);
19100
- * } catch (e) {
19101
- * if (e instanceof SigningRejectedError) {
19102
- * // User rejected the wallet signature
19103
- * }
19104
- * }
19105
- * ```
19106
- */
19107
- declare const ZamaErrorCode: {
19108
- /** User rejected the wallet signature prompt. */
19109
- readonly SigningRejected: "SIGNING_REJECTED";
19110
- /** Wallet signature failed for a reason other than rejection. */
19111
- readonly SigningFailed: "SIGNING_FAILED";
19112
- /** FHE encryption failed. */
19113
- readonly EncryptionFailed: "ENCRYPTION_FAILED";
19114
- /** FHE decryption failed. */
19115
- readonly DecryptionFailed: "DECRYPTION_FAILED";
19116
- /** On-chain transaction reverted. */
19117
- readonly TransactionReverted: "TRANSACTION_REVERTED";
19118
- /** Transport key pair has expired and needs regeneration. */
19119
- readonly TransportKeyPairExpired: "KEYPAIR_EXPIRED";
19120
- /** Relayer rejected transport key pair (stale, expired, or malformed). */
19121
- readonly InvalidTransportKeyPair: "INVALID_KEYPAIR";
19122
- /** No FHE ciphertext exists for this account (never shielded). */
19123
- readonly NoCiphertext: "NO_CIPHERTEXT";
19124
- /** Relayer HTTP request failed. */
19125
- readonly RelayerRequestFailed: "RELAYER_REQUEST_FAILED";
19126
- /** The configured signer/account is not entitled (ACL) to decrypt this encrypted value. Don't retry — wait for a grant. */
19127
- readonly NotEntitled: "NOT_ENTITLED";
19128
- /** The consumer's RPC provider rate-limited an on-chain read (e.g. HTTP 429 / JSON-RPC -32005). Retryable. */
19129
- readonly RpcRateLimited: "RPC_RATE_LIMITED";
19130
- /** SDK configuration is invalid (e.g. forbidden chain ID, unsupported type). */
19131
- readonly Configuration: "CONFIGURATION";
19132
- /** Delegation cannot target self (delegate === msg.sender). */
19133
- readonly DelegationSelfNotAllowed: "DELEGATION_SELF_NOT_ALLOWED";
19134
- /** Only one delegate/revoke per (delegator, delegate, contract) per block. */
19135
- readonly DelegationCooldown: "DELEGATION_COOLDOWN";
19136
- /** No active delegation found for this (delegator, delegate, contract) tuple. */
19137
- readonly DelegationNotFound: "DELEGATION_NOT_FOUND";
19138
- /** The delegation has expired. */
19139
- readonly DelegationExpired: "DELEGATION_EXPIRED";
19140
- /** Confidential (cToken) balance is insufficient for the requested operation. */
19141
- readonly InsufficientConfidentialBalance: "INSUFFICIENT_CONFIDENTIAL_BALANCE";
19142
- /** ERC-20 balance is insufficient for the requested shield amount. */
19143
- readonly InsufficientERC20Balance: "INSUFFICIENT_ERC20_BALANCE";
19144
- /** ERC-20 allowance granted to the wrapper is insufficient for the requested wrap amount. */
19145
- readonly InsufficientAllowance: "INSUFFICIENT_ALLOWANCE";
19146
- /** Balance validation could not be performed (no cached credentials and decryption not possible). */
19147
- readonly BalanceCheckUnavailable: "BALANCE_CHECK_UNAVAILABLE";
19148
- /** Public ERC-20 read (e.g. balanceOf) failed due to a network or contract error. */
19149
- readonly ERC20ReadFailed: "ERC20_READ_FAILED";
19150
- /** The new expiration date equals the current one — no on-chain change needed. */
19151
- readonly DelegationExpiryUnchanged: "DELEGATION_EXPIRY_UNCHANGED";
19152
- /** Delegate address cannot be the contract address. */
19153
- readonly DelegationDelegateEqualsContract: "DELEGATION_DELEGATE_EQUALS_CONTRACT";
19154
- /** Contract address cannot be the sender address. */
19155
- readonly DelegationContractIsSelf: "DELEGATION_CONTRACT_IS_SELF";
19156
- /** The ACL contract is paused. */
19157
- readonly AclPaused: "ACL_PAUSED";
19158
- /** Expiration date is too soon (must be at least 1 hour in the future). */
19159
- readonly DelegationExpirationTooSoon: "DELEGATION_EXPIRATION_TOO_SOON";
19160
- /** Delegation exists on-chain but hasn't propagated to the gateway yet. */
19161
- readonly DelegationNotPropagated: "DELEGATION_NOT_PROPAGATED";
19162
- /** Signer and provider are connected to different chains. */
19163
- readonly ChainMismatch: "CHAIN_MISMATCH";
19164
- /** Operation requires a signer but none is configured. */
19165
- readonly SignerNotConfigured: "SIGNER_NOT_CONFIGURED";
19166
- /** Operation requires a connected wallet account. */
19167
- readonly WalletNotConnected: "WALLET_NOT_CONNECTED";
19168
- /** Wallet account discovery is still resolving. */
19169
- readonly WalletAccountNotReady: "WALLET_ACCOUNT_NOT_READY";
19170
- };
19171
- /** Union of all {@link ZamaErrorCode} string values. */
19172
- type ZamaErrorCode = (typeof ZamaErrorCode)[keyof typeof ZamaErrorCode];
19173
- /**
19174
- * Base error thrown by all SDK operations.
19175
- * Carries a {@link ZamaErrorCode} for programmatic error handling.
19176
- * Prefer catching specific subclasses (e.g. {@link EncryptionFailedError}).
19177
- */
19178
- declare class ZamaError extends Error {
19179
- /** Machine-readable error code. */
19180
- readonly code: ZamaErrorCode;
19181
- /**
19182
- * Whether the operation that threw this error is safe to retry. Defaults to
19183
- * {@link RETRYABLE_BY_CODE}'s entry for `code`; only {@link RelayerRequestFailedError}
19184
- * overrides it per-instance (its retryability depends on the HTTP status).
19185
- * Prefer {@link isRetryable} over reading this directly, so a new `unknown`
19186
- * caught value doesn't need an `instanceof ZamaError` check first.
19187
- */
19188
- readonly retryable: boolean;
19189
- constructor(code: ZamaErrorCode, message: string, options?: ErrorOptions & {
19190
- retryable?: boolean;
19191
- });
19192
- }
19193
- /**
19194
- * True if `error` is a {@link ZamaError} whose failure is transient and safe to
19195
- * retry (rate-limited, back-pressured, a delegation still propagating or in
19196
- * its per-block cooldown, or a wallet account still resolving).
19197
- * Compiler-guaranteed to stay in sync with the
19198
- * taxonomy: every {@link ZamaError} subclass declares its own retryability via
19199
- * {@link ZamaError.retryable}, so a consumer never has to hardcode a set of
19200
- * retryable codes.
19201
- *
19202
- * @example
19203
- * ```ts
19204
- * try {
19205
- * await sdk.decryption.decryptValues([{ encryptedValue, contractAddress }]);
19206
- * } catch (e) {
19207
- * if (isRetryable(e)) {
19208
- * // back off and retry (see retryAfterSeconds for a server-suggested delay)
19209
- * } else {
19210
- * throw e; // terminal — surface it
19211
- * }
19212
- * }
19213
- * ```
19214
- */
19215
- declare function isRetryable(error: unknown): error is ZamaError & {
19216
- retryable: true;
19217
- };
19218
- /**
19219
- * The server-suggested retry delay, in **seconds**, for a retryable
19220
- * {@link ZamaError} — unifying the `retryAfter` field that today lives on
19221
- * {@link RelayerRequestFailedError} and {@link RpcRateLimitError} only.
19222
- * `undefined` when the error isn't retryable, or is retryable but carries no
19223
- * server-driven delay (e.g. {@link DelegationNotPropagatedError} — retry that
19224
- * with your own backoff).
19225
- */
19226
- declare function retryAfterSeconds(error: unknown): number | undefined;
19227
- //#endregion
19228
- //#region src/errors/chain.d.ts
19229
- /**
19230
- * Thrown when the signer and provider are connected to different chains at the
19231
- * start of a write operation.
19232
- *
19233
- * Every write method runs a chain-alignment pre-flight check. If
19234
- * `signer.getChainId()` and `provider.getChainId()` return different values,
19235
- * this error is thrown before any RPC mutation is attempted.
18845
+ * Every write method runs a chain-alignment pre-flight check. If
18846
+ * `signer.getChainId()` and `provider.getChainId()` return different values,
18847
+ * this error is thrown before any RPC mutation is attempted.
19236
18848
  *
19237
18849
  * @example
19238
18850
  * ```ts
@@ -19248,8 +18860,11 @@ declare function retryAfterSeconds(error: unknown): number | undefined;
19248
18860
  * ```
19249
18861
  */
19250
18862
  declare class ChainMismatchError extends ZamaError {
18863
+ /** Name of the operation that triggered the check. */
19251
18864
  readonly operation: string;
18865
+ /** Chain ID the signer is connected to. */
19252
18866
  readonly signerChainId: number;
18867
+ /** Chain ID the provider is connected to. */
19253
18868
  readonly providerChainId: number;
19254
18869
  constructor({ operation, signerChainId, providerChainId }: {
19255
18870
  operation: string;
@@ -19349,8 +18964,11 @@ declare class DecryptionFailedError extends ZamaError {
19349
18964
  //#region src/errors/balance.d.ts
19350
18965
  /** Structured details shared by balance-related errors. */
19351
18966
  interface BalanceErrorDetails {
18967
+ /** Amount the caller requested, in the token's base units. */
19352
18968
  readonly requested: bigint;
18969
+ /** Amount available at the time of the check, in the token's base units. */
19353
18970
  readonly available: bigint;
18971
+ /** Address of the token contract involved. */
19354
18972
  readonly token: Address;
19355
18973
  }
19356
18974
  /** Confidential (cToken) balance is insufficient for the requested operation. */
@@ -19488,6 +19106,7 @@ declare class RpcRateLimitError extends ZamaError {
19488
19106
  * Base class for signer/account readiness failures.
19489
19107
  */
19490
19108
  declare class SignerRequiredError extends ZamaError {
19109
+ /** Name of the operation that required a signer. */
19491
19110
  readonly operation: string;
19492
19111
  constructor(code: ZamaErrorCode, operation: string, message: string, options?: ErrorOptions);
19493
19112
  }
@@ -19537,51 +19156,75 @@ declare class TransactionRevertedError extends ZamaError {
19537
19156
  }
19538
19157
  //#endregion
19539
19158
  //#region src/errors/match.d.ts
19540
- /**
19541
- * Identity type that fails to instantiate unless `T` maps every code to a `ZamaError`.
19542
- * Guards presence + value type only: a wrong-but-valid mapping (a code pointing at a
19543
- * structurally identical sibling class) still compiles — `errors.test-d.ts` backstops that.
19544
- */
19545
- type Complete<T extends Record<ZamaErrorCode, ZamaError>> = T;
19546
19159
  /**
19547
19160
  * Maps each {@link ZamaErrorCode} to the error class thrown with that code, so
19548
19161
  * {@link matchZamaError} handlers receive the matched subtype instead of the base
19549
- * `ZamaError`. Hand-maintained; the `Complete` wrapper fails the build if a code is
19550
- * added without an entry here (or mapped to a non-`ZamaError`).
19162
+ * `ZamaError`.
19551
19163
  */
19552
- type ErrorForCode = Complete<{
19164
+ interface ErrorForCode {
19165
+ /** Thrown for {@link ZamaErrorCode.SigningRejected}. */
19553
19166
  [ZamaErrorCode.SigningRejected]: SigningRejectedError;
19167
+ /** Thrown for {@link ZamaErrorCode.SigningFailed}. */
19554
19168
  [ZamaErrorCode.SigningFailed]: SigningFailedError;
19169
+ /** Thrown for {@link ZamaErrorCode.EncryptionFailed}. */
19555
19170
  [ZamaErrorCode.EncryptionFailed]: EncryptionFailedError;
19171
+ /** Thrown for {@link ZamaErrorCode.DecryptionFailed}. */
19556
19172
  [ZamaErrorCode.DecryptionFailed]: DecryptionFailedError;
19173
+ /** Thrown for {@link ZamaErrorCode.TransactionReverted}. */
19557
19174
  [ZamaErrorCode.TransactionReverted]: TransactionRevertedError;
19175
+ /** Thrown for {@link ZamaErrorCode.TransportKeyPairExpired}. */
19558
19176
  [ZamaErrorCode.TransportKeyPairExpired]: TransportKeyPairExpiredError;
19177
+ /** Thrown for {@link ZamaErrorCode.InvalidTransportKeyPair}. */
19559
19178
  [ZamaErrorCode.InvalidTransportKeyPair]: InvalidTransportKeyPairError;
19179
+ /** Thrown for {@link ZamaErrorCode.NoCiphertext}. */
19560
19180
  [ZamaErrorCode.NoCiphertext]: NoCiphertextError;
19181
+ /** Thrown for {@link ZamaErrorCode.RelayerRequestFailed}. */
19561
19182
  [ZamaErrorCode.RelayerRequestFailed]: RelayerRequestFailedError;
19183
+ /** Thrown for {@link ZamaErrorCode.NotEntitled}. */
19562
19184
  [ZamaErrorCode.NotEntitled]: NotEntitledError;
19185
+ /** Thrown for {@link ZamaErrorCode.RpcRateLimited}. */
19563
19186
  [ZamaErrorCode.RpcRateLimited]: RpcRateLimitError;
19187
+ /** Thrown for {@link ZamaErrorCode.Configuration}. */
19564
19188
  [ZamaErrorCode.Configuration]: ConfigurationError;
19189
+ /** Thrown for {@link ZamaErrorCode.DelegationSelfNotAllowed}. */
19565
19190
  [ZamaErrorCode.DelegationSelfNotAllowed]: DelegationSelfNotAllowedError;
19191
+ /** Thrown for {@link ZamaErrorCode.DelegationCooldown}. */
19566
19192
  [ZamaErrorCode.DelegationCooldown]: DelegationCooldownError;
19193
+ /** Thrown for {@link ZamaErrorCode.DelegationNotFound}. */
19567
19194
  [ZamaErrorCode.DelegationNotFound]: DelegationNotFoundError;
19195
+ /** Thrown for {@link ZamaErrorCode.DelegationExpired}. */
19568
19196
  [ZamaErrorCode.DelegationExpired]: DelegationExpiredError;
19197
+ /** Thrown for {@link ZamaErrorCode.InsufficientConfidentialBalance}. */
19569
19198
  [ZamaErrorCode.InsufficientConfidentialBalance]: InsufficientConfidentialBalanceError;
19199
+ /** Thrown for {@link ZamaErrorCode.InsufficientERC20Balance}. */
19570
19200
  [ZamaErrorCode.InsufficientERC20Balance]: InsufficientERC20BalanceError;
19201
+ /** Thrown for {@link ZamaErrorCode.InsufficientAllowance}. */
19571
19202
  [ZamaErrorCode.InsufficientAllowance]: InsufficientAllowanceError;
19203
+ /** Thrown for {@link ZamaErrorCode.BalanceCheckUnavailable}. */
19572
19204
  [ZamaErrorCode.BalanceCheckUnavailable]: BalanceCheckUnavailableError;
19205
+ /** Thrown for {@link ZamaErrorCode.ERC20ReadFailed}. */
19573
19206
  [ZamaErrorCode.ERC20ReadFailed]: ERC20ReadFailedError;
19207
+ /** Thrown for {@link ZamaErrorCode.DelegationExpiryUnchanged}. */
19574
19208
  [ZamaErrorCode.DelegationExpiryUnchanged]: DelegationExpiryUnchangedError;
19209
+ /** Thrown for {@link ZamaErrorCode.DelegationDelegateEqualsContract}. */
19575
19210
  [ZamaErrorCode.DelegationDelegateEqualsContract]: DelegationDelegateEqualsContractError;
19211
+ /** Thrown for {@link ZamaErrorCode.DelegationContractIsSelf}. */
19576
19212
  [ZamaErrorCode.DelegationContractIsSelf]: DelegationContractIsSelfError;
19213
+ /** Thrown for {@link ZamaErrorCode.AclPaused}. */
19577
19214
  [ZamaErrorCode.AclPaused]: AclPausedError;
19215
+ /** Thrown for {@link ZamaErrorCode.DelegationExpirationTooSoon}. */
19578
19216
  [ZamaErrorCode.DelegationExpirationTooSoon]: DelegationExpirationTooSoonError;
19217
+ /** Thrown for {@link ZamaErrorCode.DelegationNotPropagated}. */
19579
19218
  [ZamaErrorCode.DelegationNotPropagated]: DelegationNotPropagatedError;
19219
+ /** Thrown for {@link ZamaErrorCode.ChainMismatch}. */
19580
19220
  [ZamaErrorCode.ChainMismatch]: ChainMismatchError;
19221
+ /** Thrown for {@link ZamaErrorCode.SignerNotConfigured}. */
19581
19222
  [ZamaErrorCode.SignerNotConfigured]: SignerNotConfiguredError;
19223
+ /** Thrown for {@link ZamaErrorCode.WalletNotConnected}. */
19582
19224
  [ZamaErrorCode.WalletNotConnected]: WalletNotConnectedError;
19225
+ /** Thrown for {@link ZamaErrorCode.WalletAccountNotReady}. */
19583
19226
  [ZamaErrorCode.WalletAccountNotReady]: WalletAccountNotReadyError;
19584
- }>;
19227
+ }
19585
19228
  /**
19586
19229
  * Pattern-match on a {@link ZamaError} by its error code. Each handler receives the
19587
19230
  * error class for its code, so subclass fields are available without a cast.
@@ -19602,1455 +19245,1226 @@ declare function matchZamaError<R>(error: unknown, handlers: { [K in ZamaErrorCo
19602
19245
  _?: (error: unknown) => R;
19603
19246
  }): R | undefined;
19604
19247
  //#endregion
19605
- //#region src/token/token.d.ts
19606
- /** Options for {@link Token.batchDecryptBalancesAs}. */
19607
- interface BatchDecryptAsOptions {
19608
- /** The address of the account that delegated decryption rights. */
19609
- delegatorAddress: Address;
19610
- /** Pre-fetched encrypted values. When omitted, they are fetched from the chain. */
19611
- encryptedValues?: EncryptedValue[];
19248
+ //#region src/services/decryption-service.d.ts
19249
+ /** Options shared by the delegated-decrypt entry points. */
19250
+ interface DelegatedDecryptOptions {
19612
19251
  /**
19613
- * The account whose on-chain balance to read. Defaults to the delegator
19614
- * address, which is the common case (the delegator grants permission to
19615
- * decrypt their own balance). Only set this when the account differs
19616
- * from the delegator.
19617
- *
19618
- * Matches the `account` parameter of `confidentialBalanceOf(account)` on-chain.
19252
+ * Ride out the gateway propagation window: when a just-granted delegation
19253
+ * has not yet synced, the delegated decrypt is retried (bounded, ~30s) until
19254
+ * it lands instead of throwing {@link DelegationNotPropagatedError}. Defaults
19255
+ * to `true`. Pass `false` to fail fast on the first not-propagated response.
19619
19256
  */
19620
- accountAddress?: Address;
19621
- /** Maximum number of concurrent decrypt calls. Default: 10. */
19622
- maxConcurrency?: number;
19623
- /** Called when decryption fails for a single token. Return a fallback bigint. */
19624
- onError?: (error: Error, address: Address) => bigint;
19257
+ waitForPropagation?: boolean;
19625
19258
  }
19626
- /** Result of {@link Token.batchBalancesOf}. */
19627
- interface BatchBalancesResult {
19628
- /** Successfully decrypted balances, keyed by token address. */
19629
- results: Map<Address, bigint>;
19630
- /** Per-token errors for tokens that failed to decrypt. */
19631
- errors: Map<Address, ZamaError>;
19259
+ /** Per-handle outcome of a batch decrypt: the decrypted value, or a per-item error. */
19260
+ interface BatchDecryptItem {
19261
+ /** The encrypted value (handle) being decrypted. */
19262
+ encryptedValue: EncryptedValue;
19263
+ /** Address of the contract the handle belongs to. */
19264
+ contractAddress: Address;
19265
+ /** Decrypted clear value; set when this item succeeded. */
19266
+ value?: ClearValue;
19267
+ /** Error for this item; set when this item failed. */
19268
+ error?: ZamaError;
19269
+ }
19270
+ /** Result of a batch decrypt: one entry per requested handle, in input order. */
19271
+ interface BatchDecryptResult {
19272
+ /** Per-handle outcomes. */
19273
+ items: BatchDecryptItem[];
19632
19274
  }
19275
+ //#endregion
19276
+ //#region src/namespaces/decryption.d.ts
19633
19277
  /**
19634
- * High-level interface for an ERC-7984 confidential token.
19635
- * Hides FHE complexity (encryption, decryption, EIP-712 signing) behind
19636
- * familiar ERC-20-like methods.
19278
+ * Public namespace for FHE decryption — the canonical way to decrypt.
19637
19279
  *
19638
- * For ERC-7984 wrappers (shield/unshield), use {@link WrappedToken} instead —
19639
- * it extends `Token` with wrapper-specific operations.
19280
+ * Exposed as `sdk.decryption`. Prefer these methods over the low-level
19281
+ * `sdk.relayer.decryptValues` / `decryptPublicValues`: they
19282
+ * assemble the credential bundle (transport key pair, EIP-712 permit) for you,
19283
+ * cache results, and wrap relayer errors. Reach for `sdk.relayer.*` only when
19284
+ * you must control credential assembly by hand.
19640
19285
  *
19641
- * Decryption, credentials, caching, and event emission are handled by the
19642
- * owning {@link ZamaSDK} — this class only exposes token-scoped helpers
19643
- * that delegate to `sdk.decryption.decryptValues` and `sdk.permits.grantPermit`.
19286
+ * Owns the SDK-level guards (signer requirement on
19287
+ * `decryptValues` and `delegatedDecryptValues`, empty-array
19288
+ * short-circuit on `decryptPublicValues`, relayer error wrapping) and delegates the
19289
+ * actual work to the internal {@link DecryptionService} or the relayer directly for
19290
+ * `decryptPublicValues`.
19291
+ *
19292
+ * **Mixed signer requirement:** `decryptValues` and
19293
+ * `delegatedDecryptValues` need a configured signer; `decryptPublicValues`
19294
+ * does not. Each method documents its requirement in its JSDoc.
19295
+ *
19296
+ * **Request chunking:** decrypt requests are split internally to stay under
19297
+ * the relayer's 2048-cleartext-bit per-request budget — callers never need to
19298
+ * size batches themselves.
19644
19299
  */
19645
- declare class Token {
19300
+ declare class Decryption {
19646
19301
  #private;
19647
- readonly sdk: ZamaSDK;
19648
- readonly address: Address;
19649
- constructor(sdk: ZamaSDK, address: Address);
19650
- /** Read the token name from the contract. */
19651
- name(): Promise<string>;
19652
- /** Read the token symbol from the contract. */
19653
- symbol(): Promise<string>;
19654
- /** Read the token decimals from the contract. */
19655
- decimals(): Promise<number>;
19656
- /**
19657
- * ERC-165 check for {@link ERC7984_INTERFACE_ID} support.
19658
- *
19659
- * @returns `true` if the contract implements the ERC-7984 confidential token interface.
19660
- */
19661
- isConfidential(): Promise<boolean>;
19662
- /**
19663
- * ERC-165 check for IERC7984ERC20Wrapper support.
19664
- *
19665
- * @returns `true` if the contract implements the ERC-7984 wrapper interface
19666
- * ({@link ERC7984_WRAPPER_INTERFACE_ID}, `0x1f1c62b2`).
19667
- */
19668
- isWrapper(): Promise<boolean>;
19669
19302
  /**
19670
- * Decrypt and return the plaintext balance for the given owner.
19671
- * Acquires FHE credentials via a wallet signature if none are cached.
19672
- *
19673
- * @param owner - Balance owner address.
19674
- * @returns The decrypted plaintext balance as a bigint.
19675
- * @throws if FHE decryption fails. {@link DecryptionFailedError}
19303
+ * Decrypt one or more FHE encrypted values. Results are cached — repeated calls
19304
+ * for the same encrypted value skip the relayer round-trip.
19676
19305
  *
19677
- * @example
19678
- * ```ts
19679
- * const balance = await token.balanceOf("0xOwner");
19680
- * ```
19681
- */
19682
- balanceOf(owner: Address): Promise<bigint>;
19683
- /**
19684
- * Return the raw encrypted balance without decrypting.
19306
+ * Zero encrypted values are mapped to `0n` without hitting the relayer.
19307
+ * Events (`DecryptStart/End/Error`) are emitted uniformly.
19308
+ * Relayer errors are wrapped into typed SDK errors.
19685
19309
  *
19686
- * @param owner - Balance owner address.
19687
- * @returns The encrypted balance as a hex string.
19310
+ * @param encryptedInput - Encrypted values to decrypt, each paired with its contract address.
19311
+ * @param options - Per-call `signal` and `timeout` forwarded to the relayer round-trip.
19312
+ * @returns A record mapping each encrypted value to its decrypted clear-text value.
19313
+ * @throws if no signer is configured. {@link SignerNotConfiguredError}
19314
+ * @throws if signer and provider are on different chains. {@link ChainMismatchError}
19688
19315
  *
19689
19316
  * @example
19690
19317
  * ```ts
19691
- * const encryptedValue = await token.confidentialBalanceOf("0xOwner");
19318
+ * const values = await sdk.decryption.decryptValues([
19319
+ * { encryptedValue: balance, contractAddress: cUSDT },
19320
+ * ]);
19321
+ * console.log(values[balance]); // 1000n
19692
19322
  * ```
19693
19323
  */
19694
- confidentialBalanceOf(owner: Address): Promise<EncryptedValue>;
19324
+ decryptValues(encryptedInput: EncryptedInput[], options?: Pick<FhevmRelayerOptions, "signal" | "timeout">): Promise<Record<EncryptedValue, ClearValue>>;
19695
19325
  /**
19696
- * Decrypt the balance of a delegator using delegated decryption credentials.
19697
- * The connected signer acts as the delegatee who has been granted permission
19698
- * by the delegator to decrypt their balance.
19326
+ * Decrypt one or more FHE encrypted values using delegated credentials.
19699
19327
  *
19700
- * Clear values are cached in storage keyed by `(account, token, encryptedValue)`.
19701
- * Because every on-chain balance change produces a new encrypted value,
19702
- * stale cache entries are never served. Cache write failures are silently
19703
- * ignored — they do not affect the returned value.
19328
+ * Mirrors {@link decryptValues} with delegated credentials — same caching and
19329
+ * zero-value short-circuit. Before reading from cache or calling the relayer,
19330
+ * every non-zero encrypted value's contract must have an active delegation from the
19331
+ * delegator to the connected signer; missing or expired delegations fail fast.
19704
19332
  *
19705
- * @param delegatorAddress - The address of the account that delegated decryption rights.
19706
- * @param accountAddress - The account whose on-chain balance to read. Defaults
19707
- * to the delegator address.
19708
- * @returns The decrypted plaintext balance as a bigint.
19709
- * @throws if no active delegation exists. {@link DelegationNotFoundError}
19710
- * @throws if the delegation has expired. {@link DelegationExpiredError}
19711
- * @throws if delegated decryption fails. {@link DecryptionFailedError}
19333
+ * @param encryptedInputs - FHE encrypted values paired with their contract addresses.
19334
+ * @param delegatorAddress - The address that granted delegation rights.
19335
+ * @param accountAddress - Address used as the cache key's "requester"
19336
+ * dimension. Defaults to `delegatorAddress`. Pass the actual account address
19337
+ * when decrypting on behalf of someone whose balance is stored under a
19338
+ * different address (e.g. `decryptBalanceAs` with an explicit `accountAddress`).
19339
+ * @param options - Delegated-decrypt options. By default the call rides out the
19340
+ * gateway propagation window ({@link DelegatedDecryptOptions.waitForPropagation});
19341
+ * pass `{ waitForPropagation: false }` to fail fast instead.
19342
+ * @returns Map of encrypted value → clear-text value.
19712
19343
  *
19713
19344
  * @example
19714
19345
  * ```ts
19715
- * const balance = await token.decryptBalanceAs({
19716
- * delegatorAddress: "0xDelegator",
19717
- * });
19346
+ * const values = await sdk.decryption.delegatedDecryptValues([
19347
+ * { encryptedValue: balance, contractAddress: tokenAddr },
19348
+ * ], delegatorAddr);
19349
+ * console.log(values[balance]); // 1000n
19718
19350
  * ```
19719
19351
  */
19720
- decryptBalanceAs({ delegatorAddress, accountAddress }: {
19721
- delegatorAddress: Address;
19722
- accountAddress?: Address;
19723
- }): Promise<bigint>;
19352
+ delegatedDecryptValues(encryptedInputs: EncryptedInput[], delegatorAddress: Address, accountAddress?: Address, options?: DelegatedDecryptOptions): Promise<Record<EncryptedValue, ClearValue>>;
19724
19353
  /**
19725
- * Decrypt confidential balances for multiple tokens in parallel, returning
19726
- * successes and per-token errors separately. Pre-authorizes all token
19727
- * addresses in a single wallet signature, then delegates each decrypt to
19728
- * `sdk.decryption.decryptValues`.
19354
+ * Publicly decrypt one or more FHE encrypted values.
19729
19355
  *
19730
- * Tokens that fail to decrypt land in `errors` rather than aborting the
19731
- * whole batch — caller decides how to surface them.
19356
+ * Signer-independent: works without a configured signer.
19357
+ * Returns the decryption proof alongside the clear-text values so callers
19358
+ * can submit on-chain finalization transactions (e.g. `finalizeUnwrap`).
19732
19359
  *
19733
- * @param tokens - Array of {@link Token} instances bound to the same SDK.
19734
- * @param owner - Balance owner address.
19735
- * @returns `{ results, errors }` partitioning the per-token outcomes.
19360
+ * @param encryptedValues - FHE encrypted values to decrypt publicly.
19361
+ * @param options - Per-call `signal` and `timeout` forwarded to the relayer round-trip.
19362
+ * @returns Clear-text values, ABI-encoded values, and the decryption proof.
19736
19363
  *
19737
19364
  * @example
19738
19365
  * ```ts
19739
- * const { results, errors } = await Token.batchBalancesOf(tokens, owner);
19366
+ * const { clearValues, decryptionProof, abiEncodedClearValues } =
19367
+ * await sdk.decryption.decryptPublicValues([encryptedValue]);
19740
19368
  * ```
19741
19369
  */
19742
- static batchBalancesOf(tokens: Token[], owner: Address): Promise<BatchBalancesResult>;
19370
+ decryptPublicValues(encryptedValues: EncryptedValue[], options?: Pick<FhevmRelayerOptions, "signal" | "timeout">): Promise<DecryptPublicValuesResult>;
19743
19371
  /**
19744
- * Batch decrypt confidential balances as a delegate across multiple tokens.
19745
- * Mirrors {@link batchBalancesOf} but uses delegated credentials.
19372
+ * Batch-decrypt delegated encrypted values with per-entry error isolation.
19746
19373
  *
19747
- * **Error handling:** If a per-token decryption fails and no `onError` callback
19748
- * is provided, errors are collected and thrown as an aggregated
19749
- * `DecryptionFailedError`. When the relayer returns no value for an encrypted value,
19750
- * a `DecryptionFailedError` is thrown for that token (never silently returns `0n`).
19751
- * Pass `onError: () => 0n` to opt into the silent zero behavior.
19374
+ * Attempts a single batch request first. If the batch fails with a non-fatal
19375
+ * error (e.g. one entry is invalid), falls back to per-entry decryption so
19376
+ * healthy entries still resolve. Each item in the result carries either a
19377
+ * decrypted value or an error — callers decide how to surface partial failures.
19752
19378
  *
19753
- * @param tokens - Array of Token instances to decrypt balances for.
19754
- * @param options - Delegated decryption configuration.
19755
- * @returns A Map from token address to decrypted balance.
19756
- * @throws if no active delegation exists. {@link DelegationNotFoundError}
19757
- * @throws if the delegation has expired. {@link DelegationExpiredError}
19758
- * @throws if any decryption fails and no `onError` is provided. {@link DecryptionFailedError}
19379
+ * @param encryptedInputs - FHE encrypted values paired with their contract addresses.
19380
+ * @param delegatorAddress - The address that granted delegation rights.
19381
+ * @param accountAddress - The account on whose behalf decryption is performed. Defaults to `delegatorAddress`.
19382
+ * @param maxConcurrency - Maximum parallel decrypt calls during per-entry fallback.
19383
+ * @param waitForPropagation - Ride out the gateway propagation window on the
19384
+ * initial batch attempt (default `true`). See {@link DelegatedDecryptOptions.waitForPropagation}.
19385
+ * @returns Per-entry results, each with a value or an error.
19386
+ * @throws if no signer is configured. {@link SignerNotConfiguredError}
19387
+ * @throws if signer and provider are on different chains. {@link ChainMismatchError}
19759
19388
  *
19760
19389
  * @example
19761
19390
  * ```ts
19762
- * const balances = await Token.batchDecryptBalancesAs(tokens, {
19391
+ * const result = await sdk.decryption.delegatedBatchDecryptValues({
19392
+ * encryptedInputs: [
19393
+ * { encryptedValue: encryptedValue1, contractAddress: tokenA },
19394
+ * { encryptedValue: encryptedValue2, contractAddress: tokenB },
19395
+ * ],
19763
19396
  * delegatorAddress: "0xDelegator",
19764
- * onError: (err, addr) => { console.error(addr, err); return 0n; },
19397
+ * maxConcurrency: 5,
19765
19398
  * });
19399
+ * for (const item of result.items) {
19400
+ * if (item.error) console.error(item.encryptedValue, item.error);
19401
+ * else console.log(item.encryptedValue, item.value);
19402
+ * }
19766
19403
  * ```
19767
19404
  */
19768
- static batchDecryptBalancesAs(tokens: Token[], options: BatchDecryptAsOptions): Promise<Map<Address, bigint>>;
19769
- private static readBalanceHandlesBatch;
19405
+ delegatedBatchDecryptValues({ encryptedInputs, delegatorAddress, accountAddress, maxConcurrency, waitForPropagation }: {
19406
+ encryptedInputs: EncryptedInput[];
19407
+ delegatorAddress: Address;
19408
+ accountAddress?: Address;
19409
+ maxConcurrency?: number;
19410
+ } & DelegatedDecryptOptions): Promise<BatchDecryptResult>;
19411
+ }
19412
+ //#endregion
19413
+ //#region src/services/delegation-service.d.ts
19414
+ /** Delegation activity and expiry, resolved from a single expiry read. */
19415
+ interface DelegationStatus {
19416
+ /** Whether the delegation is currently active (exists and not expired). */
19417
+ isActive: boolean;
19418
+ /** Unix timestamp (seconds) when the delegation expires; `0n` if none exists. */
19419
+ expiryTimestamp: bigint;
19420
+ }
19421
+ //#endregion
19422
+ //#region src/namespaces/delegations.d.ts
19423
+ /**
19424
+ * Public namespace for on-chain decryption-delegation management.
19425
+ *
19426
+ * Exposed as `sdk.delegations`. Owns the SDK-level guards (signer requirement, chain
19427
+ * alignment, delegator address resolution from the wallet account) and delegates the
19428
+ * actual work to the internal {@link DelegationService}.
19429
+ *
19430
+ * Delegation operations write to the host chain ACL; after a delegation is mined,
19431
+ * the gateway syncs the ACL state via cross-chain event propagation — usually
19432
+ * within ~10 blocks (a few seconds). Delegated decryption rides out that window
19433
+ * with a bounded internal retry, so callers can decrypt right after granting.
19434
+ */
19435
+ declare class Delegations {
19436
+ #private;
19770
19437
  /**
19771
- * Confidential transfer. Encrypts the amount via FHE, then calls the contract.
19438
+ * Delegate decryption rights for a confidential contract to another address.
19439
+ * Calls `ACL.delegateForUserDecryption()` on-chain.
19772
19440
  *
19773
- * By default, the SDK validates the confidential balance before submitting.
19774
- * If a cached plaintext balance exists it is used; otherwise, if credentials
19775
- * are cached, it decrypts on the fly. Set `skipBalanceCheck: true` to bypass
19776
- * this validation (e.g. for smart wallets).
19441
+ * The delegation is recorded on L1 immediately, but the gateway must sync the
19442
+ * ACL state via cross-chain event propagation — usually within ~10 blocks (a
19443
+ * few seconds). You do not need to wait: delegated decryption rides out that
19444
+ * window with a bounded internal retry, so you can decrypt right after this
19445
+ * resolves.
19777
19446
  *
19778
- * @param to - Recipient address.
19779
- * @param amount - Plaintext amount to transfer (encrypted automatically via FHE).
19780
- * @param options - Optional: `skipBalanceCheck` (default `false`).
19447
+ * @param contractAddress - The confidential contract address to delegate on.
19448
+ * @param delegateAddress - Address to delegate decryption rights to.
19449
+ * @param expirationDate - Optional expiration date (defaults to permanent delegation via `uint64.max`).
19781
19450
  * @returns The transaction hash and mined receipt.
19451
+ * @throws if no signer is configured. {@link SignerNotConfiguredError}
19782
19452
  * @throws if signer and provider are on different chains. {@link ChainMismatchError}
19783
- * @throws if the balance is less than `amount`. {@link InsufficientConfidentialBalanceError}
19784
- * @throws if balance validation requires decryption that is not possible. {@link BalanceCheckUnavailableError}
19785
- * @throws if FHE encryption fails. {@link EncryptionFailedError}
19786
- * @throws if the on-chain transfer reverts. {@link TransactionRevertedError}
19787
- *
19788
- * @example
19789
- * ```ts
19790
- * const txHash = await token.confidentialTransfer("0xRecipient", 1000n);
19791
- * ```
19453
+ * @throws if `expirationDate` is less than 1 hour in the future. {@link DelegationExpirationTooSoonError}
19454
+ * @throws if the delegate equals the connected wallet. {@link DelegationSelfNotAllowedError}
19455
+ * @throws if the delegate equals the contract address. {@link DelegationDelegateEqualsContractError}
19456
+ * @throws if the new expiry equals the current one. {@link DelegationExpiryUnchangedError}
19457
+ * @throws if the delegation transaction reverts. {@link TransactionRevertedError}
19792
19458
  */
19793
- confidentialTransfer(to: Address, amount: bigint, options?: TransferOptions): Promise<TransactionResult>;
19459
+ delegateDecryption({ contractAddress, delegateAddress, expirationDate }: {
19460
+ contractAddress: Address;
19461
+ delegateAddress: Address;
19462
+ expirationDate?: Date;
19463
+ }): Promise<TransactionResult>;
19794
19464
  /**
19795
- * Operator encrypted transfer on behalf of another address.
19796
- * The caller must be an approved operator for `from`.
19465
+ * Revoke decryption delegation for a confidential contract.
19466
+ * Calls `ACL.revokeDelegationForUserDecryption()` on-chain.
19797
19467
  *
19798
- * @param from - The address to transfer from (caller must be an approved operator).
19799
- * @param to - Recipient address.
19800
- * @param amount - Plaintext amount to transfer (encrypted automatically via FHE).
19468
+ * @param contractAddress - The confidential contract address to revoke delegation on.
19469
+ * @param delegateAddress - Address to revoke delegation from.
19801
19470
  * @returns The transaction hash and mined receipt.
19471
+ * @throws if no signer is configured. {@link SignerNotConfiguredError}
19472
+ * @throws if signer and provider are on different chains. {@link ChainMismatchError}
19473
+ * @throws if no delegation exists for this (delegator, delegate, contract) tuple. {@link DelegationNotFoundError}
19474
+ * @throws if the revocation transaction reverts. {@link TransactionRevertedError}
19475
+ */
19476
+ revokeDelegation({ contractAddress, delegateAddress }: {
19477
+ contractAddress: Address;
19478
+ delegateAddress: Address;
19479
+ }): Promise<TransactionResult>;
19480
+ /**
19481
+ * Check whether a delegation is active for the given contract address.
19802
19482
  *
19803
- * @example
19804
- * ```ts
19805
- * const txHash = await token.confidentialTransferFrom("0xFrom", "0xTo", 500n);
19806
- * ```
19483
+ * Signer-independent: works without a configured signer.
19484
+ *
19485
+ * @param contractAddress - The confidential contract address.
19486
+ * @param delegatorAddress - The address that granted the delegation.
19487
+ * @param delegateAddress - The address that received delegation rights.
19488
+ * @returns `true` if the delegation exists and has not expired.
19807
19489
  */
19808
- confidentialTransferFrom(from: Address, to: Address, amount: bigint, callbacks?: TransferCallbacks): Promise<TransactionResult>;
19490
+ isActive(params: {
19491
+ contractAddress: Address;
19492
+ delegatorAddress: Address;
19493
+ delegateAddress: Address;
19494
+ }): Promise<boolean>;
19809
19495
  /**
19810
- * ERC-7984 `confidentialTransferAndCall`: encrypted transfer that also invokes
19811
- * the recipient's receiver hook (`onConfidentialTransferReceived`) in a single
19812
- * transaction. The caller crafts the opaque `data` payload — the SDK does not
19813
- * encode, validate, or interpret it.
19496
+ * Get the expiration timestamp of a delegation for the given contract.
19814
19497
  *
19815
- * Balance validation follows the same rules as {@link Token.confidentialTransfer}.
19498
+ * Signer-independent: works without a configured signer.
19816
19499
  *
19817
- * @param to - Recipient address. Must implement the ERC-7984 receiver hook.
19818
- * @param amount - Plaintext amount to transfer (encrypted automatically via FHE).
19819
- * @param data - Opaque bytes forwarded to the recipient's receiver hook.
19820
- * @param options - Optional: `skipBalanceCheck` (default `false`).
19821
- * @returns The transaction hash and mined receipt.
19500
+ * @param contractAddress - The confidential contract address.
19501
+ * @param delegatorAddress - The address that granted the delegation.
19502
+ * @param delegateAddress - The address that received delegation rights.
19503
+ * @returns Unix timestamp as bigint. `0n` = no delegation. `2^64 - 1` = permanent.
19504
+ */
19505
+ getExpiry(params: {
19506
+ contractAddress: Address;
19507
+ delegatorAddress: Address;
19508
+ delegateAddress: Address;
19509
+ }): Promise<bigint>;
19510
+ /**
19511
+ * Get activity and expiry together in a single on-chain read, instead of
19512
+ * calling {@link isActive} and {@link getExpiry} separately.
19822
19513
  *
19823
- * @throws if signer and provider are on different chains. {@link ChainMismatchError}
19824
- * @throws if the balance is less than `amount`. {@link InsufficientConfidentialBalanceError}
19825
- * @throws if balance validation requires decryption that is not possible. {@link BalanceCheckUnavailableError}
19826
- * @throws if FHE encryption fails. {@link EncryptionFailedError}
19827
- * @throws if the on-chain transfer reverts. {@link TransactionRevertedError}
19514
+ * Signer-independent: works without a configured signer.
19828
19515
  *
19829
- * @example
19830
- * ```ts
19831
- * const txHash = await token.confidentialTransferAndCall(
19832
- * "0xRecipient",
19833
- * 1000n,
19834
- * "0xabcd", // caller-encoded payload forwarded to the receiver hook
19835
- * );
19836
- * ```
19516
+ * @param contractAddress - The confidential contract address.
19517
+ * @param delegatorAddress - The address that granted the delegation.
19518
+ * @param delegateAddress - The address that received delegation rights.
19519
+ * @returns `{ isActive, expiryTimestamp }` — activity and the raw expiry timestamp together.
19837
19520
  */
19838
- confidentialTransferAndCall(to: Address, amount: bigint, data: Hex, options?: TransferOptions): Promise<TransactionResult>;
19521
+ getStatus(params: {
19522
+ contractAddress: Address;
19523
+ delegatorAddress: Address;
19524
+ delegateAddress: Address;
19525
+ }): Promise<DelegationStatus>;
19526
+ }
19527
+ //#endregion
19528
+ //#region src/namespaces/permits.d.ts
19529
+ /**
19530
+ * Public namespace for permit and transport-key-pair management.
19531
+ *
19532
+ * Exposed as `sdk.permits`. Owns the SDK-level guards (chain alignment, empty-array
19533
+ * short-circuit, decrypt-cache invalidation) and delegates the actual work to the
19534
+ * internal {@link CredentialService}.
19535
+ *
19536
+ * The namespace is named `permits` because the user-facing concept is the signed-permit
19537
+ * store. The transport key pair is invisible plumbing — there is no `getTransportKeyPair()`
19538
+ * surfaced; the key pair exists to sign permits and is created automatically when needed.
19539
+ * {@link clear} wipes both the permit store and the transport key pair (permits
19540
+ * cascade-delete with the key pair).
19541
+ *
19542
+ * When `transportKeyPairScope` is configured (opt-in shared-tenant scope for B2B2C/WaaS
19543
+ * operators), {@link clear} and {@link revokePermits} stay signer-level only — they never
19544
+ * touch the shared key pair. {@link revokeTransportKeyPair} is the distinct,
19545
+ * operator-level operation for that.
19546
+ */
19547
+ declare class Permits {
19548
+ #private;
19839
19549
  /**
19840
- * ERC-7984 `confidentialTransferFromAndCall`: operator-initiated encrypted
19841
- * transfer that also invokes the recipient's receiver hook in a single
19842
- * transaction. The caller must be an approved operator for `from` and crafts
19843
- * the opaque `data` payload — the SDK does not encode or interpret it.
19550
+ * Sign and store an EIP-712 permit authorising direct decryption for the
19551
+ * given contract addresses.
19844
19552
  *
19845
- * @param from - The address to transfer from (caller must be an approved operator).
19846
- * @param to - Recipient address. Must implement the ERC-7984 receiver hook.
19847
- * @param amount - Plaintext amount to transfer (encrypted automatically via FHE).
19848
- * @param data - Opaque bytes forwarded to the recipient's receiver hook.
19849
- * @param callbacks - Optional progress callbacks.
19850
- * @returns The transaction hash and mined receipt.
19553
+ * Idempotent: if a permit covering the requested set already exists, no
19554
+ * wallet prompt occurs. Otherwise the SDK chunks the uncovered subset into
19555
+ * groups of ≤10 contracts and prompts once per chunk; partial mid-flight
19556
+ * rejection is preserved (already-signed chunks are persisted before the
19557
+ * next prompt).
19851
19558
  *
19852
- * @example
19853
- * ```ts
19854
- * const txHash = await token.confidentialTransferFromAndCall(
19855
- * "0xFrom",
19856
- * "0xRecipient",
19857
- * 500n,
19858
- * "0xabcd",
19859
- * );
19860
- * ```
19559
+ * @param contracts - Contract addresses to authorize.
19861
19560
  */
19862
- confidentialTransferFromAndCall(from: Address, to: Address, amount: bigint, data: Hex, callbacks?: TransferCallbacks): Promise<TransactionResult>;
19561
+ grantPermit(contracts: Address[]): Promise<void>;
19863
19562
  /**
19864
- * Set operator approval for the confidential token.
19865
- * Defaults to 1 hour from now if `until` is not specified.
19563
+ * Sign and store an EIP-712 delegation permit authorising decryption on
19564
+ * behalf of `delegator`. Same idempotence/chunking semantics as {@link grantPermit}.
19866
19565
  *
19867
- * @param operator - The address to set as an operator.
19868
- * @param until - Optional Unix timestamp for approval expiry. Defaults to now + 1 hour.
19869
- * @returns The transaction hash and mined receipt.
19566
+ * @param delegator - The address that delegated decryption rights to the connected signer.
19567
+ * @param contracts - Contract addresses to authorize.
19568
+ */
19569
+ grantDelegationPermit(delegator: Address, contracts: Address[]): Promise<void>;
19570
+ /**
19571
+ * Pure store lookup: is there a permit covering `contracts`?
19572
+ * No wallet prompt, no transport key pair generation. Returns `false` when no signer
19573
+ * is configured.
19574
+ */
19575
+ hasPermit(contracts: Address[]): Promise<boolean>;
19576
+ /**
19577
+ * Pure store lookup for a delegation permit. See {@link hasPermit}.
19578
+ *
19579
+ * @param delegator - The address that delegated decryption rights to the connected signer.
19580
+ * @param contracts - Contract addresses to check.
19581
+ * @returns `true` if cached delegation permits cover all requested contracts.
19582
+ */
19583
+ hasDelegationPermit(delegator: Address, contracts: Address[]): Promise<boolean>;
19584
+ /**
19585
+ * Best-effort transport-key-pair prefetch for the connected signer.
19586
+ *
19587
+ * Optional latency optimization: decrypt and permit flows remain correct
19588
+ * without it because they lazily create the transport key pair when needed.
19589
+ *
19590
+ * Silent no-op when no signer is configured or no wallet account is
19591
+ * available. The transport key pair is generated through the relayer dispatcher's
19592
+ * currently active chain — see {@link LifecycleService}, which calls
19593
+ * `switchChain` before fanning the wallet-account change out to listeners,
19594
+ * so any downstream caller (including React adapters) observes the
19595
+ * dispatcher on the wallet chain by the time it invokes warmup.
19870
19596
  *
19871
- * @example
19872
- * ```ts
19873
- * const txHash = await token.setOperator("0xOperator");
19874
- * ```
19597
+ * Not for pre-warming a shared `transportKeyPairScope`: this call's wallet-account
19598
+ * precondition doesn't conceptually apply to a scope-wide key, and would silently
19599
+ * no-op precisely when an operator is most likely to be calling it (no end-user
19600
+ * connected yet). Use {@link warmTransportKeyPairScope} instead.
19875
19601
  */
19876
- setOperator(operator: Address, until?: number): Promise<TransactionResult>;
19602
+ warmTransportKeyPair(): Promise<void>;
19877
19603
  /**
19878
- * Check if a spender is an approved operator for a given holder.
19604
+ * Wipe FHE permits for the current signer.
19879
19605
  *
19880
- * @param holder - The token holder address.
19881
- * @param spender - The address to check operator approval for.
19882
- * @returns `true` if the spender is an approved operator for the holder.
19606
+ * - With no argument: every permit referencing this signer is removed across
19607
+ * all chains and delegators. The transport key pair survives — use {@link clear} to
19608
+ * also wipe the transport key pair.
19609
+ * - With a contract list: every signed permit in the direct-decrypt scope
19610
+ * (current chain) whose immutable payload touches any listed address is
19611
+ * removed. Delegation permits are not touched in this mode.
19883
19612
  *
19884
- * @example
19885
- * ```ts
19886
- * if (await token.isOperator("0xHolder", "0xSpender")) {
19887
- * // spender can call transferFrom on behalf of holder
19888
- * }
19889
- * ```
19613
+ * @throws if no signer is configured. {@link SignerNotConfiguredError}
19890
19614
  */
19891
- isOperator(holder: Address, spender: Address): Promise<boolean>;
19615
+ revokePermits(contracts?: Address[]): Promise<void>;
19892
19616
  /**
19893
- * Read the on-chain encrypted balance for a given owner.
19617
+ * Wipe the transport key pair for the current signer and cascade-delete every permit
19618
+ * (across chains and delegators) referencing it.
19894
19619
  *
19895
- * @internal
19620
+ * @throws if no signer is configured. {@link SignerNotConfiguredError}
19896
19621
  */
19897
- protected readConfidentialBalanceOf(owner: Address): Promise<EncryptedValue>;
19622
+ clear(): Promise<void>;
19898
19623
  /**
19899
- * Pre-flight check: decrypt the confidential balance and compare against the
19900
- * requested amount. If credentials are cached the decrypt happens silently;
19901
- * if not, throws {@link BalanceCheckUnavailableError} instead of triggering
19902
- * a surprise EIP-712 popup.
19624
+ * Revoke the shared transport key pair for `transportKeyPairScope` (operator-level
19625
+ * action — no wallet account needs to be connected, but a signer must still be
19626
+ * configured on this SDK instance at construction time).
19627
+ *
19628
+ * Deletes the shared key pair; every permit in the scope embeds its public key, so
19629
+ * they're all treated as stale on next access. Signer-level {@link clear} never does
19630
+ * this — it only ever wipes the calling signer's own permits.
19631
+ *
19632
+ * Not best-effort, unlike most credential-store writes: a storage failure rejects
19633
+ * instead of being logged and swallowed. This is the primitive an operator reaches
19634
+ * for on suspected key compromise — a resolved promise must mean the key pair is
19635
+ * actually gone.
19636
+ *
19637
+ * Stops the SDK from reissuing or reusing the deleted key — does not revoke any
19638
+ * permit already issued under it. A permit is a self-contained, bearer-style EIP-712
19639
+ * signature the relayer accepts independently of this SDK; one exfiltrated alongside
19640
+ * the key remains usable until its own `permitTTL` expiry regardless of this call.
19903
19641
  *
19904
- * @internal
19642
+ * @param scopeId - Must match the configured `transportKeyPairScope`, as a guard
19643
+ * against revoking the wrong scope by mistake.
19644
+ * @throws if no signer is configured. {@link SignerNotConfiguredError}
19645
+ * @throws if no scope is configured, or `scopeId` doesn't match it. {@link ConfigurationError}
19646
+ * @throws if the underlying storage delete fails.
19905
19647
  */
19906
- protected assertConfidentialBalance(amount: bigint): Promise<void>;
19648
+ revokeTransportKeyPair(scopeId: string): Promise<void>;
19907
19649
  /**
19908
- * Emit a token-scoped event through the owning {@link ZamaSDK} so that
19909
- * subscribers see a unified stream.
19650
+ * Warm the shared transport key pair for `transportKeyPairScope` (operator-level —
19651
+ * no wallet account needs to be connected, but a signer must still be configured on
19652
+ * this SDK instance at construction time) — the pre-warm counterpart to
19653
+ * {@link revokeTransportKeyPair}. Prefer this over {@link warmTransportKeyPair} for a
19654
+ * scoped key pair: unlike that method, this never silently no-ops for lack of a
19655
+ * connected wallet, because a scope-wide key was never tied to one in the first place.
19910
19656
  *
19911
- * @internal
19657
+ * @param scopeId - Must match the configured `transportKeyPairScope`, as a guard
19658
+ * against warming the wrong scope by mistake.
19659
+ * @throws if no signer is configured. {@link SignerNotConfiguredError}
19660
+ * @throws if no scope is configured, or `scopeId` doesn't match it. {@link ConfigurationError}
19912
19661
  */
19913
- protected emit(input: ZamaSDKEventInput): void;
19662
+ warmTransportKeyPairScope(scopeId: string): Promise<void>;
19663
+ }
19664
+ //#endregion
19665
+ //#region src/token/token.d.ts
19666
+ /** Options for {@link Token.batchDecryptBalancesAs}. */
19667
+ interface BatchDecryptAsOptions {
19668
+ /** The address of the account that delegated decryption rights. */
19669
+ delegatorAddress: Address;
19670
+ /** Pre-fetched encrypted values. When omitted, they are fetched from the chain. */
19671
+ encryptedValues?: EncryptedValue[];
19914
19672
  /**
19915
- * Submit a token-scoped write transaction through the shared SDK transaction
19916
- * pipeline. Callers keep pre-flight and operation-specific work local.
19673
+ * The account whose on-chain balance to read. Defaults to the delegator
19674
+ * address, which is the common case (the delegator grants permission to
19675
+ * decrypt their own balance). Only set this when the account differs
19676
+ * from the delegator.
19917
19677
  *
19918
- * @internal
19678
+ * Matches the `account` parameter of `confidentialBalanceOf(account)` on-chain.
19919
19679
  */
19920
- protected submitTransaction(params: {
19921
- operation: TransactionOperation;
19922
- config: WriteContractConfig;
19923
- onSubmitted?: (txHash: Hex) => void;
19924
- }): Promise<TransactionResult>;
19925
- /** Verify all tokens share the same SDK instance and return it. */
19926
- private static assertSameSdk;
19680
+ accountAddress?: Address;
19681
+ /** Maximum number of concurrent decrypt calls. Default: 10. */
19682
+ maxConcurrency?: number;
19683
+ /** Called when decryption fails for a single token. Return a fallback bigint. */
19684
+ onError?: (error: Error, address: Address) => bigint;
19685
+ }
19686
+ /** Result of {@link Token.batchBalancesOf}. */
19687
+ interface BatchBalancesResult {
19688
+ /** Successfully decrypted balances, keyed by token address. */
19689
+ results: Map<Address, bigint>;
19690
+ /** Per-token errors for tokens that failed to decrypt. */
19691
+ errors: Map<Address, ZamaError>;
19927
19692
  }
19928
- //#endregion
19929
- //#region src/token/wrapped-token.d.ts
19930
19693
  /**
19931
- * Confidential ERC-20 wrapper (ERC-7984 ERC20Wrapper).
19694
+ * High-level interface for an ERC-7984 confidential token.
19695
+ * Hides FHE complexity (encryption, decryption, EIP-712 signing) behind
19696
+ * familiar ERC-20-like methods.
19932
19697
  *
19933
- * Extends {@link Token} with wrapper-specific operations:
19934
- * - `shield` / `unshield` — convert between the underlying ERC-20 and confidential balance
19935
- * - `unwrap` / `unwrapAll` / `finalizeUnwrap` — low-level two-phase primitives
19936
- * - `underlying` / `allowance` — wrapper reads
19698
+ * For ERC-7984 wrappers (shield/unshield), use {@link WrappedToken} instead —
19699
+ * it extends `Token` with wrapper-specific operations.
19937
19700
  *
19938
- * `WrappedToken.address` is the wrapper contract address itself — the wrapper
19939
- * IS the confidential token.
19701
+ * Decryption, credentials, caching, and event emission are handled by the
19702
+ * owning {@link ZamaSDK} — this class only exposes token-scoped helpers
19703
+ * that delegate to `sdk.decryption.decryptValues` and `sdk.permits.grantPermit`.
19940
19704
  */
19941
- declare class WrappedToken extends Token {
19705
+ declare class Token {
19942
19706
  #private;
19707
+ /** The SDK instance this token operates through. */
19708
+ readonly sdk: ZamaSDK;
19709
+ /** Checksummed address of the confidential token contract. */
19710
+ readonly address: Address;
19711
+ constructor(sdk: ZamaSDK, address: Address);
19712
+ /** Read the token name from the contract. */
19713
+ name(): Promise<string>;
19714
+ /** Read the token symbol from the contract. */
19715
+ symbol(): Promise<string>;
19716
+ /** Read the token decimals from the contract. */
19717
+ decimals(): Promise<number>;
19943
19718
  /**
19944
- * Read the underlying ERC-20 token address from the wrapper contract.
19945
- *
19946
- * @returns The underlying ERC-20 token address.
19947
- */
19948
- underlying(): Promise<Address>;
19949
- /**
19950
- * Check whether the underlying ERC-20 supports ERC-1363 (payable token).
19951
- * Result is cached per WrappedToken instance (negative results included):
19952
- * once we know an underlying does not support ERC-1363, subsequent shields
19953
- * go straight to the `approve` + `wrap` path without re-probing.
19954
- */
19955
- isPayable(): Promise<boolean>;
19956
- /**
19957
- * Read the ERC-20 allowance granted by `owner` to this wrapper for the
19958
- * underlying token.
19719
+ * ERC-165 check for {@link ERC7984_INTERFACE_ID} support.
19959
19720
  *
19960
- * @param owner - The owner address whose allowance to read.
19961
- * @returns The current allowance as a bigint.
19721
+ * @returns `true` if the contract implements the ERC-7984 confidential token interface.
19962
19722
  */
19963
- allowance(owner: Address): Promise<bigint>;
19723
+ isConfidential(): Promise<boolean>;
19964
19724
  /**
19965
- * Shield public ERC-20 tokens into confidential tokens.
19966
- *
19967
- * The execution path is decided automatically by ERC-165 introspection on
19968
- * the underlying ERC-20:
19969
- * - **`transferAndCall`** (single tx): when the underlying supports
19970
- * ERC-1363, no approval is required — the wrapper's `onTransferReceived`
19971
- * callback mints confidential tokens directly. `approvalStrategy` is
19972
- * **ignored** on this path. See {@link ShieldPath}.
19973
- * - **`approveAndWrap`** (two-tx fallback): otherwise, an `approve` is
19974
- * followed by a `wrap`. Approval is controlled by `approvalStrategy`
19975
- * (`"exact"` by default, `"max"` for unlimited, `"skip"` to opt out).
19976
- *
19977
- * The ERC-20 balance is validated before submitting (public read, no
19978
- * signing required) so the call works for all wallet types, including
19979
- * smart wallets.
19980
- *
19981
- * @param amount - The plaintext amount to shield.
19982
- * @param options - Optional: `approvalStrategy`, `to`, callbacks.
19983
- * @returns The transaction hash and mined receipt.
19984
- * @throws if signer and provider are on different chains. {@link ChainMismatchError}
19985
- * @throws if the ERC-20 balance is less than `amount`. {@link InsufficientERC20BalanceError}
19986
- * @throws if the ERC-20 approval or shield transaction reverts. {@link TransactionRevertedError}
19725
+ * ERC-165 check for IERC7984ERC20Wrapper support.
19987
19726
  *
19988
- * @example
19989
- * ```ts
19990
- * const txHash = await wrappedToken.shield(1000n);
19991
- * ```
19727
+ * @returns `true` if the contract implements the ERC-7984 wrapper interface
19728
+ * ({@link ERC7984_WRAPPER_INTERFACE_ID}, `0x1f1c62b2`).
19992
19729
  */
19993
- shield(amount: bigint, options?: ShieldOptions): Promise<TransactionResult>;
19730
+ isWrapper(): Promise<boolean>;
19994
19731
  /**
19995
- * Wrap already-approved underlying ERC-20 into confidential tokens.
19996
- *
19997
- * Escape hatch for splitting shield across two signatures: call
19998
- * {@link approveUnderlying} first, then `wrap`. Most callers should use
19999
- * {@link shield}, which routes and orchestrates approval automatically.
20000
- *
20001
- * Validates the ERC-20 balance and the allowance granted to this wrapper
20002
- * (public reads, no signing) and fails early with a clear error.
19732
+ * Decrypt and return the plaintext balance for the given owner.
19733
+ * Acquires FHE credentials via a wallet signature if none are cached.
20003
19734
  *
20004
- * @param amount - The plaintext amount to wrap.
20005
- * @param options - Optional `to` recipient and `onWrapSubmitted` callback.
20006
- * @returns The transaction hash and mined receipt.
20007
- * @throws if reading the ERC-20 balance or allowance fails. {@link ERC20ReadFailedError}
20008
- * @throws if the ERC-20 balance is less than `amount`. {@link InsufficientERC20BalanceError}
20009
- * @throws if the allowance granted to the wrapper is less than `amount`. {@link InsufficientAllowanceError}
19735
+ * @param owner - Balance owner address.
19736
+ * @returns The decrypted plaintext balance as a bigint.
19737
+ * @throws if FHE decryption fails. {@link DecryptionFailedError}
20010
19738
  *
20011
19739
  * @example
20012
19740
  * ```ts
20013
- * await wrappedToken.approveUnderlying(1000n);
20014
- * await wrappedToken.wrap(1000n);
19741
+ * const balance = await token.balanceOf("0xOwner");
20015
19742
  * ```
20016
19743
  */
20017
- wrap(amount: bigint, options?: WrapOptions): Promise<TransactionResult>;
19744
+ balanceOf(owner: Address): Promise<bigint>;
20018
19745
  /**
20019
- * Approve this wrapper contract to spend the underlying ERC-20.
20020
- * Defaults to max uint256. Resets to zero first if there's an existing
20021
- * non-zero allowance (required by tokens like USDT).
19746
+ * Return the raw encrypted balance without decrypting.
20022
19747
  *
20023
- * @param amount - Optional approval amount. Defaults to max uint256.
20024
- * @returns The transaction hash and mined receipt.
19748
+ * @param owner - Balance owner address.
19749
+ * @returns The encrypted balance as a hex string.
20025
19750
  *
20026
19751
  * @example
20027
19752
  * ```ts
20028
- * await wrappedToken.approveUnderlying(); // max approval
20029
- * await wrappedToken.approveUnderlying(1000n); // exact amount
19753
+ * const encryptedValue = await token.confidentialBalanceOf("0xOwner");
20030
19754
  * ```
20031
19755
  */
20032
- approveUnderlying(amount?: bigint): Promise<TransactionResult>;
19756
+ confidentialBalanceOf(owner: Address): Promise<EncryptedValue>;
20033
19757
  /**
20034
- * Unshield a specific amount and finalize in one call.
20035
- * Orchestrates: unshield → wait for receipt → parse event → finalize.
19758
+ * Decrypt the balance of a delegator using delegated decryption credentials.
19759
+ * The connected signer acts as the delegatee who has been granted permission
19760
+ * by the delegator to decrypt their balance.
20036
19761
  *
20037
- * By default, the SDK validates the confidential balance before submitting.
20038
- * Set `skipBalanceCheck: true` to bypass this validation (e.g. for smart wallets).
19762
+ * Clear values are cached in storage keyed by `(account, token, encryptedValue)`.
19763
+ * Because every on-chain balance change produces a new encrypted value,
19764
+ * stale cache entries are never served. Cache write failures are silently
19765
+ * ignored — they do not affect the returned value.
20039
19766
  *
20040
- * @param amount - The plaintext amount to unshield.
20041
- * @param options - Optional: `skipBalanceCheck` (default `false`), callbacks.
20042
- * @returns The finalize transaction hash and mined receipt.
19767
+ * @param delegatorAddress - The address of the account that delegated decryption rights.
19768
+ * @param accountAddress - The account whose on-chain balance to read. Defaults
19769
+ * to the delegator address.
19770
+ * @returns The decrypted plaintext balance as a bigint.
19771
+ * @throws if no active delegation exists. {@link DelegationNotFoundError}
19772
+ * @throws if the delegation has expired. {@link DelegationExpiredError}
19773
+ * @throws if delegated decryption fails. {@link DecryptionFailedError}
20043
19774
  *
20044
19775
  * @example
20045
19776
  * ```ts
20046
- * const txHash = await wrappedToken.unshield(500n);
19777
+ * const balance = await token.decryptBalanceAs({
19778
+ * delegatorAddress: "0xDelegator",
19779
+ * });
20047
19780
  * ```
20048
19781
  */
20049
- unshield(amount: bigint, options?: UnshieldOptions): Promise<TransactionResult>;
19782
+ decryptBalanceAs({ delegatorAddress, accountAddress }: {
19783
+ delegatorAddress: Address;
19784
+ accountAddress?: Address;
19785
+ }): Promise<bigint>;
20050
19786
  /**
20051
- * Unshield the entire balance and finalize in one call.
20052
- * Orchestrates: unshieldAll → wait for receipt → parse event → finalize.
19787
+ * Decrypt confidential balances for multiple tokens in parallel, returning
19788
+ * successes and per-token errors separately. Pre-authorizes all token
19789
+ * addresses in a single wallet signature, then delegates each decrypt to
19790
+ * `sdk.decryption.decryptValues`.
19791
+ *
19792
+ * Tokens that fail to decrypt land in `errors` rather than aborting the
19793
+ * whole batch — caller decides how to surface them.
20053
19794
  *
20054
- * @param callbacks - Optional progress callbacks for each phase.
20055
- * @returns The finalize transaction hash and mined receipt.
20056
- * @throws if the balance is zero. {@link DecryptionFailedError}
19795
+ * @param tokens - Array of {@link Token} instances bound to the same SDK.
19796
+ * @param owner - Balance owner address.
19797
+ * @returns `{ results, errors }` partitioning the per-token outcomes.
20057
19798
  *
20058
19799
  * @example
20059
19800
  * ```ts
20060
- * const txHash = await wrappedToken.unshieldAll();
19801
+ * const { results, errors } = await Token.batchBalancesOf(tokens, owner);
20061
19802
  * ```
20062
19803
  */
20063
- unshieldAll(callbacks?: UnshieldCallbacks): Promise<TransactionResult>;
19804
+ static batchBalancesOf(tokens: Token[], owner: Address): Promise<BatchBalancesResult>;
20064
19805
  /**
20065
- * Resume an in-progress unshield from an existing unwrap tx hash.
20066
- * Useful when the user already submitted the unwrap but the finalize step
20067
- * was interrupted (e.g. page reload, network error).
19806
+ * Batch decrypt confidential balances as a delegate across multiple tokens.
19807
+ * Mirrors {@link batchBalancesOf} but uses delegated credentials.
20068
19808
  *
20069
- * @param unwrapTxHash - The transaction hash of the previously submitted unwrap.
20070
- * @param callbacks - Optional progress callbacks.
20071
- * @returns The finalize transaction hash and mined receipt.
19809
+ * **Error handling:** If a per-token decryption fails and no `onError` callback
19810
+ * is provided, errors are collected and thrown as an aggregated
19811
+ * `DecryptionFailedError`. When the relayer returns no value for an encrypted value,
19812
+ * a `DecryptionFailedError` is thrown for that token (never silently returns `0n`).
19813
+ * Pass `onError: () => 0n` to opt into the silent zero behavior.
19814
+ *
19815
+ * @param tokens - Array of Token instances to decrypt balances for.
19816
+ * @param options - Delegated decryption configuration.
19817
+ * @returns A Map from token address to decrypted balance.
19818
+ * @throws if no active delegation exists. {@link DelegationNotFoundError}
19819
+ * @throws if the delegation has expired. {@link DelegationExpiredError}
19820
+ * @throws if any decryption fails and no `onError` is provided. {@link DecryptionFailedError}
20072
19821
  *
20073
19822
  * @example
20074
19823
  * ```ts
20075
- * const txHash = await wrappedToken.resumeUnshield(previousUnwrapTxHash);
19824
+ * const balances = await Token.batchDecryptBalancesAs(tokens, {
19825
+ * delegatorAddress: "0xDelegator",
19826
+ * onError: (err, addr) => { console.error(addr, err); return 0n; },
19827
+ * });
20076
19828
  * ```
20077
19829
  */
20078
- resumeUnshield(unwrapTxHash: Hex, callbacks?: UnshieldCallbacks): Promise<TransactionResult>;
19830
+ static batchDecryptBalancesAs(tokens: Token[], options: BatchDecryptAsOptions): Promise<Map<Address, bigint>>;
19831
+ private static readBalanceHandlesBatch;
20079
19832
  /**
20080
- * Return the unwrap tx hash of an unshield that was interrupted between its
20081
- * two phases, or `null` if none is pending for this wrapper.
19833
+ * Confidential transfer. Encrypts the amount via FHE, then calls the contract.
20082
19834
  *
20083
- * The SDK persists this automatically when {@link unshield}/{@link unshieldAll}
20084
- * submit phase 1, and clears it once phase 2 finalizes. Use the returned hash
20085
- * to surface a "resume" affordance, then pass it to {@link resumeUnshield}.
20086
- * Resuming is intentionally caller-driven — auto-resuming on load would fire a
20087
- * wallet transaction unprompted.
19835
+ * By default, the SDK validates the confidential balance before submitting.
19836
+ * If a cached plaintext balance exists it is used; otherwise, if credentials
19837
+ * are cached, it decrypts on the fly. Set `skipBalanceCheck: true` to bypass
19838
+ * this validation (e.g. for smart wallets).
20088
19839
  *
20089
- * @returns The pending unwrap tx hash, or `null`.
19840
+ * @param to - Recipient address.
19841
+ * @param amount - Plaintext amount to transfer (encrypted automatically via FHE).
19842
+ * @param options - Optional: `skipBalanceCheck` (default `false`).
19843
+ * @returns The transaction hash and mined receipt.
19844
+ * @throws if signer and provider are on different chains. {@link ChainMismatchError}
19845
+ * @throws if the balance is less than `amount`. {@link InsufficientConfidentialBalanceError}
19846
+ * @throws if balance validation requires decryption that is not possible. {@link BalanceCheckUnavailableError}
19847
+ * @throws if FHE encryption fails. {@link EncryptionFailedError}
19848
+ * @throws if the on-chain transfer reverts. {@link TransactionRevertedError}
20090
19849
  *
20091
19850
  * @example
20092
19851
  * ```ts
20093
- * const unwrapTxHash = await wrappedToken.getPendingUnshield();
20094
- * if (unwrapTxHash) await wrappedToken.resumeUnshield(unwrapTxHash);
19852
+ * const txHash = await token.confidentialTransfer("0xRecipient", 1000n);
20095
19853
  * ```
20096
19854
  */
20097
- getPendingUnshield(): Promise<Hex | null>;
19855
+ confidentialTransfer(to: Address, amount: bigint, options?: TransferOptions): Promise<TransactionResult>;
20098
19856
  /**
20099
- * Request an unwrap for a specific amount. Encrypts the amount first.
20100
- * Pass the result's `unwrapRequestId` to {@link finalizeUnwrap} once the
20101
- * request is processed on-chain.
19857
+ * Operator encrypted transfer on behalf of another address.
19858
+ * The caller must be an approved operator for `from`.
20102
19859
  *
20103
- * @param amount - The plaintext amount to unwrap (encrypted automatically).
20104
- * @returns The tx hash, mined receipt, and the `unwrapRequestId` for `finalizeUnwrap`.
19860
+ * @param from - The address to transfer from (caller must be an approved operator).
19861
+ * @param to - Recipient address.
19862
+ * @param amount - Plaintext amount to transfer (encrypted automatically via FHE).
19863
+ * @returns The transaction hash and mined receipt.
20105
19864
  *
20106
19865
  * @example
20107
19866
  * ```ts
20108
- * const result = await wrappedToken.unwrap(500n);
20109
- * await wrappedToken.finalizeUnwrap(result.unwrapRequestId);
19867
+ * const txHash = await token.confidentialTransferFrom("0xFrom", "0xTo", 500n);
20110
19868
  * ```
20111
19869
  */
20112
- unwrap(amount: bigint): Promise<UnwrapResult>;
19870
+ confidentialTransferFrom(from: Address, to: Address, amount: bigint, callbacks?: TransferCallbacks): Promise<TransactionResult>;
20113
19871
  /**
20114
- * Request an unwrap for the entire confidential balance.
20115
- * Uses the on-chain encrypted balance directly (no encryption needed).
20116
- * Throws if the balance is zero.
19872
+ * ERC-7984 `confidentialTransferAndCall`: encrypted transfer that also invokes
19873
+ * the recipient's receiver hook (`onConfidentialTransferReceived`) in a single
19874
+ * transaction. The caller crafts the opaque `data` payload — the SDK does not
19875
+ * encode, validate, or interpret it.
20117
19876
  *
20118
- * @returns The tx hash, mined receipt, and the `unwrapRequestId` for `finalizeUnwrap`.
20119
- * @throws if the balance is zero. {@link DecryptionFailedError}
19877
+ * Balance validation follows the same rules as {@link Token.confidentialTransfer}.
19878
+ *
19879
+ * @param to - Recipient address. Must implement the ERC-7984 receiver hook.
19880
+ * @param amount - Plaintext amount to transfer (encrypted automatically via FHE).
19881
+ * @param data - Opaque bytes forwarded to the recipient's receiver hook.
19882
+ * @param options - Optional: `skipBalanceCheck` (default `false`).
19883
+ * @returns The transaction hash and mined receipt.
19884
+ *
19885
+ * @throws if signer and provider are on different chains. {@link ChainMismatchError}
19886
+ * @throws if the balance is less than `amount`. {@link InsufficientConfidentialBalanceError}
19887
+ * @throws if balance validation requires decryption that is not possible. {@link BalanceCheckUnavailableError}
19888
+ * @throws if FHE encryption fails. {@link EncryptionFailedError}
19889
+ * @throws if the on-chain transfer reverts. {@link TransactionRevertedError}
20120
19890
  *
20121
19891
  * @example
20122
19892
  * ```ts
20123
- * const result = await wrappedToken.unwrapAll();
20124
- * await wrappedToken.finalizeUnwrap(result.unwrapRequestId);
19893
+ * const txHash = await token.confidentialTransferAndCall(
19894
+ * "0xRecipient",
19895
+ * 1000n,
19896
+ * "0xabcd", // caller-encoded payload forwarded to the receiver hook
19897
+ * );
20125
19898
  * ```
20126
19899
  */
20127
- unwrapAll(): Promise<UnwrapResult>;
19900
+ confidentialTransferAndCall(to: Address, amount: bigint, data: Hex, options?: TransferOptions): Promise<TransactionResult>;
20128
19901
  /**
20129
- * Complete an unwrap by fetching the public decryption proof and finalizing.
20130
- * Call this once the unwrap request has been processed on-chain.
19902
+ * ERC-7984 `confidentialTransferFromAndCall`: operator-initiated encrypted
19903
+ * transfer that also invokes the recipient's receiver hook in a single
19904
+ * transaction. The caller must be an approved operator for `from` and crafts
19905
+ * the opaque `data` payload — the SDK does not encode or interpret it.
20131
19906
  *
20132
- * @param unwrapRequestId - The `unwrapRequestId` from an {@link UnwrapResult}
20133
- * (`result.unwrapRequestId`) returned by {@link unwrap} / {@link unwrapAll},
20134
- * or one decoded from an `UnwrapRequested` event (e.g. when finalizing
20135
- * across sessions).
19907
+ * @param from - The address to transfer from (caller must be an approved operator).
19908
+ * @param to - Recipient address. Must implement the ERC-7984 receiver hook.
19909
+ * @param amount - Plaintext amount to transfer (encrypted automatically via FHE).
19910
+ * @param data - Opaque bytes forwarded to the recipient's receiver hook.
19911
+ * @param callbacks - Optional progress callbacks.
20136
19912
  * @returns The transaction hash and mined receipt.
20137
19913
  *
20138
19914
  * @example
20139
19915
  * ```ts
20140
- * const { unwrapRequestId } = await wrappedToken.unwrap(500n);
20141
- * await wrappedToken.finalizeUnwrap(unwrapRequestId);
19916
+ * const txHash = await token.confidentialTransferFromAndCall(
19917
+ * "0xFrom",
19918
+ * "0xRecipient",
19919
+ * 500n,
19920
+ * "0xabcd",
19921
+ * );
20142
19922
  * ```
20143
19923
  */
20144
- finalizeUnwrap(unwrapRequestId: EncryptedValue): Promise<TransactionResult>;
20145
- }
20146
- //#endregion
20147
- //#region src/query/confidential-balance.d.ts
20148
- interface ConfidentialBalanceQueryConfig {
20149
- tokenAddress: Address;
20150
- account?: Address;
20151
- query?: Record<string, unknown>;
20152
- }
20153
- /** Query options for a single confidential token balance. Auto-gated on `account`. */
20154
- declare function confidentialBalanceQueryOptions(token: Token, config: ConfidentialBalanceQueryConfig, signerContext?: SignerQueryContext): QueryFactoryOptions<bigint, Error, bigint, ReturnType<typeof zamaQueryKeys.confidentialBalance.owner>>;
20155
- //#endregion
20156
- //#region src/query/confidential-balances.d.ts
20157
- interface ConfidentialBalancesQueryConfig {
20158
- account?: Address;
20159
- query?: Record<string, unknown>;
20160
- }
20161
- declare function confidentialBalancesQueryOptions(tokens: Token[], config?: ConfidentialBalancesQueryConfig, signerContext?: SignerQueryContext): QueryFactoryOptions<BatchBalancesResult, Error, BatchBalancesResult, ReturnType<typeof zamaQueryKeys.confidentialBalances.tokens>>;
20162
- //#endregion
20163
- //#region src/query/wrappers-registry.d.ts
20164
- interface WrappersRegistryQueryConfig {
20165
- registryAddress: Address | undefined;
20166
- query?: Record<string, unknown>;
20167
- }
20168
- declare function tokenPairsQueryOptions(sdk: ZamaSDK, config: WrappersRegistryQueryConfig): QueryFactoryOptions<readonly TokenWrapperPair[], Error, readonly TokenWrapperPair[], ReturnType<typeof zamaQueryKeys.wrappersRegistry.tokenPairs>>;
20169
- interface ConfidentialTokenAddressQueryConfig extends WrappersRegistryQueryConfig {
20170
- tokenAddress?: Address;
20171
- }
20172
- declare function confidentialTokenAddressQueryOptions(sdk: ZamaSDK, config: ConfidentialTokenAddressQueryConfig): QueryFactoryOptions<readonly [boolean, Address], Error, readonly [boolean, Address], ReturnType<typeof zamaQueryKeys.wrappersRegistry.confidentialTokenAddress>>;
20173
- interface TokenAddressQueryConfig extends WrappersRegistryQueryConfig {
20174
- confidentialTokenAddress?: Address;
20175
- }
20176
- declare function tokenAddressQueryOptions(sdk: ZamaSDK, config: TokenAddressQueryConfig): QueryFactoryOptions<readonly [boolean, Address], Error, readonly [boolean, Address], ReturnType<typeof zamaQueryKeys.wrappersRegistry.tokenAddress>>;
20177
- declare function tokenPairsLengthQueryOptions(sdk: ZamaSDK, config: WrappersRegistryQueryConfig): QueryFactoryOptions<bigint, Error, bigint, ReturnType<typeof zamaQueryKeys.wrappersRegistry.tokenPairsLength>>;
20178
- interface TokenPairsSliceQueryConfig extends WrappersRegistryQueryConfig {
20179
- fromIndex?: bigint;
20180
- toIndex?: bigint;
20181
- }
20182
- declare function tokenPairsSliceQueryOptions(sdk: ZamaSDK, config: TokenPairsSliceQueryConfig): QueryFactoryOptions<readonly TokenWrapperPair[], Error, readonly TokenWrapperPair[], ReturnType<typeof zamaQueryKeys.wrappersRegistry.tokenPairsSlice>>;
20183
- interface TokenPairQueryConfig extends WrappersRegistryQueryConfig {
20184
- index?: bigint;
20185
- }
20186
- declare function tokenPairQueryOptions(sdk: ZamaSDK, config: TokenPairQueryConfig): QueryFactoryOptions<TokenWrapperPair, Error, TokenWrapperPair, ReturnType<typeof zamaQueryKeys.wrappersRegistry.tokenPair>>;
20187
- interface IsConfidentialTokenValidQueryConfig extends WrappersRegistryQueryConfig {
20188
- confidentialTokenAddress?: Address;
20189
- }
20190
- declare function isConfidentialTokenValidQueryOptions(sdk: ZamaSDK, config: IsConfidentialTokenValidQueryConfig): QueryFactoryOptions<boolean, Error, boolean, ReturnType<typeof zamaQueryKeys.wrappersRegistry.isConfidentialTokenValid>>;
20191
- interface ListPairsQueryConfig {
20192
- /**
20193
- * The registry address for this chain — used as a query key discriminator.
20194
- * The registry instance already knows how to resolve the address for the
20195
- * current chain; this field just keeps the TanStack Query cache isolated
20196
- * per registry contract.
20197
- */
20198
- registryAddress: Address | undefined;
20199
- page?: number;
20200
- pageSize?: number;
20201
- metadata?: boolean;
20202
- query?: Record<string, unknown>;
20203
- }
20204
- /**
20205
- * Query options for paginated listing of token wrapper pairs.
20206
- *
20207
- * Accepts a {@link WrappersRegistry} instance rather than a raw provider so that the
20208
- * class-level TTL cache is shared across multiple `queryFn` executions. Pass
20209
- * `sdk.registry` (the ZamaSDK lazy singleton) to ensure a single shared cache.
20210
- */
20211
- declare function listPairsQueryOptions(registry: WrappersRegistry, config: ListPairsQueryConfig): QueryFactoryOptions<PaginatedResult<TokenWrapperPair | TokenWrapperPairWithMetadata>, Error, PaginatedResult<TokenWrapperPair | TokenWrapperPairWithMetadata>, ReturnType<typeof zamaQueryKeys.wrappersRegistry.listPairs>>;
20212
- //#endregion
20213
- //#region src/query/shield.d.ts
20214
- /** Variables for {@link shieldMutationOptions}. */
20215
- interface ShieldParams extends ShieldOptions {
20216
- amount: bigint;
20217
- }
20218
- declare function shieldMutationOptions(token: WrappedToken): MutationFactoryOptions<readonly ["zama.shield", Address], ShieldParams, TransactionResult>;
20219
- //#endregion
20220
- //#region src/query/transfer.d.ts
20221
- /** Variables for {@link confidentialTransferMutationOptions}. */
20222
- interface ConfidentialTransferParams extends TransferOptions {
20223
- to: Address;
20224
- amount: bigint;
20225
- }
20226
- declare function confidentialTransferMutationOptions(token: Token): MutationFactoryOptions<readonly ["zama.confidentialTransfer", Address], ConfidentialTransferParams, TransactionResult>;
20227
- //#endregion
20228
- //#region src/query/transfer-and-call.d.ts
20229
- /** Variables for {@link confidentialTransferAndCallMutationOptions}. */
20230
- interface ConfidentialTransferAndCallParams extends TransferOptions {
20231
- to: Address;
20232
- amount: bigint;
20233
- /** Opaque bytes forwarded to the recipient's ERC-7984 receiver hook. */
20234
- data: Hex;
20235
- }
20236
- declare function confidentialTransferAndCallMutationOptions(token: Token): MutationFactoryOptions<readonly ["zama.confidentialTransferAndCall", Address], ConfidentialTransferAndCallParams, TransactionResult>;
20237
- //#endregion
20238
- //#region src/query/transfer-from.d.ts
20239
- /** Variables for {@link confidentialTransferFromMutationOptions}. */
20240
- interface ConfidentialTransferFromParams {
20241
- from: Address;
20242
- to: Address;
20243
- amount: bigint;
20244
- /** Optional progress callbacks for the multi-step transfer flow. */
20245
- callbacks?: TransferCallbacks;
20246
- }
20247
- declare function confidentialTransferFromMutationOptions(token: Token): MutationFactoryOptions<readonly ["zama.confidentialTransferFrom", Address], ConfidentialTransferFromParams, TransactionResult>;
20248
- //#endregion
20249
- //#region src/query/transfer-from-and-call.d.ts
20250
- /** Variables for {@link confidentialTransferFromAndCallMutationOptions}. */
20251
- interface ConfidentialTransferFromAndCallParams {
20252
- from: Address;
20253
- to: Address;
20254
- amount: bigint;
20255
- /** Opaque bytes forwarded to the recipient's ERC-7984 receiver hook. */
20256
- data: Hex;
20257
- /** Optional progress callbacks for the multi-step transfer flow. */
20258
- callbacks?: TransferCallbacks;
20259
- }
20260
- declare function confidentialTransferFromAndCallMutationOptions(token: Token): MutationFactoryOptions<readonly ["zama.confidentialTransferFromAndCall", Address], ConfidentialTransferFromAndCallParams, TransactionResult>;
20261
- //#endregion
20262
- //#region src/query/set-operator.d.ts
20263
- /** Variables for {@link confidentialSetOperatorMutationOptions}. */
20264
- interface ConfidentialSetOperatorParams {
20265
- operator: Address;
20266
- until?: number;
20267
- }
20268
- declare function confidentialSetOperatorMutationOptions(token: Token): MutationFactoryOptions<readonly ["zama.confidentialSetOperator", Address], ConfidentialSetOperatorParams, TransactionResult>;
20269
- //#endregion
20270
- //#region src/query/approve-underlying.d.ts
20271
- /** Variables for {@link approveUnderlyingMutationOptions}. */
20272
- interface ApproveUnderlyingParams {
20273
- amount?: bigint;
20274
- }
20275
- declare function approveUnderlyingMutationOptions(token: WrappedToken): MutationFactoryOptions<readonly ["zama.approveUnderlying", Address], ApproveUnderlyingParams, TransactionResult>;
20276
- //#endregion
20277
- //#region src/query/unshield.d.ts
20278
- /** Variables for {@link unshieldMutationOptions}. */
20279
- interface UnshieldParams extends UnshieldOptions {
20280
- amount: bigint;
20281
- }
20282
- declare function unshieldMutationOptions(token: WrappedToken): MutationFactoryOptions<readonly ["zama.unshield", Address], UnshieldParams, TransactionResult>;
20283
- //#endregion
20284
- //#region src/query/unshield-all.d.ts
20285
- /** Variables for {@link unshieldAllMutationOptions}. */
20286
- interface UnshieldAllParams extends UnshieldCallbacks {}
20287
- declare function unshieldAllMutationOptions(token: WrappedToken): MutationFactoryOptions<readonly ["zama.unshieldAll", Address], UnshieldAllParams | void, TransactionResult>;
20288
- //#endregion
20289
- //#region src/query/resume-unshield.d.ts
20290
- /** Variables for {@link resumeUnshieldMutationOptions}. */
20291
- interface ResumeUnshieldParams extends UnshieldCallbacks {
20292
- unwrapTxHash: Hex;
20293
- }
20294
- declare function resumeUnshieldMutationOptions(token: WrappedToken): MutationFactoryOptions<readonly ["zama.resumeUnshield", Address], ResumeUnshieldParams, TransactionResult>;
20295
- //#endregion
20296
- //#region src/query/unwrap.d.ts
20297
- /** Variables for {@link unwrapMutationOptions}. */
20298
- interface UnwrapParams {
20299
- amount: bigint;
20300
- }
20301
- declare function unwrapMutationOptions(token: WrappedToken): MutationFactoryOptions<readonly ["zama.unwrap", Address], UnwrapParams, UnwrapResult>;
20302
- //#endregion
20303
- //#region src/query/wrap.d.ts
20304
- /** Variables for {@link wrapMutationOptions}. */
20305
- interface WrapParams extends WrapOptions {
20306
- amount: bigint;
20307
- }
20308
- declare function wrapMutationOptions(token: WrappedToken): MutationFactoryOptions<readonly ["zama.wrap", Address], WrapParams, TransactionResult>;
20309
- //#endregion
20310
- //#region src/query/unwrap-all.d.ts
20311
- declare function unwrapAllMutationOptions(token: WrappedToken): MutationFactoryOptions<readonly ["zama.unwrapAll", Address], void, UnwrapResult>;
20312
- //#endregion
20313
- //#region src/query/finalize-unwrap.d.ts
20314
- /** Variables for {@link finalizeUnwrapMutationOptions}. */
20315
- type FinalizeUnwrapParams = {
20316
- /** Identifier from an `UnwrapRequested` event. */
20317
- unwrapRequestId: EncryptedValue;
20318
- };
20319
- declare function finalizeUnwrapMutationOptions(token: WrappedToken): MutationFactoryOptions<readonly ["zama.finalizeUnwrap", Address], FinalizeUnwrapParams, TransactionResult>;
20320
- //#endregion
20321
- //#region src/query/encrypt.d.ts
20322
- declare function encryptMutationOptions(sdk: ZamaSDK): MutationFactoryOptions<readonly ["zama.encrypt"], EncryptParams, EncryptResult>;
20323
- //#endregion
20324
- //#region src/query/user-decrypt.d.ts
20325
- interface EncryptedInput {
20326
- encryptedValue: EncryptedValue;
20327
- contractAddress: Address;
20328
- }
20329
- /** Decrypted clear values keyed by encrypted handle. */
20330
- type DecryptResult = Readonly<Record<EncryptedValue, ClearValue>>;
20331
- declare function decryptValuesQueryOptions(sdk: ZamaSDK, encryptedInputs: EncryptedInput[], signerContext?: SignerQueryContext): QueryFactoryOptions<DecryptResult, Error, DecryptResult, ReturnType<typeof zamaQueryKeys.decryption.encryptedInputs>>;
20332
- //#endregion
20333
- //#region src/query/delegated-decrypt.d.ts
20334
- interface DelegatedDecryptValuesMutationParams {
20335
- encryptedInputs: EncryptedInput[];
20336
- delegatorAddress: Address;
20337
- }
20338
- declare function delegatedDecryptValuesMutationOptions(sdk: ZamaSDK): MutationFactoryOptions<readonly ["zama.delegatedDecryptValues"], DelegatedDecryptValuesMutationParams, Readonly<Record<EncryptedValue, ClearValue>>>;
20339
- //#endregion
20340
- //#region src/query/public-decrypt.d.ts
20341
- declare function decryptPublicValuesMutationOptions(sdk: ZamaSDK): MutationFactoryOptions<readonly ["zama.decryptPublicValues"], EncryptedValue[], DecryptPublicValuesResult>;
20342
- //#endregion
20343
- //#region src/query/grant-permit.d.ts
20344
- declare function grantPermitMutationOptions(sdk: ZamaSDK): MutationFactoryOptions<readonly ["zama.grantPermit"], Address[], void>;
20345
- //#endregion
20346
- //#region src/query/has-permit.d.ts
20347
- interface HasPermitQueryConfig {
20348
- /** Contract addresses to check credentials against. */
20349
- contractAddresses: Address[];
20350
- /**
20351
- * Standard TanStack query options. `hasPermit` intentionally overrides cache
20352
- * timing because permit state is wallet-local, not server state: every fetch
20353
- * should read the SDK credential service directly.
20354
- */
20355
- query?: Record<string, unknown>;
20356
- }
20357
- declare function hasPermitQueryOptions(sdk: ZamaSDK, config: HasPermitQueryConfig, signerContext?: SignerQueryContext): QueryFactoryOptions<boolean, Error, boolean, ReturnType<typeof zamaQueryKeys.hasPermit.scope>>;
20358
- //#endregion
20359
- //#region src/query/revoke-permits.d.ts
20360
- /** TanStack Query mutation factory for {@link Permits.revokePermits}. */
20361
- declare function revokePermitsMutationOptions(sdk: ZamaSDK): MutationFactoryOptions<readonly ["zama.revokePermits"], Address[] | void, void>;
20362
- //#endregion
20363
- //#region src/query/clear-credentials.d.ts
20364
- /** TanStack Query mutation factory for {@link Permits.clear}. */
20365
- declare function clearCredentialsMutationOptions(sdk: ZamaSDK): MutationFactoryOptions<readonly ["zama.clearCredentials"], void, void>;
20366
- //#endregion
20367
- //#region src/query/delegate-decryption.d.ts
20368
- /** Variables for {@link delegateDecryptionMutationOptions}. */
20369
- interface DelegateDecryptionParams {
20370
- delegateAddress: Address;
20371
- expirationDate?: Date;
20372
- }
20373
- declare function delegateDecryptionMutationOptions(sdk: ZamaSDK, contractAddress: Address): MutationFactoryOptions<readonly ["zama.delegateDecryption", Address], DelegateDecryptionParams, TransactionResult>;
20374
- //#endregion
20375
- //#region src/query/decrypt-balance-as.d.ts
20376
- /** Variables for {@link decryptBalanceAsMutationOptions}. */
20377
- interface DecryptBalanceAsParams {
20378
- delegatorAddress: Address;
20379
- accountAddress?: Address;
20380
- }
20381
- declare function decryptBalanceAsMutationOptions(token: Token): MutationFactoryOptions<readonly ["zama.decryptBalanceAs", Address], DecryptBalanceAsParams, bigint>;
20382
- //#endregion
20383
- //#region src/query/batch-decrypt-balances-as.d.ts
20384
- /** Variables for {@link batchDecryptBalancesAsMutationOptions}. */
20385
- type BatchDecryptBalancesAsParams = BatchDecryptAsOptions;
20386
- declare function batchDecryptBalancesAsMutationOptions(tokens: Token[]): MutationFactoryOptions<readonly ["zama.batchDecryptBalancesAs", ...Address[]], BatchDecryptBalancesAsParams, Map<Address, bigint>>;
20387
- //#endregion
20388
- //#region src/query/revoke-delegation.d.ts
20389
- /** Variables for {@link revokeDelegationMutationOptions}. */
20390
- interface RevokeDelegationParams {
20391
- delegateAddress: Address;
20392
- }
20393
- declare function revokeDelegationMutationOptions(sdk: ZamaSDK, contractAddress: Address): MutationFactoryOptions<readonly ["zama.revokeDelegation", Address], RevokeDelegationParams, TransactionResult>;
20394
- //#endregion
20395
- //#region src/services/delegation-service.d.ts
20396
- /** Delegation activity and expiry, resolved from a single expiry read. */
20397
- interface DelegationStatus {
20398
- isActive: boolean;
20399
- expiryTimestamp: bigint;
20400
- }
20401
- declare class DelegationService {
20402
- #private;
20403
- constructor({ provider, router, emitEvent, logger }: {
20404
- provider: GenericProvider;
20405
- router: ChainRouter;
20406
- logger: GenericLogger;
20407
- emitEvent?: (input: ZamaSDKEventInput, tokenAddress?: Address) => void;
20408
- });
20409
- delegateDecryption(signer: GenericSigner, { contractAddress, delegateAddress, delegatorAddress, expirationDate }: {
20410
- contractAddress: Address;
20411
- delegateAddress: Address;
20412
- delegatorAddress: Address;
20413
- expirationDate?: Date;
20414
- }): Promise<TransactionResult>;
20415
- revokeDelegation(signer: GenericSigner, { contractAddress, delegateAddress, delegatorAddress }: {
20416
- contractAddress: Address;
20417
- delegateAddress: Address;
20418
- delegatorAddress: Address;
20419
- }): Promise<TransactionResult>;
20420
- isDelegated(params: {
20421
- contractAddress: Address;
20422
- delegatorAddress: Address;
20423
- delegateAddress: Address;
20424
- }): Promise<boolean>;
19924
+ confidentialTransferFromAndCall(from: Address, to: Address, amount: bigint, data: Hex, callbacks?: TransferCallbacks): Promise<TransactionResult>;
20425
19925
  /**
20426
- * Resolve activity and expiry together from a single {@link getDelegationExpiry} read,
20427
- * instead of two separate round trips through {@link isDelegated} and
20428
- * {@link getDelegationExpiry}.
20429
- */
20430
- getStatus(params: {
20431
- contractAddress: Address;
20432
- delegatorAddress: Address;
20433
- delegateAddress: Address;
20434
- }): Promise<DelegationStatus>;
20435
- getDelegationExpiry({ contractAddress, delegatorAddress, delegateAddress }: {
20436
- contractAddress: Address;
20437
- delegatorAddress: Address;
20438
- delegateAddress: Address;
20439
- }): Promise<bigint>;
20440
- findInactiveDelegations(contractAddresses: readonly Address[], delegatorAddress: Address, delegateAddress: Address): Promise<Map<Address, DelegationNotFoundError | DelegationExpiredError>>;
20441
- assertDelegationActive(contractAddress: Address, delegatorAddress: Address, delegateAddress: Address): Promise<void>;
20442
- }
20443
- //#endregion
20444
- //#region src/query/delegation-status.d.ts
20445
- interface DelegationStatusQueryConfig {
20446
- contractAddress: Address | undefined;
20447
- delegatorAddress?: Address;
20448
- delegateAddress?: Address;
20449
- query?: Record<string, unknown>;
20450
- }
20451
- declare function delegationStatusQueryOptions(sdk: ZamaSDK, config: DelegationStatusQueryConfig): QueryFactoryOptions<DelegationStatus, Error, DelegationStatus, ReturnType<typeof zamaQueryKeys.delegationStatus.scope>>;
20452
- //#endregion
20453
- //#region src/credentials/credential-service.d.ts
20454
- /** Configuration for {@link CredentialService}. TTLs are pre-validated by the caller. */
20455
- interface CredentialServiceConfig {
20456
- router: ChainRouter;
20457
- signer: GenericSigner;
20458
- /** Transport key pair lifetime in seconds. Pre-validated. */
20459
- transportKeyPairTTL: number;
20460
- /** Permit lifetime in days. Pre-validated. */
20461
- permitTTL: number;
20462
- /** Backing storage for transport key pairs (and permits if `permitStorage` is omitted). */
20463
- storage: GenericStorage;
20464
- /** Optional dedicated storage for permits; defaults to `storage`. */
20465
- permitStorage?: GenericStorage;
20466
- /** SDK-wide logger for credential-path diagnostics. */
20467
- logger: GenericLogger;
19926
+ * Set operator approval for the confidential token.
19927
+ * Defaults to 1 hour from now if `until` is not specified.
19928
+ *
19929
+ * @param operator - The address to set as an operator.
19930
+ * @param until - Optional Unix timestamp for approval expiry. Defaults to now + 1 hour.
19931
+ * @returns The transaction hash and mined receipt.
19932
+ *
19933
+ * @example
19934
+ * ```ts
19935
+ * const txHash = await token.setOperator("0xOperator");
19936
+ * ```
19937
+ */
19938
+ setOperator(operator: Address, until?: number): Promise<TransactionResult>;
20468
19939
  /**
20469
- * Opt-in shared-tenant scope (B2B2C/WaaS operators). When set, every signer
20470
- * configured with the same scope shares one transport key pair instead of one
20471
- * per signer address. Permits stay per-signer regardless — see
20472
- * {@link revokeTransportKeyPair} for the operator-level counterpart to
20473
- * signer-level revocation.
19940
+ * Check if a spender is an approved operator for a given holder.
19941
+ *
19942
+ * @param holder - The token holder address.
19943
+ * @param spender - The address to check operator approval for.
19944
+ * @returns `true` if the spender is an approved operator for the holder.
19945
+ *
19946
+ * @example
19947
+ * ```ts
19948
+ * if (await token.isOperator("0xHolder", "0xSpender")) {
19949
+ * // spender can call transferFrom on behalf of holder
19950
+ * }
19951
+ * ```
20474
19952
  */
20475
- scope?: string;
19953
+ isOperator(holder: Address, spender: Address): Promise<boolean>;
19954
+ /** Verify all tokens share the same SDK instance and return it. */
19955
+ private static assertSameSdk;
20476
19956
  }
19957
+ //#endregion
19958
+ //#region src/token/wrapped-token.d.ts
20477
19959
  /**
20478
- * Single facade coordinating the keypair vault and the permission store.
19960
+ * Confidential ERC-20 wrapper (ERC-7984 ERC20Wrapper).
20479
19961
  *
20480
- * `CredentialService` is the only credentials object held by `ZamaSDK`. It accepts identity
20481
- * transitions via `handleWalletAccountChange`.
19962
+ * Extends {@link Token} with wrapper-specific operations:
19963
+ * - `shield` / `unshield` — convert between the underlying ERC-20 and confidential balance
19964
+ * - `unwrap` / `unwrapAll` / `finalizeUnwrap` — low-level two-phase primitives
19965
+ * - `underlying` / `allowance` — wrapper reads
20482
19966
  *
20483
- * Two distinct revocation tiers exist and must not be conflated: {@link clearCredentials}
20484
- * (signer-level, e.g. an end-user "disconnect") only ever removes that signer's own
20485
- * key-pair slot and permits — when a scope is configured, the shared key pair was never
20486
- * stored there, so it's untouched. {@link revokeTransportKeyPair} (operator-level) is
20487
- * the only way to invalidate a scope's shared key pair, and it does so for every signer
20488
- * in the scope at once.
19967
+ * `WrappedToken.address` is the wrapper contract address itself — the wrapper
19968
+ * IS the confidential token.
20489
19969
  */
20490
- declare class CredentialService {
19970
+ declare class WrappedToken extends Token {
20491
19971
  #private;
20492
- constructor(config: CredentialServiceConfig);
20493
19972
  /**
20494
- * Resolve a keypair and permissions covering `contracts`, minimizing wallet
20495
- * prompts by reusing or widening existing permits where possible. Empty
20496
- * `contracts` warms the keypair without prompting.
19973
+ * Read the underlying ERC-20 token address from the wrapper contract.
20497
19974
  *
20498
- * @returns The resolved keypair and permits covering the requested contracts.
20499
- * @throws if the user rejects a wallet signature prompt. {@link SigningRejectedError}
20500
- * @throws if signing fails for any other reason. {@link SigningFailedError}
19975
+ * @returns The underlying ERC-20 token address.
20501
19976
  */
20502
- grantPermit(contracts: readonly Address[], delegator?: Address): Promise<SerializedTransportKeyPairWithPermissions>;
19977
+ underlying(): Promise<Address>;
20503
19978
  /**
20504
- * Pure store lookup: are stored permits sufficient to cover `contracts`? No wallet prompt.
20505
- *
20506
- * @returns `true` if cached permits cover all requested contracts (vacuously
20507
- * true for an empty list); `false` if no keypair exists or coverage is
20508
- * incomplete.
19979
+ * Check whether the underlying ERC-20 supports ERC-1363 (payable token).
19980
+ * Result is cached per WrappedToken instance (negative results included):
19981
+ * once we know an underlying does not support ERC-1363, subsequent shields
19982
+ * go straight to the `approve` + `wrap` path without re-probing.
20509
19983
  */
20510
- hasPermit(contracts: readonly Address[], delegator?: Address): Promise<boolean>;
19984
+ isPayable(): Promise<boolean>;
20511
19985
  /**
20512
- * Wipe FHE permits for the current signer.
20513
- *
20514
- * - With no argument: every permit referencing this signer is removed across
20515
- * all chains and delegators. The keypair survives — use
20516
- * {@link clearCredentials} to also wipe the keypair.
20517
- * - With a contract list: every signed permit in the direct-decrypt scope
20518
- * (current chain) whose immutable payload touches any listed address is
20519
- * removed. Delegated permits are not touched in this mode.
19986
+ * Read the ERC-20 allowance granted by `owner` to this wrapper for the
19987
+ * underlying token.
20520
19988
  *
20521
- * @throws if reading the signer address fails. {@link SigningFailedError}
19989
+ * @param owner - The owner address whose allowance to read.
19990
+ * @returns The current allowance as a bigint.
20522
19991
  */
20523
- revokePermits(contracts?: readonly Address[]): Promise<void>;
19992
+ allowance(owner: Address): Promise<bigint>;
20524
19993
  /**
20525
- * Wipe the keypair for the current signer and cascade-delete every
20526
- * permission referencing it across all chains and delegators.
19994
+ * Shield public ERC-20 tokens into confidential tokens.
19995
+ *
19996
+ * The execution path is decided automatically by ERC-165 introspection on
19997
+ * the underlying ERC-20:
19998
+ * - **`transferAndCall`** (single tx): when the underlying supports
19999
+ * ERC-1363, no approval is required — the wrapper's `onTransferReceived`
20000
+ * callback mints confidential tokens directly. `approvalStrategy` is
20001
+ * **ignored** on this path. See {@link ShieldPath}.
20002
+ * - **`approveAndWrap`** (two-tx fallback): otherwise, an `approve` is
20003
+ * followed by a `wrap`. Approval is controlled by `approvalStrategy`
20004
+ * (`"exact"` by default, `"max"` for unlimited, `"skip"` to opt out).
20005
+ *
20006
+ * The ERC-20 balance is validated before submitting (public read, no
20007
+ * signing required) so the call works for all wallet types, including
20008
+ * smart wallets.
20527
20009
  *
20528
- * Signer-level only: when a scope is configured, the shared key pair was never
20529
- * stored under this signer's own slot, so it survives untouched — only this
20530
- * signer's permits are removed. Use {@link revokeTransportKeyPair} to invalidate
20531
- * the shared key pair itself.
20010
+ * @param amount - The plaintext amount to shield.
20011
+ * @param options - Optional: `approvalStrategy`, `to`, callbacks.
20012
+ * @returns The transaction hash and mined receipt.
20013
+ * @throws if signer and provider are on different chains. {@link ChainMismatchError}
20014
+ * @throws if the ERC-20 balance is less than `amount`. {@link InsufficientERC20BalanceError}
20015
+ * @throws if the ERC-20 approval or shield transaction reverts. {@link TransactionRevertedError}
20532
20016
  *
20533
- * @throws if reading the signer address fails. {@link SigningFailedError}
20017
+ * @example
20018
+ * ```ts
20019
+ * const txHash = await wrappedToken.shield(1000n);
20020
+ * ```
20534
20021
  */
20535
- clearCredentials(): Promise<void>;
20022
+ shield(amount: bigint, options?: ShieldOptions): Promise<TransactionResult>;
20536
20023
  /**
20537
- * Revoke this scope's shared transport key pair (operator-level action).
20024
+ * Wrap already-approved underlying ERC-20 into confidential tokens.
20538
20025
  *
20539
- * Deletes the shared key pair. Every permit signed under it embeds the old
20540
- * public key, so `listUsableAndPrune` treats them all as stale on next access —
20541
- * no permit is touched directly, and no connected wallet is required. This is
20542
- * the only operation that can invalidate a shared key pair; signer-level
20543
- * {@link clearCredentials} never does.
20026
+ * Escape hatch for splitting shield across two signatures: call
20027
+ * {@link approveUnderlying} first, then `wrap`. Most callers should use
20028
+ * {@link shield}, which routes and orchestrates approval automatically.
20544
20029
  *
20545
- * Not best-effort: unlike {@link clearCredentials}, a storage failure here rejects
20546
- * instead of being logged and swallowed — see {@link TransportKeyPairVault.clearScope}.
20030
+ * Validates the ERC-20 balance and the allowance granted to this wrapper
20031
+ * (public reads, no signing) and fails early with a clear error.
20547
20032
  *
20548
- * Only stops the SDK from reissuing or reusing the deleted key going forward — does
20549
- * not revoke any permit already issued under it. A permit is a self-contained,
20550
- * bearer-style EIP-712 signature the relayer accepts independently of this SDK's
20551
- * storage; one already exfiltrated alongside the key remains usable until its own
20552
- * `permitTTL` expiry regardless of this call.
20033
+ * @param amount - The plaintext amount to wrap.
20034
+ * @param options - Optional `to` recipient and `onWrapSubmitted` callback.
20035
+ * @returns The transaction hash and mined receipt.
20036
+ * @throws if reading the ERC-20 balance or allowance fails. {@link ERC20ReadFailedError}
20037
+ * @throws if the ERC-20 balance is less than `amount`. {@link InsufficientERC20BalanceError}
20038
+ * @throws if the allowance granted to the wrapper is less than `amount`. {@link InsufficientAllowanceError}
20553
20039
  *
20554
- * @param scopeId - Must match the scope this service was configured with. Requiring
20555
- * the caller to name it guards against revoking the wrong scope by mistake.
20556
- * @throws if no scope is configured, or `scopeId` doesn't match it. {@link ConfigurationError}
20557
- * @throws if the underlying storage delete fails.
20040
+ * @example
20041
+ * ```ts
20042
+ * await wrappedToken.approveUnderlying(1000n);
20043
+ * await wrappedToken.wrap(1000n);
20044
+ * ```
20558
20045
  */
20559
- revokeTransportKeyPair(scopeId: string): Promise<void>;
20046
+ wrap(amount: bigint, options?: WrapOptions): Promise<TransactionResult>;
20560
20047
  /**
20561
- * Warm the signer transport key pair cache for a known address.
20048
+ * Approve this wrapper contract to spend the underlying ERC-20.
20049
+ * Defaults to max uint256. Resets to zero first if there's an existing
20050
+ * non-zero allowance (required by tokens like USDT).
20562
20051
  *
20563
- * Best-effort prefetch primitive: correctness still comes from `grantPermit`,
20564
- * which lazily creates the transport key pair when needed. Errors (storage failure,
20565
- * relayer 4xx, missing Worker in SSR) are **not** swallowed here — the caller
20566
- * decides whether to log, ignore, or surface them.
20052
+ * @param amount - Optional approval amount. Defaults to max uint256.
20053
+ * @returns The transaction hash and mined receipt.
20567
20054
  *
20568
- * Not for pre-warming a shared scope: `address` is ignored for storage keying once
20569
- * a scope is configured (see {@link TransportKeyPairVault}), so this call's actual
20570
- * effect wouldn't match its apparent per-signer intent. Use
20571
- * {@link warmTransportKeyPairScope} instead.
20055
+ * @example
20056
+ * ```ts
20057
+ * await wrappedToken.approveUnderlying(); // max approval
20058
+ * await wrappedToken.approveUnderlying(1000n); // exact amount
20059
+ * ```
20572
20060
  */
20573
- warmTransportKeyPair(address: Address): Promise<void>;
20061
+ approveUnderlying(amount?: bigint): Promise<TransactionResult>;
20574
20062
  /**
20575
- * Warm this scope's shared transport key pair (operator-level, no wallet needed) —
20576
- * the pre-warm counterpart to {@link revokeTransportKeyPair}.
20063
+ * Unshield a specific amount and finalize in one call.
20064
+ * Orchestrates: unshield → wait for receipt → parse event → finalize.
20577
20065
  *
20578
- * @param scopeId - Must match the scope this service was configured with. Requiring
20579
- * the caller to name it guards against warming the wrong scope by mistake.
20580
- * @throws if no scope is configured, or `scopeId` doesn't match it. {@link ConfigurationError}
20066
+ * By default, the SDK validates the confidential balance before submitting.
20067
+ * Set `skipBalanceCheck: true` to bypass this validation (e.g. for smart wallets).
20068
+ *
20069
+ * @param amount - The plaintext amount to unshield.
20070
+ * @param options - Optional: `skipBalanceCheck` (default `false`), callbacks.
20071
+ * @returns The finalize transaction hash and mined receipt.
20072
+ *
20073
+ * @example
20074
+ * ```ts
20075
+ * const txHash = await wrappedToken.unshield(500n);
20076
+ * ```
20581
20077
  */
20582
- warmTransportKeyPairScope(scopeId: string): Promise<void>;
20078
+ unshield(amount: bigint, options?: UnshieldOptions): Promise<TransactionResult>;
20583
20079
  /**
20584
- * Apply a wallet account transition.
20080
+ * Unshield the entire balance and finalize in one call.
20081
+ * Orchestrates: unshieldAll → wait for receipt → parse event → finalize.
20585
20082
  *
20586
- * Address change clears persisted credentials for the previous account.
20587
- * Chain-only changes keep credentials intact because permits are chain-scoped
20588
- * already and stale decrypt plaintext is cleared by `ZamaSDK`.
20083
+ * @param callbacks - Optional progress callbacks for each phase.
20084
+ * @returns The finalize transaction hash and mined receipt.
20085
+ * @throws if the balance is zero. {@link DecryptionFailedError}
20086
+ *
20087
+ * @example
20088
+ * ```ts
20089
+ * const txHash = await wrappedToken.unshieldAll();
20090
+ * ```
20589
20091
  */
20590
- handleWalletAccountChange(prev?: {
20591
- address: Address;
20592
- }, next?: {
20593
- address: Address;
20594
- }): Promise<void>;
20595
- }
20596
- //#endregion
20597
- //#region src/services/caching-service.d.ts
20598
- /**
20599
- * Storage-backed cache for decrypted FHE plaintext values.
20600
- *
20601
- * Each entry is keyed by `(requester, contractAddress, handle)` so different
20602
- * signers cannot read each other's cached decryptions.
20603
- */
20604
- declare class CachingService {
20605
- #private;
20606
- constructor(storage: GenericStorage, logger: GenericLogger);
20607
- get(requester: Address, contractAddress: Address, encryptedValue: EncryptedValue): Promise<ClearValue | null>;
20608
- set(requester: Address, contractAddress: Address, encryptedValue: EncryptedValue, value: ClearValue): Promise<void>;
20609
- delete(requester: Address, contractAddress: Address, encryptedValue: EncryptedValue): Promise<void>;
20610
- clearForRequester(requester: Address): Promise<void>;
20611
- clearAll(): Promise<void>;
20612
- }
20613
- //#endregion
20614
- //#region src/services/decryption-service.d.ts
20615
- /** Options shared by the delegated-decrypt entry points. */
20616
- interface DelegatedDecryptOptions {
20092
+ unshieldAll(callbacks?: UnshieldCallbacks): Promise<TransactionResult>;
20617
20093
  /**
20618
- * Ride out the gateway propagation window: when a just-granted delegation
20619
- * has not yet synced, the delegated decrypt is retried (bounded, ~30s) until
20620
- * it lands instead of throwing {@link DelegationNotPropagatedError}. Defaults
20621
- * to `true`. Pass `false` to fail fast on the first not-propagated response.
20094
+ * Resume an in-progress unshield from an existing unwrap tx hash.
20095
+ * Useful when the user already submitted the unwrap but the finalize step
20096
+ * was interrupted (e.g. page reload, network error).
20097
+ *
20098
+ * @param unwrapTxHash - The transaction hash of the previously submitted unwrap.
20099
+ * @param callbacks - Optional progress callbacks.
20100
+ * @returns The finalize transaction hash and mined receipt.
20101
+ *
20102
+ * @example
20103
+ * ```ts
20104
+ * const txHash = await wrappedToken.resumeUnshield(previousUnwrapTxHash);
20105
+ * ```
20622
20106
  */
20623
- waitForPropagation?: boolean;
20624
- }
20625
- interface BatchDecryptItem {
20626
- encryptedValue: EncryptedValue;
20627
- contractAddress: Address;
20628
- value?: ClearValue;
20629
- error?: ZamaError;
20630
- }
20631
- interface BatchDecryptResult {
20632
- items: BatchDecryptItem[];
20633
- }
20634
- declare class DecryptionService {
20635
- #private;
20636
- constructor({ cache, credentialService, delegationService, router, emitEvent }: {
20637
- cache: CachingService;
20638
- credentialService: CredentialService;
20639
- delegationService: DelegationService;
20640
- router: ChainRouter;
20641
- emitEvent: (input: ZamaSDKEventInput) => void;
20642
- });
20643
- decryptValues(handles: EncryptedInput[], signerAddress: Address, opts?: Pick<FhevmRelayerOptions, "signal" | "timeout">): Promise<Record<EncryptedValue, ClearValue>>;
20644
- delegatedDecryptValues(encryptedInputs: EncryptedInput[], delegatorAddress: Address, delegateAddress: Address, accountAddress: Address, opts?: DelegatedDecryptOptions): Promise<Record<EncryptedValue, ClearValue>>;
20645
- delegatedBatchDecryptHandlesAs({ encryptedInputs, delegatorAddress, delegateAddress, accountAddress, maxConcurrency, waitForPropagation }: {
20646
- encryptedInputs: EncryptedInput[];
20647
- delegatorAddress: Address;
20648
- delegateAddress: Address;
20649
- accountAddress: Address;
20650
- maxConcurrency?: number;
20651
- waitForPropagation?: boolean;
20652
- }): Promise<BatchDecryptResult>;
20653
- }
20654
- //#endregion
20655
- //#region src/namespaces/decryption.d.ts
20656
- /**
20657
- * Public namespace for FHE decryption — the canonical way to decrypt.
20658
- *
20659
- * Exposed as `sdk.decryption`. Prefer these methods over the low-level
20660
- * `sdk.relayer.decryptValues` / `decryptPublicValues`: they
20661
- * assemble the credential bundle (transport key pair, EIP-712 permit) for you,
20662
- * cache results, and wrap relayer errors. Reach for `sdk.relayer.*` only when
20663
- * you must control credential assembly by hand.
20664
- *
20665
- * Owns the SDK-level guards (signer requirement on
20666
- * `decryptValues` and `delegatedDecryptValues`, empty-array
20667
- * short-circuit on `decryptPublicValues`, relayer error wrapping) and delegates the
20668
- * actual work to the internal {@link DecryptionService} or the relayer directly for
20669
- * `decryptPublicValues`.
20670
- *
20671
- * **Mixed signer requirement:** `decryptValues` and
20672
- * `delegatedDecryptValues` need a configured signer; `decryptPublicValues`
20673
- * does not. Each method documents its requirement in its JSDoc.
20674
- *
20675
- * **Request chunking:** decrypt requests are split internally to stay under
20676
- * the relayer's 2048-cleartext-bit per-request budget — callers never need to
20677
- * size batches themselves.
20678
- */
20679
- declare class Decryption {
20680
- #private;
20681
- /** @internal */
20682
- constructor(opts: {
20683
- signer: GenericSigner | undefined;
20684
- provider: GenericProvider;
20685
- router: ChainRouter;
20686
- decryptionService: DecryptionService | undefined;
20687
- });
20107
+ resumeUnshield(unwrapTxHash: Hex, callbacks?: UnshieldCallbacks): Promise<TransactionResult>;
20688
20108
  /**
20689
- * Decrypt one or more FHE encrypted values. Results are cached — repeated calls
20690
- * for the same encrypted value skip the relayer round-trip.
20109
+ * Return the unwrap tx hash of an unshield that was interrupted between its
20110
+ * two phases, or `null` if none is pending for this wrapper.
20691
20111
  *
20692
- * Zero encrypted values are mapped to `0n` without hitting the relayer.
20693
- * Events (`DecryptStart/End/Error`) are emitted uniformly.
20694
- * Relayer errors are wrapped into typed SDK errors.
20112
+ * The SDK persists this automatically when {@link unshield}/{@link unshieldAll}
20113
+ * submit phase 1, and clears it once phase 2 finalizes. Use the returned hash
20114
+ * to surface a "resume" affordance, then pass it to {@link resumeUnshield}.
20115
+ * Resuming is intentionally caller-driven — auto-resuming on load would fire a
20116
+ * wallet transaction unprompted.
20695
20117
  *
20696
- * @param encryptedInput - Encrypted values to decrypt, each paired with its contract address.
20697
- * @param options - Per-call `signal` and `timeout` forwarded to the relayer round-trip.
20698
- * @returns A record mapping each encrypted value to its decrypted clear-text value.
20699
- * @throws if no signer is configured. {@link SignerNotConfiguredError}
20700
- * @throws if signer and provider are on different chains. {@link ChainMismatchError}
20118
+ * @returns The pending unwrap tx hash, or `null`.
20701
20119
  *
20702
20120
  * @example
20703
20121
  * ```ts
20704
- * const values = await sdk.decryption.decryptValues([
20705
- * { encryptedValue: balance, contractAddress: cUSDT },
20706
- * ]);
20707
- * console.log(values[balance]); // 1000n
20122
+ * const unwrapTxHash = await wrappedToken.getPendingUnshield();
20123
+ * if (unwrapTxHash) await wrappedToken.resumeUnshield(unwrapTxHash);
20708
20124
  * ```
20709
20125
  */
20710
- decryptValues(encryptedInput: EncryptedInput[], options?: Pick<FhevmRelayerOptions, "signal" | "timeout">): Promise<Record<EncryptedValue, ClearValue>>;
20126
+ getPendingUnshield(): Promise<Hex | null>;
20711
20127
  /**
20712
- * Decrypt one or more FHE encrypted values using delegated credentials.
20713
- *
20714
- * Mirrors {@link decryptValues} with delegated credentials — same caching and
20715
- * zero-value short-circuit. Before reading from cache or calling the relayer,
20716
- * every non-zero encrypted value's contract must have an active delegation from the
20717
- * delegator to the connected signer; missing or expired delegations fail fast.
20718
- *
20719
- * @param encryptedInputs - FHE encrypted values paired with their contract addresses.
20720
- * @param delegatorAddress - The address that granted delegation rights.
20721
- * @param accountAddress - Address used as the cache key's "requester"
20722
- * dimension. Defaults to `delegatorAddress`. Pass the actual account address
20723
- * when decrypting on behalf of someone whose balance is stored under a
20724
- * different address (e.g. `decryptBalanceAs` with an explicit `accountAddress`).
20725
- * @param options - Delegated-decrypt options. By default the call rides out the
20726
- * gateway propagation window ({@link DelegatedDecryptOptions.waitForPropagation});
20727
- * pass `{ waitForPropagation: false }` to fail fast instead.
20728
- * @returns Map of encrypted value → clear-text value.
20128
+ * Request an unwrap for a specific amount. Encrypts the amount first.
20129
+ * Pass the result's `unwrapRequestId` to {@link finalizeUnwrap} once the
20130
+ * request is processed on-chain.
20131
+ *
20132
+ * @param amount - The plaintext amount to unwrap (encrypted automatically).
20133
+ * @returns The tx hash, mined receipt, and the `unwrapRequestId` for `finalizeUnwrap`.
20729
20134
  *
20730
20135
  * @example
20731
20136
  * ```ts
20732
- * const values = await sdk.decryption.delegatedDecryptValues([
20733
- * { encryptedValue: balance, contractAddress: tokenAddr },
20734
- * ], delegatorAddr);
20735
- * console.log(values[balance]); // 1000n
20137
+ * const result = await wrappedToken.unwrap(500n);
20138
+ * await wrappedToken.finalizeUnwrap(result.unwrapRequestId);
20736
20139
  * ```
20737
20140
  */
20738
- delegatedDecryptValues(encryptedInputs: EncryptedInput[], delegatorAddress: Address, accountAddress?: Address, options?: DelegatedDecryptOptions): Promise<Record<EncryptedValue, ClearValue>>;
20141
+ unwrap(amount: bigint): Promise<UnwrapResult>;
20739
20142
  /**
20740
- * Publicly decrypt one or more FHE encrypted values.
20741
- *
20742
- * Signer-independent: works without a configured signer.
20743
- * Returns the decryption proof alongside the clear-text values so callers
20744
- * can submit on-chain finalization transactions (e.g. `finalizeUnwrap`).
20143
+ * Request an unwrap for the entire confidential balance.
20144
+ * Uses the on-chain encrypted balance directly (no encryption needed).
20145
+ * Throws if the balance is zero.
20745
20146
  *
20746
- * @param encryptedValues - FHE encrypted values to decrypt publicly.
20747
- * @param options - Per-call `signal` and `timeout` forwarded to the relayer round-trip.
20748
- * @returns Clear-text values, ABI-encoded values, and the decryption proof.
20147
+ * @returns The tx hash, mined receipt, and the `unwrapRequestId` for `finalizeUnwrap`.
20148
+ * @throws if the balance is zero. {@link DecryptionFailedError}
20749
20149
  *
20750
20150
  * @example
20751
20151
  * ```ts
20752
- * const { clearValues, decryptionProof, abiEncodedClearValues } =
20753
- * await sdk.decryption.decryptPublicValues([encryptedValue]);
20152
+ * const result = await wrappedToken.unwrapAll();
20153
+ * await wrappedToken.finalizeUnwrap(result.unwrapRequestId);
20754
20154
  * ```
20755
20155
  */
20756
- decryptPublicValues(encryptedValues: EncryptedValue[], options?: Pick<FhevmRelayerOptions, "signal" | "timeout">): Promise<DecryptPublicValuesResult>;
20156
+ unwrapAll(): Promise<UnwrapResult>;
20757
20157
  /**
20758
- * Batch-decrypt delegated encrypted values with per-entry error isolation.
20759
- *
20760
- * Attempts a single batch request first. If the batch fails with a non-fatal
20761
- * error (e.g. one entry is invalid), falls back to per-entry decryption so
20762
- * healthy entries still resolve. Each item in the result carries either a
20763
- * decrypted value or an error — callers decide how to surface partial failures.
20158
+ * Complete an unwrap by fetching the public decryption proof and finalizing.
20159
+ * Call this once the unwrap request has been processed on-chain.
20764
20160
  *
20765
- * @param encryptedInputs - FHE encrypted values paired with their contract addresses.
20766
- * @param delegatorAddress - The address that granted delegation rights.
20767
- * @param accountAddress - The account on whose behalf decryption is performed. Defaults to `delegatorAddress`.
20768
- * @param maxConcurrency - Maximum parallel decrypt calls during per-entry fallback.
20769
- * @param waitForPropagation - Ride out the gateway propagation window on the
20770
- * initial batch attempt (default `true`). See {@link DelegatedDecryptOptions.waitForPropagation}.
20771
- * @returns Per-entry results, each with a value or an error.
20772
- * @throws if no signer is configured. {@link SignerNotConfiguredError}
20773
- * @throws if signer and provider are on different chains. {@link ChainMismatchError}
20161
+ * @param unwrapRequestId - The `unwrapRequestId` from an {@link UnwrapResult}
20162
+ * (`result.unwrapRequestId`) returned by {@link unwrap} / {@link unwrapAll},
20163
+ * or one decoded from an `UnwrapRequested` event (e.g. when finalizing
20164
+ * across sessions).
20165
+ * @returns The transaction hash and mined receipt.
20774
20166
  *
20775
20167
  * @example
20776
20168
  * ```ts
20777
- * const result = await sdk.decryption.delegatedBatchDecryptValues({
20778
- * encryptedInputs: [
20779
- * { encryptedValue: encryptedValue1, contractAddress: tokenA },
20780
- * { encryptedValue: encryptedValue2, contractAddress: tokenB },
20781
- * ],
20782
- * delegatorAddress: "0xDelegator",
20783
- * maxConcurrency: 5,
20784
- * });
20785
- * for (const item of result.items) {
20786
- * if (item.error) console.error(item.encryptedValue, item.error);
20787
- * else console.log(item.encryptedValue, item.value);
20788
- * }
20169
+ * const { unwrapRequestId } = await wrappedToken.unwrap(500n);
20170
+ * await wrappedToken.finalizeUnwrap(unwrapRequestId);
20789
20171
  * ```
20790
20172
  */
20791
- delegatedBatchDecryptValues({ encryptedInputs, delegatorAddress, accountAddress, maxConcurrency, waitForPropagation }: {
20792
- encryptedInputs: EncryptedInput[];
20793
- delegatorAddress: Address;
20794
- accountAddress?: Address;
20795
- maxConcurrency?: number;
20796
- } & DelegatedDecryptOptions): Promise<BatchDecryptResult>;
20173
+ finalizeUnwrap(unwrapRequestId: EncryptedValue): Promise<TransactionResult>;
20797
20174
  }
20798
20175
  //#endregion
20799
- //#region src/namespaces/delegations.d.ts
20176
+ //#region src/schemas/primitives.d.ts
20177
+ declare const checksummedTag: unique symbol;
20178
+ /** An EVM address that has been put through `getAddress` (EIP-55 checksum form). */
20179
+ type ChecksummedAddress = Address & {
20180
+ readonly [checksummedTag]: true;
20181
+ };
20182
+ //#endregion
20183
+ //#region src/credentials/types.d.ts
20800
20184
  /**
20801
- * Public namespace for on-chain decryption-delegation management.
20802
- *
20803
- * Exposed as `sdk.delegations`. Owns the SDK-level guards (signer requirement, chain
20804
- * alignment, delegator address resolution from the wallet account) and delegates the
20805
- * actual work to the internal {@link DelegationService}.
20806
- *
20807
- * Delegation operations write to the host chain ACL; after a delegation is mined,
20808
- * the gateway syncs the ACL state via cross-chain event propagation — usually
20809
- * within ~10 blocks (a few seconds). Delegated decryption rides out that window
20810
- * with a bounded internal retry, so callers can decrypt right after granting.
20185
+ * Serialized transport key pair — ML-KEM public + private key as hex, the shape
20186
+ * we persist and hand to the decrypt path. Mirrors `@fhevm/sdk`'s
20187
+ * `serializeTransportKeyPair` output; the private half is plaintext, so treat it
20188
+ * as sensitive.
20811
20189
  */
20812
- declare class Delegations {
20813
- #private;
20814
- /** @internal */
20815
- constructor(opts: {
20816
- signer: GenericSigner | undefined;
20817
- provider: GenericProvider;
20818
- delegationService: DelegationService;
20819
- });
20820
- /**
20821
- * Delegate decryption rights for a confidential contract to another address.
20822
- * Calls `ACL.delegateForUserDecryption()` on-chain.
20823
- *
20824
- * The delegation is recorded on L1 immediately, but the gateway must sync the
20825
- * ACL state via cross-chain event propagation — usually within ~10 blocks (a
20826
- * few seconds). You do not need to wait: delegated decryption rides out that
20827
- * window with a bounded internal retry, so you can decrypt right after this
20828
- * resolves.
20829
- *
20830
- * @param contractAddress - The confidential contract address to delegate on.
20831
- * @param delegateAddress - Address to delegate decryption rights to.
20832
- * @param expirationDate - Optional expiration date (defaults to permanent delegation via `uint64.max`).
20833
- * @returns The transaction hash and mined receipt.
20834
- * @throws if no signer is configured. {@link SignerNotConfiguredError}
20835
- * @throws if signer and provider are on different chains. {@link ChainMismatchError}
20836
- * @throws if `expirationDate` is less than 1 hour in the future. {@link DelegationExpirationTooSoonError}
20837
- * @throws if the delegate equals the connected wallet. {@link DelegationSelfNotAllowedError}
20838
- * @throws if the delegate equals the contract address. {@link DelegationDelegateEqualsContractError}
20839
- * @throws if the new expiry equals the current one. {@link DelegationExpiryUnchangedError}
20840
- * @throws if the delegation transaction reverts. {@link TransactionRevertedError}
20841
- */
20842
- delegateDecryption({ contractAddress, delegateAddress, expirationDate }: {
20843
- contractAddress: Address;
20844
- delegateAddress: Address;
20845
- expirationDate?: Date;
20846
- }): Promise<TransactionResult>;
20190
+ interface SerializedTransportKeyPair {
20191
+ /** ML-KEM public key, hex-encoded. */
20192
+ publicKey: Hex;
20193
+ /** ML-KEM private key, hex-encoded (plaintext — treat as sensitive). */
20194
+ privateKey: Hex;
20847
20195
  /**
20848
- * Revoke decryption delegation for a confidential contract.
20849
- * Calls `ACL.revokeDelegationForUserDecryption()` on-chain.
20850
- *
20851
- * @param contractAddress - The confidential contract address to revoke delegation on.
20852
- * @param delegateAddress - Address to revoke delegation from.
20853
- * @returns The transaction hash and mined receipt.
20854
- * @throws if no signer is configured. {@link SignerNotConfiguredError}
20855
- * @throws if signer and provider are on different chains. {@link ChainMismatchError}
20856
- * @throws if no delegation exists for this (delegator, delegate, contract) tuple. {@link DelegationNotFoundError}
20857
- * @throws if the revocation transaction reverts. {@link TransactionRevertedError}
20196
+ * The TKMS version the key pair was generated under, passed back to
20197
+ * `parseTransportKeyPair` so the private key deserializes under the right
20198
+ * version after a KMS/TKMS rotation. Optional — key pairs serialized before
20199
+ * this tag existed carry none.
20858
20200
  */
20859
- revokeDelegation({ contractAddress, delegateAddress }: {
20860
- contractAddress: Address;
20861
- delegateAddress: Address;
20862
- }): Promise<TransactionResult>;
20201
+ tkmsVersion?: string;
20202
+ }
20203
+ /** EIP-712 typed-data payload carried by a {@link SerializedPermit}. */
20204
+ interface SerializedPermitEip712 {
20205
+ /** EIP-712 domain separator fields. */
20206
+ domain: Record<string, unknown>;
20207
+ /** Name of the primary type being signed. */
20208
+ primaryType?: string;
20209
+ /** EIP-712 type definitions keyed by type name. */
20210
+ types: Record<string, {
20211
+ name: string;
20212
+ type: string;
20213
+ }[]>;
20214
+ /** The typed-data message being signed. */
20215
+ message: Record<string, unknown>;
20216
+ }
20217
+ /**
20218
+ * The reusable serialized `@fhevm/sdk` decryption permit persisted inside a
20219
+ * {@link Permission} — passed verbatim to `parseSignedDecryptionPermit`.
20220
+ *
20221
+ * Mirrors {@link SerializedPermitSchema}; kept in sync by a `.test-d.ts` guard.
20222
+ */
20223
+ interface SerializedPermit {
20224
+ /** Serialization format version. */
20225
+ version: number;
20226
+ /** The EIP-712 typed data that was signed. */
20227
+ eip712: SerializedPermitEip712;
20228
+ /** The signer's EIP-712 signature, hex-encoded. */
20229
+ signature: Hex;
20230
+ /** Address that produced the signature. */
20231
+ signerAddress: ChecksummedAddress;
20232
+ }
20233
+ /**
20234
+ * A signed EIP-712 permit binding a signer (and optional delegator) to a set of
20235
+ * contract addresses for a bounded time window. Wraps the serialized `@fhevm/sdk`
20236
+ * permit ({@link SerializedPermit}) alongside the scope/coverage metadata the
20237
+ * permission store indexes on.
20238
+ *
20239
+ * Mirrors {@link PermissionSchema}; kept in sync by a `.test-d.ts` guard.
20240
+ */
20241
+ interface Permission {
20242
+ /** Public key of the transport key pair this permit is bound to, hex-encoded. */
20243
+ keypairPublicKey: Hex;
20244
+ /** Contract addresses this permit grants decrypt access to. */
20245
+ contractAddresses: ChecksummedAddress[];
20246
+ /** The signed serialized permit. */
20247
+ serializedPermit: SerializedPermit;
20248
+ /** Unix timestamp (seconds) when the permit becomes valid. */
20249
+ startTimestamp: number;
20250
+ /** Validity window length in days from {@link Permission.startTimestamp}. */
20251
+ durationDays: number;
20252
+ }
20253
+ //#endregion
20254
+ //#region src/wrappers-registry.d.ts
20255
+ /**
20256
+ * Default wrappers registry addresses for known chains.
20257
+ * Only includes chains where a registry is deployed (excludes Hardhat).
20258
+ *
20259
+ * @deprecated Read `registryAddress` from the chain presets instead (e.g.
20260
+ * `sepolia.registryAddress`). Will be removed in the next major version.
20261
+ */
20262
+ declare const DefaultRegistryAddresses: Record<number, Address>;
20263
+ /** Configuration for {@link WrappersRegistry}. */
20264
+ interface WrappersRegistryConfig {
20265
+ /** Read-only chain provider used for every registry lookup. */
20266
+ provider: GenericProvider;
20863
20267
  /**
20864
- * Check whether a delegation is active for the given contract address.
20865
- *
20866
- * Signer-independent: works without a configured signer.
20268
+ * Per-chain registry address overrides, merged on top of
20269
+ * {@link DefaultRegistryAddresses}. Use this to supply a registry
20270
+ * address for custom or local chains (e.g. Hardhat).
20867
20271
  *
20868
- * @param contractAddress - The confidential contract address.
20869
- * @param delegatorAddress - The address that granted the delegation.
20870
- * @param delegateAddress - The address that received delegation rights.
20871
- * @returns `true` if the delegation exists and has not expired.
20272
+ * @example
20273
+ * ```ts
20274
+ * new WrappersRegistry({
20275
+ * provider,
20276
+ * registryAddresses: { [31337]: "0xYourHardhatRegistry" },
20277
+ * });
20278
+ * ```
20872
20279
  */
20873
- isActive(params: {
20874
- contractAddress: Address;
20875
- delegatorAddress: Address;
20876
- delegateAddress: Address;
20877
- }): Promise<boolean>;
20280
+ registryAddresses?: Record<number, Address>;
20878
20281
  /**
20879
- * Get the expiration timestamp of a delegation for the given contract.
20880
- *
20881
- * Signer-independent: works without a configured signer.
20882
- *
20883
- * @param contractAddress - The confidential contract address.
20884
- * @param delegatorAddress - The address that granted the delegation.
20885
- * @param delegateAddress - The address that received delegation rights.
20886
- * @returns Unix timestamp as bigint. `0n` = no delegation. `2^64 - 1` = permanent.
20282
+ * How long cached registry results remain valid, in seconds.
20283
+ * Default: `86400` (24 hours).
20887
20284
  */
20888
- getExpiry(params: {
20889
- contractAddress: Address;
20890
- delegatorAddress: Address;
20891
- delegateAddress: Address;
20892
- }): Promise<bigint>;
20285
+ registryTTL?: number;
20286
+ }
20287
+ /** Options for {@link WrappersRegistry.listPairs}. */
20288
+ interface ListPairsOptions {
20289
+ /** Page number (1-indexed). Default: `1`. */
20290
+ page?: number;
20291
+ /** Number of items per page. Default: `100`. */
20292
+ pageSize?: number;
20893
20293
  /**
20894
- * Get activity and expiry together in a single on-chain read, instead of
20895
- * calling {@link isActive} and {@link getExpiry} separately.
20896
- *
20897
- * Signer-independent: works without a configured signer.
20898
- *
20899
- * @param contractAddress - The confidential contract address.
20900
- * @param delegatorAddress - The address that granted the delegation.
20901
- * @param delegateAddress - The address that received delegation rights.
20902
- * @returns `{ isActive, expiryTimestamp }` — activity and the raw expiry timestamp together.
20294
+ * When `true`, fetches on-chain metadata (name, symbol, decimals) for both
20295
+ * the ERC-20 and confidential token, plus totalSupply for the ERC-20.
20296
+ * Default: `false`.
20903
20297
  */
20904
- getStatus(params: {
20905
- contractAddress: Address;
20906
- delegatorAddress: Address;
20907
- delegateAddress: Address;
20908
- }): Promise<DelegationStatus>;
20298
+ metadata?: boolean;
20909
20299
  }
20910
- //#endregion
20911
- //#region src/namespaces/permits.d.ts
20912
20300
  /**
20913
- * Public namespace for permit and transport-key-pair management.
20301
+ * High-level interface for the on-chain token wrappers registry.
20914
20302
  *
20915
- * Exposed as `sdk.permits`. Owns the SDK-level guards (chain alignment, empty-array
20916
- * short-circuit, decrypt-cache invalidation) and delegates the actual work to the
20917
- * internal {@link CredentialService}.
20303
+ * Uses the configured {@link GenericProvider} to resolve the correct registry
20304
+ * contract address for the current chain and exposes typed read helpers for
20305
+ * every registry query. Results are cached in memory with a configurable TTL
20306
+ * (default 24 hours).
20918
20307
  *
20919
- * The namespace is named `permits` because the user-facing concept is the signed-permit
20920
- * store. The transport key pair is invisible plumbing — there is no `getTransportKeyPair()`
20921
- * surfaced; the key pair exists to sign permits and is created automatically when needed.
20922
- * {@link clear} wipes both the permit store and the transport key pair (permits
20923
- * cascade-delete with the key pair).
20308
+ * @example
20309
+ * ```ts
20310
+ * const registry = new WrappersRegistry({ provider });
20311
+ *
20312
+ * // Paginated listing
20313
+ * const page1 = await registry.listPairs({ page: 1, pageSize: 20 });
20924
20314
  *
20925
- * When `transportKeyPairScope` is configured (opt-in shared-tenant scope for B2B2C/WaaS
20926
- * operators), {@link clear} and {@link revokePermits} stay signer-level only — they never
20927
- * touch the shared key pair. {@link revokeTransportKeyPair} is the distinct,
20928
- * operator-level operation for that.
20315
+ * // Structured lookups
20316
+ * const result = await registry.getConfidentialToken(erc20Address);
20317
+ * if (result) console.log(result.confidentialTokenAddress);
20318
+ *
20319
+ * // Force refresh
20320
+ * registry.refresh();
20321
+ * ```
20929
20322
  */
20930
- declare class Permits {
20323
+ declare class WrappersRegistry {
20931
20324
  #private;
20932
- /** @internal */
20933
- constructor(opts: {
20934
- signer: GenericSigner | undefined;
20935
- provider: GenericProvider;
20936
- cachingService: CachingService;
20937
- credentialService: CredentialService | undefined;
20938
- logger: GenericLogger;
20939
- });
20325
+ /** Read-only chain access used for registry contract reads. */
20326
+ readonly provider: GenericProvider;
20327
+ constructor(config: WrappersRegistryConfig);
20940
20328
  /**
20941
- * Sign and store an EIP-712 permit authorising direct decryption for the
20942
- * given contract addresses.
20943
- *
20944
- * Idempotent: if a permit covering the requested set already exists, no
20945
- * wallet prompt occurs. Otherwise the SDK chunks the uncovered subset into
20946
- * groups of ≤10 contracts and prompts once per chunk; partial mid-flight
20947
- * rejection is preserved (already-signed chunks are persisted before the
20948
- * next prompt).
20949
- *
20950
- * @param contracts - Contract addresses to authorize.
20329
+ * Synchronous lookup of the registry address for a given chain ID.
20330
+ * Returns `undefined` if no address is configured for that chain.
20951
20331
  */
20952
- grantPermit(contracts: Address[]): Promise<void>;
20332
+ getAddress(chainId: number): Address | undefined;
20953
20333
  /**
20954
- * Sign and store an EIP-712 delegation permit authorising decryption on
20955
- * behalf of `delegator`. Same idempotence/chunking semantics as {@link grantPermit}.
20956
- *
20957
- * @param delegator - The address that delegated decryption rights to the connected signer.
20958
- * @param contracts - Contract addresses to authorize.
20334
+ * Force-invalidate the in-memory cache. The next call to any read method
20335
+ * will fetch fresh data from the chain.
20959
20336
  */
20960
- grantDelegationPermit(delegator: Address, contracts: Address[]): Promise<void>;
20337
+ refresh(): void;
20961
20338
  /**
20962
- * Pure store lookup: is there a permit covering `contracts`?
20963
- * No wallet prompt, no transport key pair generation. Returns `false` when no signer
20964
- * is configured.
20339
+ * The cache TTL in milliseconds.
20340
+ * Exposed so query option factories can set a matching `staleTime`.
20965
20341
  */
20966
- hasPermit(contracts: Address[]): Promise<boolean>;
20342
+ get ttlMs(): number;
20967
20343
  /**
20968
- * Pure store lookup for a delegation permit. See {@link hasPermit}.
20344
+ * Resolve the registry contract address for the current chain.
20969
20345
  *
20970
- * @param delegator - The address that delegated decryption rights to the connected signer.
20971
- * @param contracts - Contract addresses to check.
20972
- * @returns `true` if cached delegation permits cover all requested contracts.
20346
+ * Priority: `registryAddresses[chainId]` \> built-in default.
20347
+ *
20348
+ * @returns The registry contract address for the connected chain.
20349
+ * @throws if no address is configured for the chain. {@link ConfigurationError}
20973
20350
  */
20974
- hasDelegationPermit(delegator: Address, contracts: Address[]): Promise<boolean>;
20351
+ getRegistryAddress(): Promise<Address>;
20975
20352
  /**
20976
- * Best-effort transport-key-pair prefetch for the connected signer.
20353
+ * List token wrapper pairs with page-based pagination.
20977
20354
  *
20978
- * Optional latency optimization: decrypt and permit flows remain correct
20979
- * without it because they lazily create the transport key pair when needed.
20355
+ * Internally maps to `getTokenConfidentialTokenPairsSlice` on-chain.
20980
20356
  *
20981
- * Silent no-op when no signer is configured or no wallet account is
20982
- * available. The transport key pair is generated through the relayer dispatcher's
20983
- * currently active chain — see {@link LifecycleService}, which calls
20984
- * `switchChain` before fanning the wallet-account change out to listeners,
20985
- * so any downstream caller (including React adapters) observes the
20986
- * dispatcher on the wallet chain by the time it invokes warmup.
20357
+ * @param options - Pagination and enrichment options.
20358
+ * @returns A {@link PaginatedResult} of pairs.
20987
20359
  *
20988
- * Not for pre-warming a shared `transportKeyPairScope`: this call's wallet-account
20989
- * precondition doesn't conceptually apply to a scope-wide key, and would silently
20990
- * no-op precisely when an operator is most likely to be calling it (no end-user
20991
- * connected yet). Use {@link warmTransportKeyPairScope} instead.
20360
+ * @example
20361
+ * ```ts
20362
+ * const result = await registry.listPairs({ page: 1, pageSize: 20 });
20363
+ * console.log(`${result.total} pairs, showing page ${result.page}`);
20364
+ *
20365
+ * // With on-chain metadata
20366
+ * const withMeta = await registry.listPairs({ metadata: true, pageSize: 10 });
20367
+ * for (const pair of withMeta.items) {
20368
+ * console.log(pair.underlying.symbol, "→", pair.confidential.symbol);
20369
+ * }
20370
+ * ```
20992
20371
  */
20993
- warmTransportKeyPair(): Promise<void>;
20372
+ listPairs(options: ListPairsOptions & {
20373
+ metadata: true;
20374
+ }): Promise<PaginatedResult<TokenWrapperPairWithMetadata>>;
20375
+ /** Lists registered underlying/confidential token pairs; pass `{ metadata: true }` to include on-chain token metadata. */
20376
+ listPairs(options?: ListPairsOptions): Promise<PaginatedResult<TokenWrapperPair>>;
20994
20377
  /**
20995
- * Wipe FHE permits for the current signer.
20378
+ * Look up the confidential token for a given plain ERC-20 address.
20996
20379
  *
20997
- * - With no argument: every permit referencing this signer is removed across
20998
- * all chains and delegators. The transport key pair survives — use {@link clear} to
20999
- * also wipe the transport key pair.
21000
- * - With a contract list: every signed permit in the direct-decrypt scope
21001
- * (current chain) whose immutable payload touches any listed address is
21002
- * removed. Delegation permits are not touched in this mode.
20380
+ * @param tokenAddress - The plain ERC-20 token address.
20381
+ * @returns The lookup result, or `null` if the token has never been registered.
20382
+ * **Note:** revoked tokens (registered then invalidated) return a non-null result
20383
+ * with `isValid: false`. Check `result.isValid` explicitly rather than using
20384
+ * `if (result)` to guard against processing revoked tokens.
21003
20385
  *
21004
- * @throws if no signer is configured. {@link SignerNotConfiguredError}
20386
+ * @example
20387
+ * ```ts
20388
+ * const result = await registry.getConfidentialToken(usdcAddress);
20389
+ * if (result?.isValid) {
20390
+ * console.log(result.confidentialTokenAddress);
20391
+ * }
20392
+ * ```
21005
20393
  */
21006
- revokePermits(contracts?: Address[]): Promise<void>;
20394
+ getConfidentialToken(tokenAddress: Address): Promise<{
20395
+ confidentialTokenAddress: Address;
20396
+ isValid: boolean;
20397
+ } | null>;
21007
20398
  /**
21008
- * Wipe the transport key pair for the current signer and cascade-delete every permit
21009
- * (across chains and delegators) referencing it.
20399
+ * Reverse lookup — find the plain ERC-20 for a given confidential token.
21010
20400
  *
21011
- * @throws if no signer is configured. {@link SignerNotConfiguredError}
20401
+ * @param confidentialTokenAddress - The confidential token address.
20402
+ * @returns The lookup result, or `null` if no pair is registered.
20403
+ *
20404
+ * @example
20405
+ * ```ts
20406
+ * const result = await registry.getUnderlyingToken(cUsdcAddress);
20407
+ * if (result) {
20408
+ * console.log(result.tokenAddress, result.isValid);
20409
+ * }
20410
+ * ```
21012
20411
  */
21013
- clear(): Promise<void>;
20412
+ getUnderlyingToken(confidentialTokenAddress: Address): Promise<{
20413
+ tokenAddress: Address;
20414
+ isValid: boolean;
20415
+ } | null>;
21014
20416
  /**
21015
- * Revoke the shared transport key pair for `transportKeyPairScope` (operator-level
21016
- * action — no wallet account needs to be connected, but a signer must still be
21017
- * configured on this SDK instance at construction time).
20417
+ * Fetch all token wrapper pairs from the registry.
21018
20418
  *
21019
- * Deletes the shared key pair; every permit in the scope embeds its public key, so
21020
- * they're all treated as stale on next access. Signer-level {@link clear} never does
21021
- * this — it only ever wipes the calling signer's own permits.
20419
+ * @returns All registered `TokenWrapperPair` entries.
20420
+ */
20421
+ getTokenPairs(): Promise<readonly TokenWrapperPair[]>;
20422
+ /**
20423
+ * Get the total number of token wrapper pairs.
21022
20424
  *
21023
- * Not best-effort, unlike most credential-store writes: a storage failure rejects
21024
- * instead of being logged and swallowed. This is the primitive an operator reaches
21025
- * for on suspected key compromise — a resolved promise must mean the key pair is
21026
- * actually gone.
20425
+ * @returns The count as a bigint.
20426
+ */
20427
+ getTokenPairsLength(): Promise<bigint>;
20428
+ /**
20429
+ * Fetch a range of token wrapper pairs (paginated by index).
21027
20430
  *
21028
- * Stops the SDK from reissuing or reusing the deleted key — does not revoke any
21029
- * permit already issued under it. A permit is a self-contained, bearer-style EIP-712
21030
- * signature the relayer accepts independently of this SDK; one exfiltrated alongside
21031
- * the key remains usable until its own `permitTTL` expiry regardless of this call.
20431
+ * @param fromIndex - Start index (inclusive).
20432
+ * @param toIndex - End index (exclusive).
20433
+ * @returns The slice of `TokenWrapperPair` entries.
20434
+ */
20435
+ getTokenPairsSlice(fromIndex: bigint, toIndex: bigint): Promise<readonly TokenWrapperPair[]>;
20436
+ /**
20437
+ * Fetch a single token wrapper pair by index.
21032
20438
  *
21033
- * @param scopeId - Must match the configured `transportKeyPairScope`, as a guard
21034
- * against revoking the wrong scope by mistake.
21035
- * @throws if no signer is configured. {@link SignerNotConfiguredError}
21036
- * @throws if no scope is configured, or `scopeId` doesn't match it. {@link ConfigurationError}
21037
- * @throws if the underlying storage delete fails.
20439
+ * @param index - Zero-based pair index.
20440
+ * @returns The `TokenWrapperPair` at that index.
21038
20441
  */
21039
- revokeTransportKeyPair(scopeId: string): Promise<void>;
20442
+ getTokenPair(index: bigint): Promise<TokenWrapperPair>;
21040
20443
  /**
21041
- * Warm the shared transport key pair for `transportKeyPairScope` (operator-level —
21042
- * no wallet account needs to be connected, but a signer must still be configured on
21043
- * this SDK instance at construction time) — the pre-warm counterpart to
21044
- * {@link revokeTransportKeyPair}. Prefer this over {@link warmTransportKeyPair} for a
21045
- * scoped key pair: unlike that method, this never silently no-ops for lack of a
21046
- * connected wallet, because a scope-wide key was never tied to one in the first place.
20444
+ * Look up the confidential token address for a given plain ERC-20 token.
21047
20445
  *
21048
- * @param scopeId - Must match the configured `transportKeyPairScope`, as a guard
21049
- * against warming the wrong scope by mistake.
21050
- * @throws if no signer is configured. {@link SignerNotConfiguredError}
21051
- * @throws if no scope is configured, or `scopeId` doesn't match it. {@link ConfigurationError}
20446
+ * @param tokenAddress - The plain ERC-20 token address.
20447
+ * @returns A tuple `[isValid, confidentialTokenAddress]`. `isValid` is `true` only for a
20448
+ * registered, non-revoked wrapper. The address is the zero address when no pair is registered.
20449
+ * A non-zero address with `isValid=false` means the wrapper was registered but later revoked.
21052
20450
  */
21053
- warmTransportKeyPairScope(scopeId: string): Promise<void>;
20451
+ getConfidentialTokenAddress(tokenAddress: Address): Promise<readonly [boolean, Address]>;
20452
+ /**
20453
+ * Reverse lookup — find the plain ERC-20 for a given confidential token.
20454
+ *
20455
+ * @param confidentialTokenAddress - The confidential token address.
20456
+ * @returns A tuple `[isValid, tokenAddress]`. `isValid` is `true` only for a registered,
20457
+ * non-revoked wrapper. The address is the zero address when no pair is registered.
20458
+ * A non-zero address with `isValid=false` means the wrapper was registered but later revoked.
20459
+ */
20460
+ getTokenAddress(confidentialTokenAddress: Address): Promise<readonly [boolean, Address]>;
20461
+ /**
20462
+ * Check whether a confidential token is registered and valid.
20463
+ *
20464
+ * @param confidentialTokenAddress - The confidential token address to check.
20465
+ * @returns `true` if the token is a known valid wrapper in the registry.
20466
+ */
20467
+ isConfidentialTokenValid(confidentialTokenAddress: Address): Promise<boolean>;
21054
20468
  }
21055
20469
  //#endregion
21056
20470
  //#region src/zama-sdk.d.ts
@@ -21064,8 +20478,11 @@ declare class Permits {
21064
20478
  */
21065
20479
  declare class ZamaSDK {
21066
20480
  #private;
20481
+ /** Read-only chain access used for all contract reads. */
21067
20482
  readonly provider: GenericProvider;
20483
+ /** Wallet signer used for write operations, or `undefined` when the SDK is read-only. */
21068
20484
  readonly signer: GenericSigner | undefined;
20485
+ /** Storage for cached permits and transport key pairs. */
21069
20486
  readonly storage: GenericStorage;
21070
20487
  /**
21071
20488
  * A {@link WrappersRegistry} instance auto-configured for the current chain.
@@ -21079,43 +20496,10 @@ declare class ZamaSDK {
21079
20496
  /** FHE decryption (user, delegated user, public). */
21080
20497
  readonly decryption: Decryption;
21081
20498
  constructor(config: ZamaConfig);
21082
- /**
21083
- * Subscribe to wallet account transitions.
21084
- *
21085
- * @param listener - Called on each transition with a {@link WalletAccountChange} carrying
21086
- * `previous` and `next` wallet account snapshots; either may be `undefined` for
21087
- * connect and disconnect transitions.
21088
- * @returns An unsubscribe function; calling it removes the listener.
21089
- *
21090
- * @internal
21091
- */
21092
- onWalletAccountChange(listener: WalletAccountListener): () => void;
21093
- /**
21094
- * The SDK-wide logger, exposed so contract abstractions ({@link Token},
21095
- * {@link WrappedToken}) can route their best-effort failures through the
21096
- * same sink. Silent by default.
21097
- *
21098
- * @internal
21099
- */
21100
- get logger(): GenericLogger;
21101
20499
  /**
21102
20500
  * The single-chain relayer backend for the **currently active** chain.
21103
- *
21104
- * @internal
21105
- */
21106
- get relayer(): FhevmRelayerSDK;
21107
- /**
21108
- * Emit a structured SDK event into the unified SDK event stream.
21109
- *
21110
- * Listener exceptions are caught and logged so that a misbehaving subscriber
21111
- * can never corrupt SDK operations.
21112
- *
21113
- * Application code should subscribe via the `onEvent` config option, never
21114
- * call this directly.
21115
- *
21116
- * @internal
21117
20501
  */
21118
- emitEvent(input: ZamaSDKEventInput, tokenAddress?: Address): void;
20502
+ get relayer(): RelayerSDK;
21119
20503
  /**
21120
20504
  * Create a {@link WrappersRegistry} instance bound to this SDK's provider.
21121
20505
  * Inherits the registry addresses derived from the SDK's chain configs, so
@@ -21211,5 +20595,94 @@ declare class ZamaSDK {
21211
20595
  [Symbol.dispose](): void;
21212
20596
  }
21213
20597
  //#endregion
21214
- export { confidentialTransferAndCallMutationOptions as $, filterQueryOptions as $n, DelegationExpiryUnchangedError as $t, encryptMutationOptions as A, isWrapperQueryOptions as An, confidentialTransferContract as Ar, SigningRejectedError as At, UnshieldAllParams as B, invalidateAfterTransfer as Bn, wrapContract as Br, BalanceErrorDetails as Bt, grantPermitMutationOptions as C, Permission as Cn, approveContract as Cr, WrappedToken as Ct, DecryptResult as D, totalSupplyQueryOptions as Dn, symbolContract as Dr, matchZamaError as Dt, delegatedDecryptValuesMutationOptions as E, TotalSupplyQueryConfig as En, nameContract as Er, Token as Et, wrapMutationOptions as F, QueryFilterLike as Fn, rateContract as Fr, RpcRateLimitError as Ft, approveUnderlyingMutationOptions as G, invalidateBalanceQueries as Gn, DecryptionFailedError as Gt, UnshieldParams as H, invalidateAfterUnshieldSettled as Hn, resolveChainRelayers as Hr, InsufficientAllowanceError as Ht, UnwrapParams as I, QueryLike as In, setOperatorContract as Ir, NotEntitledError as It, ConfidentialTransferFromAndCallParams as J, zamaQueryKeys as Jn, DelegationContractIsSelfError as Jt, ConfidentialSetOperatorParams as K, invalidateWagmiBalanceQueries as Kn, EncryptionFailedError as Kt, unwrapMutationOptions as L, invalidateAfterApproveUnderlying as Ln, underlyingContract as Lr, ConfigurationError as Lt, finalizeUnwrapMutationOptions as M, TokenMetadataQueryConfig as Mn, finalizeUnwrapContract as Mr, SignerRequiredError as Mt, unwrapAllMutationOptions as N, tokenMetadataQueryOptions as Nn, inferredTotalSupplyContract as Nr, WalletAccountNotReadyError as Nt, EncryptedInput as O, IsConfidentialQueryConfig as On, confidentialBalanceOfContract as Or, TransactionRevertedError as Ot, WrapParams as P, QueryClientLike as Pn, isOperatorContract as Pr, WalletNotConnectedError as Pt, ConfidentialTransferAndCallParams as Q, StrippedQueryOptionKeys as Qn, DelegationExpiredError as Qt, ResumeUnshieldParams as R, invalidateAfterSetOperator as Rn, unwrapContract as Rr, RelayerRequestFailedError as Rt, hasPermitQueryOptions as S, WrappersRegistryConfig as Sn, allowanceContract as Sr, confidentialBalanceQueryOptions as St, DelegatedDecryptValuesMutationParams as T, StoredTransportKeyPair as Tn, decimalsContract as Tr, BatchDecryptAsOptions as Tt, unshieldMutationOptions as U, invalidateAfterUnwrap as Un, resolveStorage as Ur, InsufficientConfidentialBalanceError as Ut, unshieldAllMutationOptions as V, invalidateAfterUnshield as Vn, ResolvedChainRelayer as Vr, ERC20ReadFailedError as Vt, ApproveUnderlyingParams as W, invalidateAfterWrap as Wn, createConfig as Wr, InsufficientERC20BalanceError as Wt, ConfidentialTransferFromParams as X, MutationFactoryOptions as Xn, DelegationDelegateEqualsContractError as Xt, confidentialTransferFromAndCallMutationOptions as Y, SignerQueryContext as Yn, DelegationCooldownError as Yt, confidentialTransferFromMutationOptions as Z, QueryFactoryOptions as Zn, DelegationExpirationTooSoonError as Zt, DelegateDecryptionParams as _, WrapperDiscoveryQueryConfig as _n, ERC7984_INTERFACE_ID as _r, tokenPairsQueryOptions as _t, BatchDecryptItem as a, TransportKeyPairExpiredError as an, getTokenAddressContract as ar, IsConfidentialTokenValidQueryConfig as at, revokePermitsMutationOptions as b, ListPairsOptions as bn, isConfidentialWrapperContract as br, confidentialBalancesQueryOptions as bt, DelegationStatusQueryConfig as c, ZamaErrorCode as cn, getTokenPairsLengthContract as cr, TokenPairQueryConfig as ct, RevokeDelegationParams as d, ConfidentialIsOperatorQueryConfig as dn, delegateForUserDecryptionContract as dr, confidentialTokenAddressQueryOptions as dt, DelegationNotFoundError as en, hashFn as er, ConfidentialTransferParams as et, revokeDelegationMutationOptions as f, confidentialIsOperatorQueryOptions as fn, getDelegationExpiryContract as fr, isConfidentialTokenValidQueryOptions as ft, decryptBalanceAsMutationOptions as g, underlyingAllowanceQueryOptions as gn, ERC1363_INTERFACE_ID as gr, tokenPairsLengthQueryOptions as gt, DecryptBalanceAsParams as h, UnderlyingAllowanceQueryConfig as hn, transferAndCallContract as hr, tokenPairQueryOptions as ht, Decryption as i, NoCiphertextError as in, getConfidentialTokenAddressContract as ir, ConfidentialTokenAddressQueryConfig as it, FinalizeUnwrapParams as j, TokenMetadata as jn, confidentialTransferFromContract as jr, SignerNotConfiguredError as jt, decryptValuesQueryOptions as k, isConfidentialQueryOptions as kn, confidentialTotalSupplyContract as kr, SigningFailedError as kt, delegationStatusQueryOptions as l, isRetryable as ln, getTokenPairsSliceContract as lr, TokenPairsSliceQueryConfig as lt, batchDecryptBalancesAsMutationOptions as m, pendingUnshieldQueryOptions as mn, revokeDelegationContract as mr, tokenAddressQueryOptions as mt, Permits as n, DelegationSelfNotAllowedError as nn, TokenWrapperPair as nr, ShieldParams as nt, BatchDecryptResult as o, ChainMismatchError as on, getTokenPairContract as or, ListPairsQueryConfig as ot, BatchDecryptBalancesAsParams as p, PendingUnshieldQueryConfig as pn, isHandleDelegatedContract as pr, listPairsQueryOptions as pt, confidentialSetOperatorMutationOptions as q, invalidateWalletLifecycleQueries as qn, AclPausedError as qt, Delegations as r, InvalidTransportKeyPairError as rn, TokenWrapperPairWithMetadata as rr, shieldMutationOptions as rt, DelegatedDecryptOptions as s, ZamaError as sn, getTokenPairsContract as sr, TokenAddressQueryConfig as st, ZamaSDK as t, DelegationNotPropagatedError as tn, PaginatedResult as tr, confidentialTransferMutationOptions as tt, DelegationStatus as u, retryAfterSeconds as un, isConfidentialTokenValidContract as ur, WrappersRegistryQueryConfig as ut, delegateDecryptionMutationOptions as v, wrapperDiscoveryQueryOptions as vn, ERC7984_WRAPPER_INTERFACE_ID as vr, tokenPairsSliceQueryOptions as vt, decryptPublicValuesMutationOptions as w, SerializedTransportKeyPair as wn, balanceOfContract as wr, BatchBalancesResult as wt, HasPermitQueryConfig as x, WrappersRegistry as xn, supportsInterfaceContract as xr, ConfidentialBalanceQueryConfig as xt, clearCredentialsMutationOptions as y, DefaultRegistryAddresses as yn, isConfidentialTokenContract as yr, ConfidentialBalancesQueryConfig as yt, resumeUnshieldMutationOptions as z, invalidateAfterShield as zn, unwrapFromBalanceContract as zr, BalanceCheckUnavailableError as zt };
21215
- //# sourceMappingURL=zama-sdk-BhD6nWLL.d.ts.map
20598
+ //#region src/utils/handles.d.ts
20599
+ /** All-zero encrypted-value sentinel — a 32-byte zero handle representing the cleartext value `0`. */
20600
+ declare const ZERO_ENCRYPTED_VALUE: "0x0000000000000000000000000000000000000000000000000000000000000000";
20601
+ /**
20602
+ * Check whether an encrypted value represents the zero value.
20603
+ */
20604
+ declare function isEncryptedValueZero(encryptedValue: string): boolean;
20605
+ //#endregion
20606
+ //#region src/storage/memory-storage.d.ts
20607
+ /** In-memory credential store. Credentials are lost on page reload. */
20608
+ declare class MemoryStorage implements GenericStorage {
20609
+ #private;
20610
+ /**
20611
+ * Retrieve a value by key.
20612
+ * @returns The stored value, or `null` if the key does not exist.
20613
+ */
20614
+ get<T = unknown>(key: string): Promise<T | null>;
20615
+ /** Store a value under the given key, overwriting any existing entry. */
20616
+ set<T = unknown>(key: string, value: T): Promise<void>;
20617
+ /** Remove the entry for the given key (no-op if absent). */
20618
+ delete(key: string): Promise<void>;
20619
+ }
20620
+ /** Default singleton for application-wide use. */
20621
+ declare const memoryStorage: MemoryStorage;
20622
+ //#endregion
20623
+ //#region src/storage/indexeddb-storage.d.ts
20624
+ /**
20625
+ * IndexedDB-backed {@link GenericStorage}.
20626
+ *
20627
+ * Stores keypair and permit objects keyed by a hashed wallet address. The
20628
+ * SDK delegates security to the storage backend — values are persisted
20629
+ * verbatim with no SDK-layer encryption.
20630
+ */
20631
+ declare class IndexedDBStorage implements GenericStorage {
20632
+ #private;
20633
+ constructor(dbName?: string, dbVersion?: number, storeName?: string);
20634
+ /**
20635
+ * Retrieve a value by key.
20636
+ * @returns The stored value, or `null` if the key does not exist.
20637
+ */
20638
+ get<T = unknown>(key: string): Promise<T | null>;
20639
+ /** Store a value under the given key, overwriting any existing entry. */
20640
+ set<T = unknown>(key: string, value: T): Promise<void>;
20641
+ /** Remove the entry for the given key (no-op if absent). */
20642
+ delete(key: string): Promise<void>;
20643
+ /** Remove all stored entries. */
20644
+ clear(): Promise<void>;
20645
+ }
20646
+ /** Default singleton for application-wide use. */
20647
+ declare const indexedDBStorage: IndexedDBStorage;
20648
+ //#endregion
20649
+ //#region src/storage/chrome-session-storage.d.ts
20650
+ /**
20651
+ * {@link GenericStorage} backed by `chrome.storage.session`.
20652
+ *
20653
+ * Use this in MV3 web extensions so the wallet signature survives
20654
+ * service worker restarts and is shared across popup, background,
20655
+ * and content script contexts.
20656
+ *
20657
+ * @example
20658
+ * ```ts
20659
+ * import { ZamaSDK, indexedDBStorage, chromeSessionStorage } from "@zama-fhe/sdk";
20660
+ * import { createConfig } from "@zama-fhe/sdk/viem";
20661
+ *
20662
+ * const config = createConfig({
20663
+ * chains: [mySepolia],
20664
+ * publicClient,
20665
+ * walletClient,
20666
+ * relayers: { [mySepolia.id]: web() },
20667
+ * storage: indexedDBStorage, // encrypted transport key pair — persistent
20668
+ * permitStorage: chromeSessionStorage, // signed permits — ephemeral
20669
+ * });
20670
+ * const sdk = new ZamaSDK(config);
20671
+ * ```
20672
+ */
20673
+ declare class ChromeSessionStorage implements GenericStorage {
20674
+ /**
20675
+ * Retrieve a value by key.
20676
+ * @returns The stored value, or `null` if the key does not exist.
20677
+ */
20678
+ get<T = unknown>(key: string): Promise<T | null>;
20679
+ /** Store a value under the given key, overwriting any existing entry. */
20680
+ set(key: string, value: unknown): Promise<void>;
20681
+ /** Remove the entry for the given key (no-op if absent). */
20682
+ delete(key: string): Promise<void>;
20683
+ }
20684
+ /** Default singleton for application-wide use. */
20685
+ declare const chromeSessionStorage: ChromeSessionStorage;
20686
+ //#endregion
20687
+ export { AclPausedError as $, confidentialTransferContract as $t, BatchDecryptResult as A, getTokenPairsContract as At, WalletNotConnectedError as B, ERC7984_INTERFACE_ID as Bt, BatchDecryptAsOptions as C, QueryFactoryOptions as Ct, DelegationStatus as D, getConfidentialTokenAddressContract as Dt, Delegations as E, TokenWrapperPairWithMetadata as Et, SigningFailedError as F, getDelegationExpiryContract as Ft, BalanceCheckUnavailableError as G, allowanceContract as Gt, NotEntitledError as H, isConfidentialTokenContract as Ht, SigningRejectedError as I, isHandleDelegatedContract as It, InsufficientAllowanceError as J, decimalsContract as Jt, BalanceErrorDetails as K, approveContract as Kt, SignerNotConfiguredError as L, revokeDelegationContract as Lt, ErrorForCode as M, getTokenPairsSliceContract as Mt, matchZamaError as N, isConfidentialTokenValidContract as Nt, Decryption as O, getTokenAddressContract as Ot, TransactionRevertedError as P, delegateForUserDecryptionContract as Pt, EncryptionFailedError as Q, confidentialTotalSupplyContract as Qt, SignerRequiredError as R, transferAndCallContract as Rt, BatchBalancesResult as S, MutationFactoryOptions as St, Permits as T, TokenWrapperPair as Tt, ConfigurationError as U, isConfidentialWrapperContract as Ut, RpcRateLimitError as V, ERC7984_WRAPPER_INTERFACE_ID as Vt, RelayerRequestFailedError as W, supportsInterfaceContract as Wt, InsufficientERC20BalanceError as X, symbolContract as Xt, InsufficientConfidentialBalanceError as Y, nameContract as Yt, DecryptionFailedError as Z, confidentialBalanceOfContract as Zt, SerializedPermit as _, DecryptResult as _t, IndexedDBStorage as a, setOperatorContract as an, DelegationExpiryUnchangedError as at, ChecksummedAddress as b, SignerQueryContext as bt, memoryStorage as c, unwrapFromBalanceContract as cn, DelegationSelfNotAllowedError as ct, ZamaSDK as d, TransportKeyPairExpiredError as dt, confidentialTransferFromContract as en, DelegationContractIsSelfError as et, DefaultRegistryAddresses as f, ChainMismatchError as ft, Permission as g, retryAfterSeconds as gt, WrappersRegistryConfig as h, isRetryable as ht, chromeSessionStorage as i, rateContract as in, DelegationExpiredError as it, DelegatedDecryptOptions as j, getTokenPairsLengthContract as jt, BatchDecryptItem as k, getTokenPairContract as kt, ZERO_ENCRYPTED_VALUE as l, wrapContract as ln, InvalidTransportKeyPairError as lt, WrappersRegistry as m, ZamaErrorCode as mt, Hex$1 as n, inferredTotalSupplyContract as nn, DelegationDelegateEqualsContractError as nt, indexedDBStorage as o, underlyingContract as on, DelegationNotFoundError as ot, ListPairsOptions as p, ZamaError as pt, ERC20ReadFailedError as q, balanceOfContract as qt, ChromeSessionStorage as r, isOperatorContract as rn, DelegationExpirationTooSoonError as rt, MemoryStorage as s, unwrapContract as sn, DelegationNotPropagatedError as st, Address$1 as t, finalizeUnwrapContract as tn, DelegationCooldownError as tt, isEncryptedValueZero as u, createConfig as un, NoCiphertextError as ut, SerializedPermitEip712 as v, EncryptedInput as vt, Token as w, PaginatedResult as wt, WrappedToken as x, zamaQueryKeys as xt, SerializedTransportKeyPair as y, decryptValuesQueryOptions as yt, WalletAccountNotReadyError as z, ERC1363_INTERFACE_ID as zt };
20688
+ //# sourceMappingURL=index-DLaQtvYu.d.ts.map