@zama-fhe/sdk 2.3.0-alpha.4 → 2.3.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 (34) hide show
  1. package/dist/cjs/activity.cjs +1 -1
  2. package/dist/cjs/index.cjs +2 -2
  3. package/dist/cjs/index.cjs.map +1 -1
  4. package/dist/cjs/query/index.cjs +1 -1
  5. package/dist/cjs/query/index.cjs.map +1 -1
  6. package/dist/cjs/relayer.cjs +1 -1
  7. package/dist/cjs/relayer.cjs.map +1 -1
  8. package/dist/esm/{activity-CitpHeLO.d.ts → activity-DTBvolDB.d.ts} +195 -15
  9. package/dist/esm/{activity-CNU7ZLpc.js → activity-b2RsqKHW.js} +2 -2
  10. package/dist/esm/{activity-CNU7ZLpc.js.map → activity-b2RsqKHW.js.map} +1 -1
  11. package/dist/esm/cleartext/index.d.ts +2 -2
  12. package/dist/esm/cleartext/index.js +1 -1
  13. package/dist/esm/{cleartext-BO5OIem2.js → cleartext-Bzxet3H7.js} +2 -2
  14. package/dist/esm/{cleartext-BO5OIem2.js.map → cleartext-Bzxet3H7.js.map} +1 -1
  15. package/dist/esm/{encryption-UaXE1L_W.js → encryption-CmIPBcfP.js} +2 -2
  16. package/dist/esm/{encryption-UaXE1L_W.js.map → encryption-CmIPBcfP.js.map} +1 -1
  17. package/dist/esm/ethers/index.d.ts +2 -2
  18. package/dist/esm/{index-C3ELlhM8.d.ts → index-BXdXzzx4.d.ts} +2 -2
  19. package/dist/esm/index.d.ts +5 -128
  20. package/dist/esm/index.js +2 -2
  21. package/dist/esm/index.js.map +1 -1
  22. package/dist/esm/node/index.d.ts +2 -2
  23. package/dist/esm/node/index.js +1 -1
  24. package/dist/esm/query/index.d.ts +10 -18
  25. package/dist/esm/query/index.js +1 -1
  26. package/dist/esm/query/index.js.map +1 -1
  27. package/dist/esm/relayer-C6u3eOlN.js +2 -0
  28. package/dist/esm/relayer-C6u3eOlN.js.map +1 -0
  29. package/dist/esm/{relayer-sdk-Cqx3HnZh.d.ts → relayer-sdk-C_4bkxxH.d.ts} +2 -2
  30. package/dist/esm/{relayer-sdk.types-BhV3n5qO.d.ts → relayer-sdk.types-C9GAgQ7q.d.ts} +23 -2
  31. package/dist/esm/viem/index.d.ts +2 -2
  32. package/package.json +1 -1
  33. package/dist/esm/relayer-DfjPWTBf.js +0 -2
  34. package/dist/esm/relayer-DfjPWTBf.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["#dbName","#dbVersion","#storeName","#db","#dbPromise","#withTransaction","#getDB","workerFilename","workerCode","#config","#status","#initError","#getWorkerConfig","#ensureWorker","#ensureLock","#ensureWorkerInner","#workerClient","#initPromise","#artifactCache","#terminated","#resolvedChainId","#tearDown","#artifactStorage","#setStatus","#initWorker","#refreshCsrfToken","#getUnderlying","#underlying","#underlyingPromise","#ensureAllowance","#waitAndFinalizeUnshield","#batchDelegationOp","#addresses","#ttlMs","#cache","#getCached","#setCached","#pairWithMetadata","#registryTTL","#onEvent","#identityReady","#initIdentity","#unsubscribeSigner","#revokeByTrackedIdentity","#lastAddress","#lastChainId"],"sources":["../../src/errors/transaction.ts","../../src/errors/acl-revert.ts","../../src/storage/indexeddb-storage.ts","../../src/worker/browser-extension.ts","../../src/worker/worker.client.ts","../../src/relayer/relayer-web.ts","../../src/token/token.ts","../../src/wrappers-registry.ts","../../src/zama-sdk.ts","../../src/token/pending-unshield.ts","../../src/storage/chrome-session-storage.ts"],"sourcesContent":["import { ZamaError, ZamaErrorCode } from \"./base\";\n\n/** ERC-20 approval transaction failed. */\nexport class ApprovalFailedError extends ZamaError {\n constructor(message: string, options?: ErrorOptions) {\n super(ZamaErrorCode.ApprovalFailed, message, options);\n this.name = \"ApprovalFailedError\";\n }\n}\n\n/** On-chain transaction reverted. */\nexport class TransactionRevertedError extends ZamaError {\n constructor(message: string, options?: ErrorOptions) {\n super(ZamaErrorCode.TransactionReverted, message, options);\n this.name = \"TransactionRevertedError\";\n }\n}\n","import type { ZamaError } from \"./base\";\nimport {\n AclPausedError,\n DelegationContractIsSelfError,\n DelegationCooldownError,\n DelegationDelegateEqualsContractError,\n DelegationExpirationTooSoonError,\n DelegationExpiryUnchangedError,\n DelegationNotFoundError,\n DelegationSelfNotAllowedError,\n} from \"./delegation\";\n\n/** Extract the decoded error name from a viem ContractFunctionRevertedError. */\nfunction extractRevertErrorName(error: unknown): string | null {\n if (!(error instanceof Error)) {\n return null;\n }\n const cause = error.cause;\n if (typeof cause !== \"object\" || cause === null || !(\"data\" in cause)) {\n return null;\n }\n const { data } = cause;\n if (typeof data !== \"object\" || data === null || !(\"errorName\" in data)) {\n return null;\n }\n return typeof data.errorName === \"string\" ? data.errorName : null;\n}\n\n/** ACL error name -> typed SDK error mapping. */\nconst ACL_ERROR_MAP: Record<string, (cause: Error | undefined) => ZamaError> = {\n AlreadyDelegatedOrRevokedInSameBlock: (cause) =>\n new DelegationCooldownError(\n \"Only one delegate/revoke per (delegator, delegate, contract) per block. Wait for the next block before retrying.\",\n { cause },\n ),\n SenderCannotBeContractAddress: (cause) =>\n new DelegationContractIsSelfError(\"The contract address cannot be the caller address.\", {\n cause,\n }),\n EnforcedPause: (cause) =>\n new AclPausedError(\n \"The ACL contract is paused. Delegation operations are temporarily disabled.\",\n { cause },\n ),\n SenderCannotBeDelegate: (cause) =>\n new DelegationSelfNotAllowedError(\"Cannot delegate to yourself (delegate === msg.sender).\", {\n cause,\n }),\n DelegateCannotBeContractAddress: (cause) =>\n new DelegationDelegateEqualsContractError(\n \"Delegate address cannot be the same as the contract address.\",\n { cause },\n ),\n ExpirationDateBeforeOneHour: (cause) =>\n new DelegationExpirationTooSoonError(\"Expiration date must be at least 1 hour in the future.\", {\n cause,\n }),\n ExpirationDateAlreadySetToSameValue: (cause) =>\n new DelegationExpiryUnchangedError(\"The new expiration date is the same as the current one.\", {\n cause,\n }),\n NotDelegatedYet: (cause) =>\n new DelegationNotFoundError(\"Cannot revoke: no active delegation exists.\", { cause }),\n};\n\n/**\n * Map known ACL Solidity revert error names to typed ZamaError subclasses.\n * Prefers viem's structured `error.cause.data.errorName` when available,\n * falling back to string-includes matching on the error message.\n * Returns `null` if the revert reason is not recognized.\n * @public\n */\nexport function matchAclRevert(error: unknown): ZamaError | null {\n const cause = error instanceof Error ? error : undefined;\n\n // Prefer structured error data from viem's ContractFunctionRevertedError\n const errorName = extractRevertErrorName(error);\n if (errorName && errorName in ACL_ERROR_MAP) {\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- guarded by `in` check above\n return ACL_ERROR_MAP[errorName]!(cause);\n }\n\n // Fallback: string matching for non-viem RPC providers\n const message = error instanceof Error ? error.message : String(error);\n for (const [name, factory] of Object.entries(ACL_ERROR_MAP)) {\n if (message.includes(name)) {\n return factory(cause);\n }\n }\n\n return null;\n}\n","\"use client\";\n\nimport type { GenericStorage } from \"../types\";\n\n/**\n * IndexedDB-backed {@link GenericStorage}.\n *\n * Stores encrypted credential objects keyed by a hashed wallet address.\n * Encryption is handled by {@link CredentialsManager} — this store only\n * persists opaque values.\n */\nexport class IndexedDBStorage implements GenericStorage {\n #db: IDBDatabase | null = null;\n #dbPromise: Promise<IDBDatabase> | null = null;\n #dbName: string;\n #dbVersion: number;\n #storeName: string;\n\n constructor(dbName = \"CredentialStore\", dbVersion = 1, storeName = \"credentials\") {\n this.#dbName = dbName;\n this.#dbVersion = dbVersion;\n this.#storeName = storeName;\n }\n\n #getDB(): Promise<IDBDatabase> {\n if (this.#db) {\n return Promise.resolve(this.#db);\n }\n if (this.#dbPromise) {\n return this.#dbPromise;\n }\n\n this.#dbPromise = new Promise((resolve, reject) => {\n const request = indexedDB.open(this.#dbName, this.#dbVersion);\n\n request.onupgradeneeded = () => {\n const db = request.result;\n if (!db.objectStoreNames.contains(this.#storeName)) {\n db.createObjectStore(this.#storeName, { keyPath: \"key\" });\n }\n };\n\n request.onsuccess = () => {\n this.#db = request.result;\n this.#dbPromise = null;\n this.#db.onversionchange = () => {\n // oxlint-disable-next-line no-console\n console.warn(\n `IndexedDB \"${this.#dbName}\" closing due to version change from another tab`,\n );\n this.#db?.close();\n this.#db = null;\n this.#dbPromise = null;\n };\n this.#db.onclose = () => {\n this.#db = null;\n this.#dbPromise = null;\n };\n resolve(this.#db);\n };\n\n request.onerror = () => {\n this.#db = null;\n this.#dbPromise = null;\n reject(request.error);\n };\n });\n\n return this.#dbPromise;\n }\n\n async #withTransaction<T>(\n mode: IDBTransactionMode,\n fn: (store: IDBObjectStore) => IDBRequest,\n ): Promise<T> {\n const db = await this.#getDB();\n return new Promise((resolve, reject) => {\n const tx = db.transaction(this.#storeName, mode);\n tx.onabort = () => reject(tx.error ?? new Error(\"Transaction aborted\"));\n const request = fn(tx.objectStore(this.#storeName));\n if (mode === \"readonly\") {\n request.onsuccess = () => resolve(request.result);\n } else {\n tx.oncomplete = () => resolve(request.result);\n }\n request.onerror = () => reject(request.error);\n });\n }\n\n async get<T = unknown>(key: string): Promise<T | null> {\n const result = await this.#withTransaction<{ value: T } | undefined>(\"readonly\", (store) =>\n store.get(key),\n );\n return result?.value ?? null;\n }\n\n async set<T = unknown>(key: string, value: T): Promise<void> {\n await this.#withTransaction<void>(\"readwrite\", (store) => store.put({ key, value }));\n }\n\n async delete(key: string): Promise<void> {\n await this.#withTransaction<void>(\"readwrite\", (store) => store.delete(key));\n }\n\n async clear(): Promise<void> {\n await this.#withTransaction<void>(\"readwrite\", (store) => store.clear());\n }\n}\n\n/** Default singleton for application-wide use. */\nexport const indexedDBStorage = new IndexedDBStorage();\n","import { assertFunctionProp, assertObject, assertStringProp } from \"../utils/assertions\";\n\n/**\n * Subset of the WebExtensions `runtime` API used by the SDK.\n * @see https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/runtime\n */\nexport interface BrowserExtensionRuntime {\n /** The ID of the extension. */\n id: string;\n /** Convert a relative path within the extension to a fully-qualified URL. */\n getURL: (path: string) => string;\n}\n\nfunction isValidRuntime(runtime: unknown): runtime is BrowserExtensionRuntime {\n try {\n assertObject(runtime, \"runtime\");\n assertStringProp(runtime, \"id\", \"runtime.id\");\n assertFunctionProp<\"getURL\", (path: string) => string>(runtime, \"getURL\", \"runtime.getURL\");\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Return the browser extension runtime object, or `undefined` outside extensions.\n * Works across Chrome/Edge (`chrome.runtime`) and Firefox/Safari (`browser.runtime`).\n * Extensions have restricted CSP that blocks `blob:` URLs, so callers use\n * this to detect the environment and resolve file URLs via `runtime.getURL`.\n */\nexport function getBrowserExtensionRuntime(): BrowserExtensionRuntime | undefined {\n const g = globalThis as unknown as Record<string, unknown>;\n for (const ns of [g.chrome, g.browser]) {\n try {\n assertObject(ns, \"ns\");\n if (isValidRuntime(ns.runtime)) {\n return ns.runtime;\n }\n } catch {\n continue;\n }\n }\n return undefined;\n}\n","import type { FhevmInstanceConfig } from \"@zama-fhe/relayer-sdk/bundle\";\nimport type {\n GenericLogger,\n UpdateCsrfResponseData,\n WorkerRequest,\n WorkerRequestType,\n WorkerResponse,\n} from \"./worker.types\";\nimport { BaseWorkerClient } from \"./worker.base-client\";\nimport { getBrowserExtensionRuntime } from \"./browser-extension\";\nimport { default as workerCode, filename as workerFilename } from \"./relayer-sdk.worker.ts?iife\";\n\n/** Configuration for the worker client */\nexport interface WorkerClientConfig {\n cdnUrl: string;\n fhevmConfig: FhevmInstanceConfig;\n csrfToken: string;\n /** Expected SHA-384 hex digest of the CDN bundle for integrity verification. */\n integrity?: string;\n /** Optional logger for tracing worker request lifecycle. */\n logger?: GenericLogger;\n /** Number of WASM threads for parallel FHE operations (passed to `initSDK({ thread })`). */\n thread?: number;\n}\n\n/**\n * Client for communicating with the RelayerSDK Web Worker.\n * Provides a promise-based API for FHE operations.\n */\nexport class RelayerWorkerClient extends BaseWorkerClient<Worker, WorkerClientConfig> {\n constructor(config: WorkerClientConfig) {\n super(config, config.logger);\n }\n\n protected createWorker(): Worker {\n const runtime = getBrowserExtensionRuntime();\n if (runtime) {\n return new Worker(runtime.getURL(workerFilename));\n }\n const blobUrl = URL.createObjectURL(new Blob([workerCode], { type: \"application/javascript\" }));\n try {\n return new Worker(blobUrl);\n } finally {\n URL.revokeObjectURL(blobUrl);\n }\n }\n\n protected wireEvents(worker: Worker): void {\n worker.onmessage = (event: MessageEvent<WorkerResponse<unknown>>) =>\n this.handleResponse(event.data);\n worker.onerror = (event: ErrorEvent) => this.handleWorkerError(event.message);\n worker.onmessageerror = () => this.handleWorkerMessageError();\n }\n\n protected postMessage(worker: Worker, request: WorkerRequest): void {\n worker.postMessage(request);\n }\n\n protected terminateWorker(worker: Worker): void {\n worker.terminate();\n }\n\n protected generateRequestId(): string {\n return crypto.randomUUID();\n }\n\n protected getInitPayload(): {\n type: WorkerRequestType;\n payload: WorkerRequest[\"payload\"];\n } {\n // Explicitly construct the payload from serializable fields only.\n // Functions (e.g. `logger`) cannot be cloned by the structured clone\n // algorithm used by `worker.postMessage()`.\n const { cdnUrl, fhevmConfig, csrfToken, integrity, thread } = this.config;\n return { type: \"INIT\", payload: { cdnUrl, fhevmConfig, csrfToken, integrity, thread } };\n }\n\n /**\n * Update the CSRF token in the worker.\n * Call this before making authenticated requests to ensure the token is fresh.\n */\n async updateCsrf(csrfToken: string): Promise<void> {\n await this.sendRequest<UpdateCsrfResponseData>(\"UPDATE_CSRF\", {\n csrfToken,\n });\n }\n}\n","import type {\n InputProofBytesType,\n KeypairType,\n KmsDelegatedUserDecryptEIP712Type,\n ZKProofLike,\n} from \"@zama-fhe/relayer-sdk/bundle\";\nimport type { Address, Hex } from \"viem\";\nimport { ConfigurationError, ZamaError } from \"../errors\";\nimport { IndexedDBStorage } from \"../storage/indexeddb-storage\";\nimport type { GenericStorage } from \"../types\";\nimport { RelayerWorkerClient, type WorkerClientConfig } from \"../worker/worker.client\";\nimport { FheArtifactCache } from \"./fhe-artifact-cache\";\nimport type { RelayerSDK } from \"./relayer-sdk\";\nimport type {\n ClearValueType,\n DelegatedUserDecryptParams,\n EIP712TypedData,\n EncryptParams,\n EncryptResult,\n Handle,\n PublicDecryptResult,\n RelayerSDKStatus,\n RelayerWebConfig,\n UserDecryptParams,\n} from \"./relayer-sdk.types\";\nimport { buildEIP712DomainType, DefaultConfigs, withRetry } from \"./relayer-utils\";\n\n/**\n * Pinned relayer SDK version used for the WASM CDN bundle.\n * Update this when upgrading @zama-fhe/relayer-sdk, and keep the\n * peerDependencies range in package.json in sync (~x.y.z).\n */\nconst RELAYER_SDK_VERSION = \"0.4.2\";\nconst CDN_URL = `https://cdn.zama.org/relayer-sdk-js/${RELAYER_SDK_VERSION}/relayer-sdk-js.umd.cjs`;\n/** SHA-384 hex digest of the pinned CDN bundle for integrity verification. */\nconst CDN_INTEGRITY =\n \"114438b01d518b53a447fa3e8bfbe6e71031cb42ac43219bb9f53488456fdfa4bbc8989628366d436e68f6526c7647eb\";\n\n/**\n * RelayerWeb — browser encryption/decryption layer using a Web Worker.\n * Handles WASM initialization in a Web Worker for non-blocking operations.\n *\n * ## Worker initialization / promise lock pattern\n *\n * Every public method calls `#ensureWorker()` before proceeding.\n * Initialization is managed by three private fields:\n *\n * - `#workerClient` — the live worker instance (null until first init)\n * - `#initPromise` — cached promise from `#initWorker()`; once resolved,\n * all subsequent callers reuse the same worker without re-initializing.\n * Cleared on error so the next caller retries a fresh init.\n * - `#ensureLock` — short-lived promise that serializes concurrent calls\n * to `#ensureWorkerInner()`. While one caller is checking chain IDs and\n * potentially tearing down an old worker, all other callers await the\n * same lock instead of racing through the same logic. Cleared in\n * `finally` so it's never leaked.\n *\n * Chain switching: when `getChainId()` returns a value different from the\n * previously resolved chain, the old worker is terminated, `#initPromise`\n * is cleared, and a fresh worker is created for the new chain — all within\n * the `#ensureLock` critical section.\n */\nexport class RelayerWeb implements RelayerSDK, Disposable {\n #workerClient: RelayerWorkerClient | null = null;\n #initPromise: Promise<RelayerWorkerClient> | null = null;\n #ensureLock: Promise<RelayerWorkerClient> | null = null;\n #terminated = false;\n #resolvedChainId: number | null = null;\n #artifactCache: FheArtifactCache | null = null;\n #artifactStorage: GenericStorage | null = null;\n #status: RelayerSDKStatus = \"idle\";\n #initError: Error | undefined;\n readonly #config: RelayerWebConfig;\n\n constructor(config: RelayerWebConfig) {\n this.#config = config;\n }\n\n /** Current WASM initialization status. */\n get status(): RelayerSDKStatus {\n return this.#status;\n }\n\n /** The error that caused initialization to fail, if `status` is `\"error\"`. */\n get initError(): Error | undefined {\n return this.#initError;\n }\n\n #setStatus(status: RelayerSDKStatus, error?: Error): void {\n this.#status = status;\n this.#initError = error;\n this.#config.onStatusChange?.(status, error);\n }\n\n async #getWorkerConfig(): Promise<WorkerClientConfig> {\n const chainId = await this.#config.getChainId();\n const { transports, security, threads } = this.#config;\n\n if (threads !== undefined && (!Number.isInteger(threads) || threads < 1)) {\n throw new Error(`Invalid thread count: ${threads}. Must be a positive integer.`);\n }\n\n if (threads !== undefined && globalThis.SharedArrayBuffer === undefined) {\n this.#config.logger?.warn(\n \"threads option requires SharedArrayBuffer (COOP/COEP headers). Falling back to single-threaded.\",\n );\n }\n\n return {\n cdnUrl: CDN_URL,\n fhevmConfig: Object.assign({}, DefaultConfigs[chainId], transports[chainId]),\n csrfToken: security?.getCsrfToken?.() ?? \"\",\n integrity: security?.integrityCheck === false ? undefined : CDN_INTEGRITY,\n logger: this.#config.logger,\n // Public API uses `threads` (plural, \"how many threads\"); upstream\n // `initSDK` expects `thread` (singular) — rename at the boundary.\n thread: threads,\n };\n }\n\n /**\n * Ensure the worker is initialized.\n * Uses a promise lock to prevent concurrent initialization.\n * Resets on failure to allow retries.\n */\n async #ensureWorker(): Promise<RelayerWorkerClient> {\n if (this.#ensureLock) {\n return this.#ensureLock;\n }\n this.#ensureLock = this.#ensureWorkerInner();\n try {\n return await this.#ensureLock;\n } finally {\n this.#ensureLock = null;\n }\n }\n\n #tearDown(): void {\n this.#workerClient?.terminate();\n this.#workerClient = null;\n this.#initPromise = null;\n this.#artifactCache = null;\n }\n\n async #ensureWorkerInner(): Promise<RelayerWorkerClient> {\n // Auto-restart after terminate() — supports React StrictMode's\n // unmount→remount cycle and HMR without permanently killing the worker.\n if (this.#terminated) {\n this.#terminated = false;\n this.#workerClient = null;\n this.#initPromise = null;\n this.#resolvedChainId = null;\n }\n\n const chainId = await this.#config.getChainId();\n\n // Chain changed → tear down old worker, re-init\n if (this.#resolvedChainId !== null && chainId !== this.#resolvedChainId) {\n this.#tearDown();\n }\n\n this.#resolvedChainId = chainId;\n\n // Create cache for current chain.\n // Storage is chain-independent — reuse across chain switches.\n if (!this.#artifactStorage) {\n this.#artifactStorage =\n this.#config.fheArtifactStorage ?? new IndexedDBStorage(\"FheArtifactCache\", 1, \"artifacts\");\n }\n if (!this.#artifactCache) {\n const config = Object.assign({}, DefaultConfigs[chainId], this.#config.transports[chainId]);\n this.#artifactCache = new FheArtifactCache({\n storage: this.#artifactStorage,\n chainId,\n relayerUrl: config.relayerUrl,\n ttl: this.#config.fheArtifactCacheTTL,\n logger: this.#config.logger,\n });\n }\n\n // Revalidate cached artifacts if due — never let revalidation block init\n if (this.#artifactCache) {\n let stale = false;\n try {\n stale = await this.#artifactCache.revalidateIfDue();\n } catch (err) {\n this.#config.logger?.warn(\n \"Artifact revalidation failed, proceeding with potentially stale cache\",\n { error: err instanceof Error ? err.message : String(err) },\n );\n }\n if (stale) {\n this.#config.logger?.info(\"Cached FHE artifacts are stale — reinitializing\");\n this.#tearDown();\n }\n }\n\n if (!this.#initPromise) {\n this.#setStatus(\"initializing\");\n this.#initPromise = this.#initWorker()\n .then((client) => {\n this.#setStatus(\"ready\");\n return client;\n })\n .catch((error) => {\n this.#initPromise = null;\n const wrappedError =\n error instanceof ZamaError\n ? error\n : new ConfigurationError(\"Failed to initialize FHE worker\", {\n cause: error,\n });\n this.#setStatus(\"error\", wrappedError);\n throw wrappedError;\n });\n }\n return this.#initPromise;\n }\n\n /**\n * Initialize the worker (called once via promise lock).\n */\n async #initWorker(): Promise<RelayerWorkerClient> {\n const workerConfig = await this.#getWorkerConfig();\n const client = new RelayerWorkerClient(workerConfig);\n await client.initWorker();\n // If terminate() was called while we were initializing, clean up immediately\n if (this.#terminated) {\n client.terminate();\n throw new Error(\"RelayerWeb was terminated during initialization\");\n }\n this.#workerClient = client;\n return client;\n }\n\n /**\n * Terminate the worker and clean up resources.\n * Call this when the SDK is no longer needed.\n */\n terminate(): void {\n this.#terminated = true;\n if (this.#workerClient) {\n this.#workerClient.terminate();\n this.#workerClient = null;\n }\n this.#initPromise = null;\n this.#ensureLock = null;\n }\n\n /** Calls {@link terminate}, shutting down the Web Worker. */\n [Symbol.dispose](): void {\n this.terminate();\n }\n\n /**\n * Refresh the CSRF token in the worker.\n * Call this before making authenticated network requests.\n */\n async #refreshCsrfToken(): Promise<void> {\n if (this.#workerClient) {\n const token = this.#config.security?.getCsrfToken?.() ?? \"\";\n if (token) {\n await this.#workerClient.updateCsrf(token);\n }\n }\n }\n\n /**\n * Generate a keypair for FHE operations.\n */\n async generateKeypair(): Promise<KeypairType<Hex>> {\n const worker = await this.#ensureWorker();\n const result = await worker.generateKeypair();\n return {\n publicKey: result.publicKey,\n privateKey: result.privateKey,\n };\n }\n\n /**\n * Create EIP712 typed data for user decryption authorization.\n */\n async createEIP712(\n publicKey: Hex,\n contractAddresses: Address[],\n startTimestamp: number,\n durationDays = 7,\n ): Promise<EIP712TypedData> {\n const worker = await this.#ensureWorker();\n const result = await worker.createEIP712({\n publicKey,\n contractAddresses,\n startTimestamp,\n durationDays,\n });\n\n const domain = {\n name: result.domain.name,\n version: result.domain.version,\n chainId: result.domain.chainId,\n verifyingContract: result.domain.verifyingContract,\n };\n\n return {\n domain,\n types: {\n EIP712Domain: buildEIP712DomainType(domain),\n UserDecryptRequestVerification: result.types.UserDecryptRequestVerification,\n },\n message: {\n publicKey: result.message.publicKey,\n contractAddresses: result.message.contractAddresses,\n startTimestamp: result.message.startTimestamp,\n durationDays: result.message.durationDays,\n extraData: result.message.extraData,\n },\n };\n }\n\n /**\n * Encrypt values for use in smart contract calls.\n * Each value must specify its FHE type (ebool, euint8–256, eaddress).\n */\n async encrypt(params: EncryptParams): Promise<EncryptResult> {\n const { values, contractAddress, userAddress } = params;\n\n return withRetry(async () => {\n const worker = await this.#ensureWorker();\n await this.#refreshCsrfToken();\n const result = await worker.encrypt({\n values,\n contractAddress,\n userAddress,\n });\n return { handles: result.handles, inputProof: result.inputProof };\n });\n }\n\n /**\n * Decrypt ciphertexts using user's private key.\n * Requires a valid EIP712 signature.\n */\n async userDecrypt(params: UserDecryptParams): Promise<Readonly<Record<Handle, ClearValueType>>> {\n return withRetry(async () => {\n const worker = await this.#ensureWorker();\n await this.#refreshCsrfToken();\n const result = await worker.userDecrypt(params);\n return result.clearValues;\n });\n }\n\n /**\n * Public decryption - no authorization needed.\n * Used for publicly visible encrypted values.\n */\n async publicDecrypt(handles: Handle[]): Promise<PublicDecryptResult> {\n return withRetry(async () => {\n const worker = await this.#ensureWorker();\n await this.#refreshCsrfToken();\n const result = await worker.publicDecrypt(handles);\n return {\n clearValues: result.clearValues,\n abiEncodedClearValues: result.abiEncodedClearValues,\n decryptionProof: result.decryptionProof,\n };\n });\n }\n\n /**\n * Create EIP712 typed data for delegated user decryption authorization.\n */\n async createDelegatedUserDecryptEIP712(\n publicKey: Hex,\n contractAddresses: Address[],\n delegatorAddress: Address,\n startTimestamp: number,\n durationDays = 7,\n ): Promise<KmsDelegatedUserDecryptEIP712Type> {\n const worker = await this.#ensureWorker();\n return worker.createDelegatedUserDecryptEIP712({\n publicKey,\n contractAddresses,\n delegatorAddress,\n startTimestamp,\n durationDays,\n });\n }\n\n /**\n * Decrypt ciphertexts via delegation.\n * Requires a valid EIP712 signature from the delegator.\n */\n async delegatedUserDecrypt(\n params: DelegatedUserDecryptParams,\n ): Promise<Readonly<Record<Handle, ClearValueType>>> {\n return withRetry(async () => {\n const worker = await this.#ensureWorker();\n await this.#refreshCsrfToken();\n const result = await worker.delegatedUserDecrypt(params);\n return result.clearValues;\n });\n }\n\n /**\n * Submit a ZK proof to the relayer for verification.\n */\n async requestZKProofVerification(zkProof: ZKProofLike): Promise<InputProofBytesType> {\n return withRetry(async () => {\n const worker = await this.#ensureWorker();\n await this.#refreshCsrfToken();\n return worker.requestZKProofVerification(zkProof);\n });\n }\n\n /**\n * Get the TFHE compact public key.\n * When storage is configured, the result is cached persistently.\n */\n async getPublicKey(): Promise<{\n publicKeyId: string;\n publicKey: Uint8Array;\n } | null> {\n const worker = await this.#ensureWorker();\n if (this.#artifactCache) {\n return this.#artifactCache.getPublicKey(async () => (await worker.getPublicKey()).result);\n }\n return (await worker.getPublicKey()).result;\n }\n\n /**\n * Get public parameters for encryption capacity.\n * When storage is configured, the result is cached persistently.\n */\n async getPublicParams(\n bits: number,\n ): Promise<{ publicParams: Uint8Array; publicParamsId: string } | null> {\n const worker = await this.#ensureWorker();\n if (this.#artifactCache) {\n return this.#artifactCache.getPublicParams(\n bits,\n async () => (await worker.getPublicParams(bits)).result,\n );\n }\n return (await worker.getPublicParams(bits)).result;\n }\n\n async getAclAddress(): Promise<Address> {\n const chainId = await this.#config.getChainId();\n const config = Object.assign({}, DefaultConfigs[chainId], this.#config.transports[chainId]);\n if (!config.aclContractAddress) {\n throw new ConfigurationError(`No ACL address configured for chain ${chainId}`);\n }\n return config.aclContractAddress as Address;\n }\n}\n","import { type Address, getAddress, type Hex, hexToBigInt } from \"viem\";\nimport {\n allowanceContract,\n approveContract,\n confidentialTransferContract,\n confidentialTransferFromContract,\n delegateForUserDecryptionContract,\n finalizeUnwrapContract,\n isOperatorContract,\n revokeDelegationContract,\n setOperatorContract,\n underlyingContract,\n unwrapContract,\n unwrapFromBalanceContract,\n wrapContract,\n wrapETHContract,\n MAX_UINT64,\n} from \"../contracts\";\nimport { findUnwrapRequested } from \"../events/onchain-events\";\nimport { ZamaSDKEvents } from \"../events/sdk-events\";\nimport type { Handle } from \"../relayer/relayer-sdk.types\";\nimport {\n ApprovalFailedError,\n DecryptionFailedError,\n DelegationDelegateEqualsContractError,\n DelegationExpirationTooSoonError,\n DelegationExpiryUnchangedError,\n DelegationNotFoundError,\n DelegationSelfNotAllowedError,\n EncryptionFailedError,\n TransactionRevertedError,\n ZamaError,\n matchAclRevert,\n} from \"../errors\";\nimport { ReadonlyToken, type ReadonlyTokenConfig } from \"./readonly-token\";\nimport type {\n ShieldCallbacks,\n TransactionResult,\n TransferCallbacks,\n UnshieldCallbacks,\n} from \"../types\";\nimport { toError } from \"../utils\";\n\n/**\n * ERC-20-like interface for a single confidential token.\n * Hides all FHE complexity (encryption, decryption, EIP-712 signing)\n * behind familiar methods.\n *\n * Extends ReadonlyToken with write operations\n * (transfer, shield, unshield).\n */\nexport interface TokenConfig extends ReadonlyTokenConfig {\n /** Override the wrapper address. Defaults to `address` (the token IS the wrapper). */\n wrapper?: Address;\n}\n\nexport class Token extends ReadonlyToken {\n static readonly ZERO_ADDRESS: Address = \"0x0000000000000000000000000000000000000000\";\n\n readonly wrapper: Address;\n #underlying: Address | undefined;\n #underlyingPromise: Promise<Address> | null = null;\n\n constructor(config: TokenConfig) {\n super(config);\n this.wrapper = config.wrapper ? getAddress(config.wrapper) : this.address;\n }\n\n async #getUnderlying(): Promise<Address> {\n if (this.#underlying !== undefined) {\n return this.#underlying;\n }\n if (!this.#underlyingPromise) {\n this.#underlyingPromise = this.signer\n .readContract(underlyingContract(this.wrapper))\n .then((v) => {\n this.#underlying = v;\n this.#underlyingPromise = null;\n return v;\n })\n .catch((error) => {\n this.#underlyingPromise = null;\n throw error;\n });\n }\n return this.#underlyingPromise;\n }\n\n // WRITE OPERATIONS\n\n /**\n * Confidential transfer. Encrypts the amount via FHE, then calls the contract.\n * Returns the transaction hash.\n *\n * @param to - Recipient address.\n * @param amount - Plaintext amount to transfer (encrypted automatically via FHE).\n * @returns The transaction hash and mined receipt.\n * @throws {@link EncryptionFailedError} if FHE encryption fails.\n * @throws {@link TransactionRevertedError} if the on-chain transfer reverts.\n *\n * @example\n * ```ts\n * const txHash = await token.confidentialTransfer(\"0xRecipient\", 1000n);\n * ```\n */\n async confidentialTransfer(\n to: Address,\n amount: bigint,\n callbacks?: TransferCallbacks,\n ): Promise<TransactionResult> {\n const normalizedTo = getAddress(to);\n\n let handles: Uint8Array[];\n let inputProof: Uint8Array;\n const t0 = Date.now();\n try {\n this.emit({ type: ZamaSDKEvents.EncryptStart });\n ({ handles, inputProof } = await this.relayer.encrypt({\n values: [{ value: amount, type: \"euint64\" }],\n contractAddress: this.address,\n userAddress: await this.signer.getAddress(),\n }));\n this.emit({\n type: ZamaSDKEvents.EncryptEnd,\n durationMs: Date.now() - t0,\n });\n safeCallback(() => callbacks?.onEncryptComplete?.());\n } catch (error) {\n this.emit({\n type: ZamaSDKEvents.EncryptError,\n error: toError(error),\n durationMs: Date.now() - t0,\n });\n if (error instanceof ZamaError) {\n throw error;\n }\n throw new EncryptionFailedError(\"Failed to encrypt transfer amount\", {\n cause: error,\n });\n }\n\n if (handles.length === 0) {\n throw new EncryptionFailedError(\"Encryption returned no handles\");\n }\n\n try {\n const txHash = await this.signer.writeContract(\n confidentialTransferContract(this.address, normalizedTo, handles[0]!, inputProof),\n );\n this.emit({ type: ZamaSDKEvents.TransferSubmitted, txHash });\n safeCallback(() => callbacks?.onTransferSubmitted?.(txHash));\n const receipt = await this.signer.waitForTransactionReceipt(txHash);\n return { txHash, receipt };\n } catch (error) {\n this.emit({\n type: ZamaSDKEvents.TransactionError,\n operation: \"transfer\",\n error: toError(error),\n });\n if (error instanceof ZamaError) {\n throw error;\n }\n throw new TransactionRevertedError(\"Transfer transaction failed\", {\n cause: error,\n });\n }\n }\n\n /**\n * Operator encrypted transfer on behalf of another address.\n * The caller must be an approved operator for `from`.\n *\n * @param from - The address to transfer from (caller must be an approved operator).\n * @param to - Recipient address.\n * @param amount - Plaintext amount to transfer (encrypted automatically via FHE).\n * @returns The transaction hash and mined receipt.\n * @throws {@link EncryptionFailedError} if FHE encryption fails.\n * @throws {@link TransactionRevertedError} if the on-chain transfer reverts.\n *\n * @example\n * ```ts\n * const txHash = await token.confidentialTransferFrom(\"0xFrom\", \"0xTo\", 500n);\n * ```\n */\n async confidentialTransferFrom(\n from: Address,\n to: Address,\n amount: bigint,\n callbacks?: TransferCallbacks,\n ): Promise<TransactionResult> {\n const normalizedFrom = getAddress(from);\n const normalizedTo = getAddress(to);\n\n let handles: Uint8Array[];\n let inputProof: Uint8Array;\n const t0 = Date.now();\n try {\n this.emit({ type: ZamaSDKEvents.EncryptStart });\n ({ handles, inputProof } = await this.relayer.encrypt({\n values: [{ value: amount, type: \"euint64\" }],\n contractAddress: this.address,\n userAddress: normalizedFrom,\n }));\n this.emit({\n type: ZamaSDKEvents.EncryptEnd,\n durationMs: Date.now() - t0,\n });\n safeCallback(() => callbacks?.onEncryptComplete?.());\n } catch (error) {\n this.emit({\n type: ZamaSDKEvents.EncryptError,\n error: toError(error),\n durationMs: Date.now() - t0,\n });\n if (error instanceof ZamaError) {\n throw error;\n }\n throw new EncryptionFailedError(\"Failed to encrypt transferFrom amount\", {\n cause: error,\n });\n }\n\n if (handles.length === 0) {\n throw new EncryptionFailedError(\"Encryption returned no handles\");\n }\n\n try {\n const txHash = await this.signer.writeContract(\n confidentialTransferFromContract(\n this.address,\n normalizedFrom,\n normalizedTo,\n handles[0]!,\n inputProof,\n ),\n );\n this.emit({ type: ZamaSDKEvents.TransferFromSubmitted, txHash });\n safeCallback(() => callbacks?.onTransferSubmitted?.(txHash));\n const receipt = await this.signer.waitForTransactionReceipt(txHash);\n return { txHash, receipt };\n } catch (error) {\n this.emit({\n type: ZamaSDKEvents.TransactionError,\n operation: \"transferFrom\",\n error: toError(error),\n });\n if (error instanceof ZamaError) {\n throw error;\n }\n throw new TransactionRevertedError(\"TransferFrom transaction failed\", {\n cause: error,\n });\n }\n }\n\n /**\n * Set operator approval for the confidential token.\n * Defaults to 1 hour from now if `until` is not specified.\n *\n * @param spender - The address to approve as an operator.\n * @param until - Optional Unix timestamp for approval expiry. Defaults to now + 1 hour.\n * @returns The transaction hash and mined receipt.\n * @throws {@link ApprovalFailedError} if the approval transaction fails.\n *\n * @example\n * ```ts\n * const txHash = await token.approve(\"0xSpender\");\n * ```\n */\n async approve(spender: Address, until?: number): Promise<TransactionResult> {\n const normalizedSpender = getAddress(spender);\n try {\n const txHash = await this.signer.writeContract(\n setOperatorContract(this.address, normalizedSpender, until),\n );\n this.emit({ type: ZamaSDKEvents.ApproveSubmitted, txHash });\n const receipt = await this.signer.waitForTransactionReceipt(txHash);\n return { txHash, receipt };\n } catch (error) {\n this.emit({\n type: ZamaSDKEvents.TransactionError,\n operation: \"approve\",\n error: toError(error),\n });\n if (error instanceof ZamaError) {\n throw error;\n }\n throw new ApprovalFailedError(\"Operator approval failed\", {\n cause: error,\n });\n }\n }\n\n /**\n * Check if a spender is an approved operator for a given holder.\n *\n * @param spender - The address to check operator approval for.\n * @param holder - The token holder address. Defaults to the connected wallet.\n * @returns `true` if the spender is an approved operator for the holder.\n *\n * @example\n * ```ts\n * if (await token.isApproved(\"0xSpender\")) {\n * // spender can call transferFrom on behalf of connected wallet\n * }\n * // or check for a specific holder:\n * if (await token.isApproved(\"0xSpender\", \"0xHolder\")) { ... }\n * ```\n */\n async isApproved(spender: Address, holder?: Address): Promise<boolean> {\n const normalizedSpender = getAddress(spender);\n const resolvedHolder = holder ? getAddress(holder) : await this.signer.getAddress();\n return this.signer.readContract(\n isOperatorContract(this.address, resolvedHolder, normalizedSpender),\n );\n }\n\n /**\n * Shield public ERC-20 tokens into confidential tokens.\n * Handles ERC-20 approval automatically based on `approvalStrategy`\n * (`\"exact\"` by default, `\"max\"` for unlimited approval, `\"skip\"` to opt out).\n *\n * @param amount - The plaintext amount to shield.\n * @param options - Optional configuration: `approvalStrategy` (`\"exact\"` | `\"max\"` | `\"skip\"`, default `\"exact\"`), `fees` (extra ETH for native wrappers).\n * @returns The transaction hash and mined receipt.\n * @throws {@link ApprovalFailedError} if the ERC-20 approval step fails.\n * @throws {@link TransactionRevertedError} if the shield transaction reverts.\n *\n * @example\n * ```ts\n * const txHash = await token.shield(1000n);\n * // or with exact approval:\n * const txHash = await token.shield(1000n, { approvalStrategy: \"exact\" });\n * ```\n */\n async shield(\n amount: bigint,\n options?: {\n approvalStrategy?: \"max\" | \"exact\" | \"skip\";\n fees?: bigint;\n /** Recipient address for the shielded tokens. Defaults to the connected wallet. */\n to?: Address;\n /** Progress callbacks for the multi-step shield flow. */\n callbacks?: ShieldCallbacks;\n },\n ): Promise<TransactionResult> {\n const underlying = await this.#getUnderlying();\n\n if (underlying === Token.ZERO_ADDRESS) {\n return this.shieldETH(amount, amount + (options?.fees ?? 0n));\n }\n\n const strategy = options?.approvalStrategy ?? \"exact\";\n if (strategy !== \"skip\") {\n await this.#ensureAllowance(amount, strategy === \"max\", options?.callbacks);\n }\n\n try {\n const recipient = options?.to ? getAddress(options.to) : await this.signer.getAddress();\n const txHash = await this.signer.writeContract(wrapContract(this.wrapper, recipient, amount));\n this.emit({ type: ZamaSDKEvents.ShieldSubmitted, txHash });\n safeCallback(() => options?.callbacks?.onShieldSubmitted?.(txHash));\n const receipt = await this.signer.waitForTransactionReceipt(txHash);\n return { txHash, receipt };\n } catch (error) {\n this.emit({\n type: ZamaSDKEvents.TransactionError,\n operation: \"shield\",\n error: toError(error),\n });\n if (error instanceof ZamaError) {\n throw error;\n }\n throw new TransactionRevertedError(\"Shield transaction failed\", {\n cause: error,\n });\n }\n }\n\n /**\n * Shield native ETH into confidential tokens. `value` defaults to `amount`.\n *\n * @param amount - The amount of ETH to shield (in wei).\n * @param value - Optional ETH value to send. Defaults to `amount`.\n * @returns The transaction hash and mined receipt.\n * @throws {@link TransactionRevertedError} if the shield transaction reverts.\n *\n * @example\n * ```ts\n * const txHash = await token.shieldETH(1000000000000000000n); // 1 ETH\n * ```\n */\n async shieldETH(amount: bigint, value?: bigint): Promise<TransactionResult> {\n try {\n const userAddress = await this.signer.getAddress();\n const txHash = await this.signer.writeContract(\n wrapETHContract(this.wrapper, userAddress, amount, value ?? amount),\n );\n this.emit({ type: ZamaSDKEvents.ShieldSubmitted, txHash });\n const receipt = await this.signer.waitForTransactionReceipt(txHash);\n return { txHash, receipt };\n } catch (error) {\n this.emit({\n type: ZamaSDKEvents.TransactionError,\n operation: \"shieldETH\",\n error: toError(error),\n });\n if (error instanceof ZamaError) {\n throw error;\n }\n throw new TransactionRevertedError(\"Shield ETH transaction failed\", {\n cause: error,\n });\n }\n }\n\n /**\n * Request an unwrap for a specific amount. Encrypts the amount first.\n * Call {@link finalizeUnwrap} after the request is processed on-chain.\n *\n * @param amount - The plaintext amount to unwrap (encrypted automatically).\n * @returns The transaction hash and mined receipt.\n * @throws {@link EncryptionFailedError} if FHE encryption fails.\n * @throws {@link TransactionRevertedError} if the unwrap transaction reverts.\n *\n * @example\n * ```ts\n * const txHash = await token.unwrap(500n);\n * ```\n */\n async unwrap(amount: bigint): Promise<TransactionResult> {\n const userAddress = await this.signer.getAddress();\n\n let handles: Uint8Array[];\n let inputProof: Uint8Array;\n const t0 = Date.now();\n try {\n this.emit({ type: ZamaSDKEvents.EncryptStart });\n ({ handles, inputProof } = await this.relayer.encrypt({\n values: [{ value: amount, type: \"euint64\" }],\n contractAddress: this.wrapper,\n userAddress,\n }));\n this.emit({\n type: ZamaSDKEvents.EncryptEnd,\n durationMs: Date.now() - t0,\n });\n } catch (error) {\n this.emit({\n type: ZamaSDKEvents.EncryptError,\n error: toError(error),\n durationMs: Date.now() - t0,\n });\n if (error instanceof ZamaError) {\n throw error;\n }\n throw new EncryptionFailedError(\"Failed to encrypt unshield amount\", {\n cause: error,\n });\n }\n\n if (handles.length === 0) {\n throw new EncryptionFailedError(\"Encryption returned no handles\");\n }\n\n try {\n const txHash = await this.signer.writeContract(\n unwrapContract(this.address, userAddress, userAddress, handles[0]!, inputProof),\n );\n this.emit({ type: ZamaSDKEvents.UnwrapSubmitted, txHash });\n const receipt = await this.signer.waitForTransactionReceipt(txHash);\n return { txHash, receipt };\n } catch (error) {\n this.emit({\n type: ZamaSDKEvents.TransactionError,\n operation: \"unwrap\",\n error: toError(error),\n });\n if (error instanceof ZamaError) {\n throw error;\n }\n throw new TransactionRevertedError(\"Unshield transaction failed\", {\n cause: error,\n });\n }\n }\n\n /**\n * Request an unwrap for the entire confidential balance.\n * Uses the on-chain balance handle directly (no encryption needed).\n * Throws if the balance is zero.\n *\n * @returns The transaction hash and mined receipt.\n * @throws {@link DecryptionFailedError} if the balance is zero.\n * @throws {@link TransactionRevertedError} if the unwrap transaction reverts.\n *\n * @example\n * ```ts\n * const txHash = await token.unwrapAll();\n * ```\n */\n async unwrapAll(): Promise<TransactionResult> {\n const userAddress = await this.signer.getAddress();\n const handle = await this.readConfidentialBalanceOf(userAddress);\n\n if (this.isZeroHandle(handle)) {\n throw new DecryptionFailedError(\"Cannot unshield: balance is zero\");\n }\n\n try {\n const txHash = await this.signer.writeContract(\n unwrapFromBalanceContract(this.address, userAddress, userAddress, handle),\n );\n this.emit({ type: ZamaSDKEvents.UnwrapSubmitted, txHash });\n const receipt = await this.signer.waitForTransactionReceipt(txHash);\n return { txHash, receipt };\n } catch (error) {\n this.emit({\n type: ZamaSDKEvents.TransactionError,\n operation: \"unwrap\",\n error: toError(error),\n });\n if (error instanceof ZamaError) {\n throw error;\n }\n throw new TransactionRevertedError(\"Unshield-all transaction failed\", {\n cause: error,\n });\n }\n }\n\n /**\n * Unshield a specific amount and finalize in one call.\n * Orchestrates: unshield → wait for receipt → parse event → finalize.\n *\n * @param amount - The plaintext amount to unshield.\n * @param callbacks - Optional progress callbacks for each phase.\n * @returns The finalize transaction hash and mined receipt.\n * @throws {@link EncryptionFailedError} if FHE encryption fails.\n * @throws {@link TransactionRevertedError} if any transaction in the flow reverts.\n *\n * @example\n * ```ts\n * const txHash = await token.unshield(500n);\n * ```\n */\n async unshield(amount: bigint, callbacks?: UnshieldCallbacks): Promise<TransactionResult> {\n const operationId = crypto.randomUUID();\n const unwrapResult = await this.unwrap(amount);\n safeCallback(() => callbacks?.onUnwrapSubmitted?.(unwrapResult.txHash));\n return this.#waitAndFinalizeUnshield(unwrapResult.txHash, callbacks, operationId);\n }\n\n /**\n * Unshield the entire balance and finalize in one call.\n * Orchestrates: unshieldAll → wait for receipt → parse event → finalize.\n *\n * @param callbacks - Optional progress callbacks for each phase.\n * @returns The finalize transaction hash and mined receipt.\n * @throws {@link DecryptionFailedError} if the balance is zero.\n * @throws {@link TransactionRevertedError} if any transaction in the flow reverts.\n *\n * @example\n * ```ts\n * const txHash = await token.unshieldAll();\n * ```\n */\n async unshieldAll(callbacks?: UnshieldCallbacks): Promise<TransactionResult> {\n const operationId = crypto.randomUUID();\n const unwrapResult = await this.unwrapAll();\n safeCallback(() => callbacks?.onUnwrapSubmitted?.(unwrapResult.txHash));\n return this.#waitAndFinalizeUnshield(unwrapResult.txHash, callbacks, operationId);\n }\n\n /**\n * Resume an in-progress unshield from an existing unwrap tx hash.\n * Useful when the user already submitted the unwrap but the finalize step\n * was interrupted (e.g. page reload, network error).\n *\n * @param unwrapTxHash - The transaction hash of the previously submitted unwrap.\n * @param callbacks - Optional progress callbacks.\n * @returns The finalize transaction hash and mined receipt.\n * @throws {@link TransactionRevertedError} if finalization fails.\n *\n * @example\n * ```ts\n * const txHash = await token.resumeUnshield(previousUnwrapTxHash);\n * ```\n */\n async resumeUnshield(\n unwrapTxHash: Hex,\n callbacks?: UnshieldCallbacks,\n ): Promise<TransactionResult> {\n return this.#waitAndFinalizeUnshield(unwrapTxHash, callbacks, crypto.randomUUID());\n }\n\n /**\n * Complete an unwrap by providing the public decryption proof.\n * Call this after an unshield request has been processed on-chain.\n *\n * @param burnAmountHandle - The encrypted amount handle from the `UnwrapRequested` event.\n * @returns The transaction hash and mined receipt.\n * @throws {@link DecryptionFailedError} if public decryption fails.\n * @throws {@link TransactionRevertedError} if the finalize transaction reverts.\n *\n * @example\n * ```ts\n * const event = findUnwrapRequested(receipt.logs);\n * const txHash = await token.finalizeUnwrap(event.encryptedAmount);\n * ```\n */\n async finalizeUnwrap(burnAmountHandle: Handle): Promise<TransactionResult> {\n let clearValue: bigint;\n let decryptionProof: Hex;\n\n const t0 = Date.now();\n try {\n this.emit({ type: ZamaSDKEvents.DecryptStart });\n const result = await this.relayer.publicDecrypt([burnAmountHandle]);\n this.emit({\n type: ZamaSDKEvents.DecryptEnd,\n durationMs: Date.now() - t0,\n });\n decryptionProof = result.decryptionProof;\n try {\n clearValue = hexToBigInt(result.abiEncodedClearValues);\n } catch {\n throw new DecryptionFailedError(\n `Cannot parse decrypted value: ${result.abiEncodedClearValues}`,\n );\n }\n } catch (error) {\n this.emit({\n type: ZamaSDKEvents.DecryptError,\n error: toError(error),\n durationMs: Date.now() - t0,\n });\n if (error instanceof ZamaError) {\n throw error;\n }\n throw new DecryptionFailedError(\"Failed to finalize unshield\", {\n cause: error,\n });\n }\n\n try {\n const txHash = await this.signer.writeContract(\n finalizeUnwrapContract(this.wrapper, burnAmountHandle, clearValue, decryptionProof),\n );\n this.emit({ type: ZamaSDKEvents.FinalizeUnwrapSubmitted, txHash });\n const receipt = await this.signer.waitForTransactionReceipt(txHash);\n return { txHash, receipt };\n } catch (error) {\n this.emit({\n type: ZamaSDKEvents.TransactionError,\n operation: \"finalizeUnwrap\",\n error: toError(error),\n });\n if (error instanceof ZamaError) {\n throw error;\n }\n throw new TransactionRevertedError(\"Failed to finalize unshield\", {\n cause: error,\n });\n }\n }\n\n /**\n * Approve this token contract to spend the underlying ERC-20.\n * Defaults to max uint256. Resets to zero first if there's an existing\n * non-zero allowance (required by tokens like USDT).\n *\n * @param amount - Optional approval amount. Defaults to max uint256.\n * @returns The transaction hash and mined receipt.\n * @throws {@link ApprovalFailedError} if the approval transaction fails.\n *\n * @example\n * ```ts\n * await token.approveUnderlying(); // max approval\n * await token.approveUnderlying(1000n); // exact amount\n * ```\n */\n async approveUnderlying(amount?: bigint): Promise<TransactionResult> {\n const underlying = await this.#getUnderlying();\n\n const approvalAmount = amount ?? 2n ** 256n - 1n;\n\n try {\n if (approvalAmount > 0n) {\n const userAddress = await this.signer.getAddress();\n const currentAllowance = await this.signer.readContract(\n allowanceContract(underlying, userAddress, this.wrapper),\n );\n\n if (currentAllowance > 0n) {\n await this.signer.writeContract(approveContract(underlying, this.wrapper, 0n));\n }\n }\n\n const txHash = await this.signer.writeContract(\n approveContract(underlying, this.wrapper, approvalAmount),\n );\n this.emit({ type: ZamaSDKEvents.ApproveUnderlyingSubmitted, txHash });\n const receipt = await this.signer.waitForTransactionReceipt(txHash);\n return { txHash, receipt };\n } catch (error) {\n this.emit({\n type: ZamaSDKEvents.TransactionError,\n operation: \"approveUnderlying\",\n error: toError(error),\n });\n if (error instanceof ZamaError) {\n throw error;\n }\n throw new ApprovalFailedError(\"ERC-20 approval failed\", {\n cause: error,\n });\n }\n }\n\n // DELEGATION OPERATIONS\n\n /**\n * Delegate decryption rights for this token to another address.\n * Calls `ACL.delegateForUserDecryption()` on-chain.\n *\n * **Important:** After the transaction is mined, allow **1–2 minutes** before\n * calling {@link ReadonlyToken.decryptBalanceAs | decryptBalanceAs}. The delegation\n * is recorded on L1 immediately, but the gateway (on Arbitrum) must sync the\n * ACL state via cross-chain event propagation. Attempting delegated decryption\n * before propagation completes will throw a\n * {@link DelegationNotPropagatedError}.\n *\n * @param delegateAddress - Address to delegate decryption rights to.\n * @param expirationDate - Optional expiration date (defaults to permanent delegation via `uint64.max`).\n * @returns The transaction hash and mined receipt.\n * @throws {@link TransactionRevertedError} if the delegation transaction reverts.\n */\n async delegateDecryption({\n delegateAddress,\n expirationDate,\n }: {\n delegateAddress: Address;\n expirationDate?: Date;\n }): Promise<TransactionResult> {\n if (expirationDate && expirationDate.getTime() < Date.now() + 3600_000) {\n throw new DelegationExpirationTooSoonError(\n \"Expiration date must be at least 1 hour in the future\",\n );\n }\n\n const normalizedDelegate = getAddress(delegateAddress);\n\n // Pre-flight: delegate cannot be the connected wallet (SenderCannotBeDelegate)\n const signerAddress = await this.signer.getAddress();\n if (normalizedDelegate === getAddress(signerAddress)) {\n throw new DelegationSelfNotAllowedError(\n \"Cannot delegate to yourself (delegate === msg.sender).\",\n );\n }\n\n // Pre-flight: delegate cannot be the contract address (DelegateCannotBeContractAddress)\n if (normalizedDelegate === this.address) {\n throw new DelegationDelegateEqualsContractError(\n `Delegate address cannot be the same as the contract address (${this.address}).`,\n );\n }\n\n const acl = await this.getAclAddress();\n // uint64 max → no practical expiry\n const expDate = expirationDate\n ? BigInt(Math.floor(expirationDate.getTime() / 1000))\n : MAX_UINT64;\n\n // Pre-flight with RPC: new expiry must differ from current (ExpirationDateAlreadySetToSameValue)\n const currentExpiry = await this.getDelegationExpiry({\n delegatorAddress: signerAddress,\n delegateAddress: normalizedDelegate,\n });\n if (currentExpiry === expDate) {\n throw new DelegationExpiryUnchangedError(\n `The new expiration date (${expDate}) is the same as the current one. No on-chain change needed.`,\n );\n }\n\n try {\n const txHash = await this.signer.writeContract(\n delegateForUserDecryptionContract(acl, normalizedDelegate, this.address, expDate),\n );\n this.emit({ type: ZamaSDKEvents.DelegationSubmitted, txHash });\n const receipt = await this.signer.waitForTransactionReceipt(txHash);\n return { txHash, receipt };\n } catch (error) {\n this.emit({\n type: ZamaSDKEvents.TransactionError,\n operation: \"delegateDecryption\",\n error: toError(error),\n });\n if (error instanceof ZamaError) {\n throw error;\n }\n const mapped = matchAclRevert(error);\n if (mapped) {\n throw mapped;\n }\n throw new TransactionRevertedError(\"Delegation transaction failed\", {\n cause: error,\n });\n }\n }\n\n /**\n * Revoke decryption delegation for this token.\n * Calls `ACL.revokeDelegationForUserDecryption()` on-chain.\n *\n * @param delegateAddress - Address to revoke delegation from.\n * @returns The transaction hash and mined receipt.\n * @throws {@link TransactionRevertedError} if the revocation transaction reverts.\n */\n async revokeDelegation({\n delegateAddress,\n }: {\n delegateAddress: Address;\n }): Promise<TransactionResult> {\n const normalizedDelegate = getAddress(delegateAddress);\n const signerAddress = await this.signer.getAddress();\n const acl = await this.getAclAddress();\n\n // Pre-flight: reject if never delegated (expiry === 0).\n // Expired delegations (non-zero expiry in the past) are allowed through —\n // the ACL contract accepts revocation of expired delegations.\n const currentExpiry = await this.getDelegationExpiry({\n delegatorAddress: signerAddress,\n delegateAddress: normalizedDelegate,\n });\n if (currentExpiry === 0n) {\n throw new DelegationNotFoundError(\n `No active delegation found for delegate ${normalizedDelegate} on contract ${this.address}.`,\n );\n }\n\n try {\n const txHash = await this.signer.writeContract(\n revokeDelegationContract(acl, normalizedDelegate, this.address),\n );\n this.emit({ type: ZamaSDKEvents.RevokeDelegationSubmitted, txHash });\n const receipt = await this.signer.waitForTransactionReceipt(txHash);\n return { txHash, receipt };\n } catch (error) {\n this.emit({\n type: ZamaSDKEvents.TransactionError,\n operation: \"revokeDelegation\",\n error: toError(error),\n });\n if (error instanceof ZamaError) {\n throw error;\n }\n const mapped = matchAclRevert(error);\n if (mapped) {\n throw mapped;\n }\n throw new TransactionRevertedError(\"Revoke delegation transaction failed\", {\n cause: error,\n });\n }\n }\n\n // BATCH DELEGATION\n\n /**\n * Delegate decryption rights across multiple tokens in parallel.\n * Returns a per-token result map with partial success semantics.\n *\n * @param tokens - Array of Token instances to delegate on.\n * @param delegateAddress - Address to delegate decryption rights to.\n * @param expirationDate - Optional expiration date.\n * @returns Map from token address to TransactionResult or ZamaError.\n */\n static async batchDelegateDecryption({\n tokens,\n delegateAddress,\n expirationDate,\n }: {\n tokens: Token[];\n delegateAddress: Address;\n expirationDate?: Date;\n }): Promise<Map<Address, TransactionResult | ZamaError>> {\n return Token.#batchDelegationOp(\n tokens,\n (t) => t.delegateDecryption({ delegateAddress, expirationDate }),\n \"Delegation failed\",\n );\n }\n\n /**\n * Revoke delegation across multiple tokens in parallel.\n * Returns a per-token result map with partial success semantics.\n *\n * @param tokens - Array of Token instances to revoke delegation on.\n * @param delegateAddress - Address to revoke delegation from.\n * @returns Map from token address to TransactionResult or ZamaError.\n */\n static async batchRevokeDelegation({\n tokens,\n delegateAddress,\n }: {\n tokens: Token[];\n delegateAddress: Address;\n }): Promise<Map<Address, TransactionResult | ZamaError>> {\n return Token.#batchDelegationOp(\n tokens,\n (t) => t.revokeDelegation({ delegateAddress }),\n \"Revoke delegation failed\",\n );\n }\n\n static async #batchDelegationOp(\n tokens: Token[],\n op: (token: Token) => Promise<TransactionResult>,\n errorMessage: string,\n ): Promise<Map<Address, TransactionResult | ZamaError>> {\n const results = new Map<Address, TransactionResult | ZamaError>();\n // Run sequentially: parallel writeContract calls from the same signer\n // cause nonce contention. The value of the batch API is partial-success\n // semantics (per-token results without throwing), not parallelism.\n for (let i = 0; i < tokens.length; i++) {\n try {\n results.set(tokens[i]!.address, await op(tokens[i]!));\n } catch (error) {\n if (error instanceof ZamaError) {\n results.set(tokens[i]!.address, error);\n } else {\n results.set(\n tokens[i]!.address,\n new TransactionRevertedError(errorMessage, {\n cause: error,\n }),\n );\n }\n }\n }\n return results;\n }\n\n // PRIVATE HELPERS\n\n async #waitAndFinalizeUnshield(\n unshieldHash: Hex,\n callbacks: UnshieldCallbacks | undefined,\n operationId: string,\n ): Promise<TransactionResult> {\n this.emit({\n type: ZamaSDKEvents.UnshieldPhase1Submitted,\n txHash: unshieldHash,\n operationId,\n });\n let receipt;\n try {\n receipt = await this.signer.waitForTransactionReceipt(unshieldHash);\n } catch (error) {\n if (error instanceof ZamaError) {\n throw error;\n }\n throw new TransactionRevertedError(\"Failed to get unshield receipt\", {\n cause: error,\n });\n }\n const event = findUnwrapRequested(receipt.logs);\n if (!event) {\n throw new TransactionRevertedError(\"No UnwrapRequested event found in unshield receipt\");\n }\n this.emit({ type: ZamaSDKEvents.UnshieldPhase2Started, operationId });\n safeCallback(() => callbacks?.onFinalizing?.());\n const finalizeResult = await this.finalizeUnwrap(event.encryptedAmount);\n this.emit({\n type: ZamaSDKEvents.UnshieldPhase2Submitted,\n txHash: finalizeResult.txHash,\n operationId,\n });\n safeCallback(() => callbacks?.onFinalizeSubmitted?.(finalizeResult.txHash));\n return finalizeResult;\n }\n\n async #ensureAllowance(\n amount: bigint,\n maxApproval: boolean,\n callbacks?: ShieldCallbacks,\n ): Promise<void> {\n const underlying = await this.#getUnderlying();\n\n const userAddress = await this.signer.getAddress();\n const allowance = await this.signer.readContract(\n allowanceContract(underlying, userAddress, this.wrapper),\n );\n\n if (allowance >= amount) {\n return;\n }\n\n try {\n // Reset to zero first when there's an existing non-zero allowance.\n // Required by non-standard tokens like USDT, and also mitigates the\n // ERC-20 approve race condition for all tokens.\n if (allowance > 0n) {\n await this.signer.writeContract(approveContract(underlying, this.wrapper, 0n));\n }\n\n const approvalAmount = maxApproval ? 2n ** 256n - 1n : amount;\n\n const txHash = await this.signer.writeContract(\n approveContract(underlying, this.wrapper, approvalAmount),\n );\n this.emit({ type: ZamaSDKEvents.ApproveUnderlyingSubmitted, txHash });\n safeCallback(() => callbacks?.onApprovalSubmitted?.(txHash));\n } catch (error) {\n if (error instanceof ZamaError) {\n throw error;\n }\n throw new ApprovalFailedError(\"ERC-20 approval failed\", {\n cause: error,\n });\n }\n }\n}\n\n/**\n * Invoke a callback inside a try/catch so a throwing listener\n * can never break the unshield flow (unwrap already on-chain).\n */\nfunction safeCallback(fn: () => void): void {\n try {\n fn();\n } catch (error) {\n console.warn(\"[zama-sdk] Callback threw:\", error);\n }\n}\n","import { type Address, getAddress } from \"viem\";\nimport type { TokenWrapperPairWithMetadata, PaginatedResult, TokenWrapperPair } from \"./contracts\";\nimport {\n decimalsContract,\n erc20TotalSupplyContract,\n getConfidentialTokenAddressContract,\n getTokenAddressContract,\n getTokenPairContract,\n getTokenPairsContract,\n getTokenPairsLengthContract,\n getTokenPairsSliceContract,\n isConfidentialTokenValidContract,\n nameContract,\n symbolContract,\n} from \"./contracts\";\nimport { ConfigurationError } from \"./errors/relayer\";\nimport { hoodiCleartextConfig } from \"./relayer/cleartext\";\nimport { MainnetConfig, SepoliaConfig } from \"./relayer/relayer-utils\";\nimport type { GenericSigner } from \"./types/signer\";\n\n/**\n * Default wrappers registry addresses for known chains.\n * Only includes chains where a registry is deployed (excludes Hardhat).\n */\nexport const DefaultRegistryAddresses: Record<number, Address> = {\n [MainnetConfig.chainId]: MainnetConfig.registryAddress,\n [SepoliaConfig.chainId]: SepoliaConfig.registryAddress,\n [hoodiCleartextConfig.chainId]: hoodiCleartextConfig.registryAddress,\n};\n\n/** Default page size for {@link WrappersRegistry.listPairs}. */\nconst DEFAULT_PAGE_SIZE = 100;\n\n/** Default registry TTL in seconds (24 hours). */\nconst DEFAULT_REGISTRY_TTL = 86400;\n\n/** Configuration for {@link WrappersRegistry}. */\nexport interface WrappersRegistryConfig {\n /** The connected wallet signer. Must satisfy the full `GenericSigner` interface. */\n signer: GenericSigner;\n /**\n * Per-chain registry address overrides, merged on top of\n * {@link DefaultRegistryAddresses}. Use this to supply a registry\n * address for custom or local chains (e.g. Hardhat).\n *\n * @example\n * ```ts\n * new WrappersRegistry({\n * signer,\n * registryAddresses: { [31337]: \"0xYourHardhatRegistry\" },\n * });\n * ```\n */\n registryAddresses?: Record<number, Address>;\n /**\n * How long cached registry results remain valid, in seconds.\n * Default: `86400` (24 hours).\n */\n registryTTL?: number;\n}\n\n/** Options for {@link WrappersRegistry.listPairs}. */\nexport interface ListPairsOptions {\n /** Page number (1-indexed). Default: `1`. */\n page?: number;\n /** Number of items per page. Default: `100`. */\n pageSize?: number;\n /**\n * When `true`, fetches on-chain metadata (name, symbol, decimals) for both\n * the ERC-20 and confidential token, plus totalSupply for the ERC-20.\n * Default: `false`.\n */\n metadata?: boolean;\n}\n\n/** Shorter TTL for negative lookups (5 minutes) so newly registered tokens are discoverable quickly. */\nconst NEGATIVE_CACHE_TTL_MS = 5 * 60 * 1000;\n\n/** Cache entry with expiry timestamp. */\ninterface CacheEntry<T> {\n data: T;\n expiresAt: number;\n}\n\n/**\n * High-level interface for the on-chain token wrappers registry.\n *\n * Uses the connected signer to resolve the correct registry contract\n * address for the current chain and exposes typed read helpers for\n * every registry query. Results are cached in memory with a\n * configurable TTL (default 24 hours).\n *\n * @example\n * ```ts\n * const registry = new WrappersRegistry({ signer });\n *\n * // Paginated listing\n * const page1 = await registry.listPairs({ page: 1, pageSize: 20 });\n *\n * // Structured lookups\n * const result = await registry.getConfidentialToken(erc20Address);\n * if (result) console.log(result.confidentialTokenAddress);\n *\n * // Force refresh\n * registry.refresh();\n * ```\n */\nexport class WrappersRegistry {\n readonly signer: GenericSigner;\n readonly #addresses: Record<number, Address>;\n readonly #ttlMs: number;\n readonly #cache = new Map<string, CacheEntry<unknown>>();\n\n constructor(config: WrappersRegistryConfig) {\n this.signer = config.signer;\n this.#addresses = Object.assign({}, DefaultRegistryAddresses, config.registryAddresses);\n this.#ttlMs = (config.registryTTL ?? DEFAULT_REGISTRY_TTL) * 1000;\n }\n\n /**\n * Synchronous lookup of the registry address for a given chain ID.\n * Returns `undefined` if no address is configured for that chain.\n */\n getAddress(chainId: number): Address | undefined {\n return this.#addresses[chainId];\n }\n\n // ---------------------------------------------------------------------------\n // Cache helpers\n // ---------------------------------------------------------------------------\n\n #getCached<T>(key: string): T | undefined {\n const entry = this.#cache.get(key);\n if (!entry) {\n return undefined;\n }\n if (Date.now() >= entry.expiresAt) {\n this.#cache.delete(key);\n return undefined;\n }\n return entry.data as T;\n }\n\n #setCached<T>(key: string, data: T, ttlMs = this.#ttlMs): T {\n this.#cache.set(key, {\n data,\n expiresAt: Date.now() + ttlMs,\n });\n return data;\n }\n\n /**\n * Force-invalidate the in-memory cache. The next call to any read method\n * will fetch fresh data from the chain.\n */\n refresh(): void {\n this.#cache.clear();\n }\n\n /**\n * The cache TTL in milliseconds.\n * Exposed so query option factories can set a matching `staleTime`.\n */\n get ttlMs(): number {\n return this.#ttlMs;\n }\n\n // ---------------------------------------------------------------------------\n // Registry address resolution\n // ---------------------------------------------------------------------------\n\n /**\n * Resolve the registry contract address for the current chain.\n *\n * Priority: `registryAddresses[chainId]` \\> built-in default.\n *\n * @returns The registry contract address for the connected chain.\n * @throws {@link ConfigurationError} if no address is configured for the chain.\n */\n async getRegistryAddress(): Promise<Address> {\n const chainId = await this.signer.getChainId();\n const address = this.#addresses[chainId];\n\n if (!address) {\n throw new ConfigurationError(\n `No wrappers registry address configured for chain ${chainId}.\\n` +\n `Pass a registryAddresses entry for this chain.`,\n );\n }\n\n return getAddress(address);\n }\n\n // ---------------------------------------------------------------------------\n // Paginated listing\n // ---------------------------------------------------------------------------\n\n /**\n * List token wrapper pairs with page-based pagination.\n *\n * Internally maps to `getTokenConfidentialTokenPairsSlice` on-chain.\n *\n * @param options - Pagination and enrichment options.\n * @returns A {@link PaginatedResult} of pairs.\n *\n * @example\n * ```ts\n * const result = await registry.listPairs({ page: 1, pageSize: 20 });\n * console.log(`${result.total} pairs, showing page ${result.page}`);\n *\n * // With on-chain metadata\n * const withMeta = await registry.listPairs({ metadata: true, pageSize: 10 });\n * for (const pair of withMeta.items) {\n * console.log(pair.underlying.symbol, \"→\", pair.confidential.symbol);\n * }\n * ```\n */\n async listPairs(\n options: ListPairsOptions & { metadata: true },\n ): Promise<PaginatedResult<TokenWrapperPairWithMetadata>>;\n async listPairs(options?: ListPairsOptions): Promise<PaginatedResult<TokenWrapperPair>>;\n async listPairs(\n options: ListPairsOptions = {},\n ): Promise<PaginatedResult<TokenWrapperPair | TokenWrapperPairWithMetadata>> {\n const page = options.page ?? 1;\n const pageSize = options.pageSize ?? DEFAULT_PAGE_SIZE;\n const metadata = options.metadata ?? false;\n\n if (page < 1) {\n throw new ConfigurationError(`page must be >= 1, got ${page}`);\n }\n if (pageSize < 1) {\n throw new ConfigurationError(`pageSize must be >= 1, got ${pageSize}`);\n }\n\n const registry = await this.getRegistryAddress();\n\n // Fetch total (cached)\n const totalCacheKey = `total:${registry}`;\n let total = this.#getCached<number>(totalCacheKey);\n if (total === undefined) {\n const raw = await this.signer.readContract(getTokenPairsLengthContract(registry));\n total = this.#setCached(totalCacheKey, Number(raw));\n }\n\n // Compute slice indices, clamping toIndex to total\n const fromIndex = BigInt((page - 1) * pageSize);\n const clampedToIndex =\n fromIndex + BigInt(pageSize) > BigInt(total) ? BigInt(total) : fromIndex + BigInt(pageSize);\n\n // Page beyond total — return empty\n if (fromIndex >= BigInt(total)) {\n return { items: [], total, page, pageSize };\n }\n\n // Fetch slice (cached)\n const sliceCacheKey = `slice:${registry}:${fromIndex}:${clampedToIndex}`;\n let items = this.#getCached<TokenWrapperPair[]>(sliceCacheKey);\n if (items === undefined) {\n const raw = await this.signer.readContract(\n getTokenPairsSliceContract(registry, fromIndex, clampedToIndex),\n );\n items = this.#setCached(sliceCacheKey, [...raw]);\n }\n\n if (!metadata) {\n return { items, total, page, pageSize };\n }\n\n // Enrich with on-chain metadata (resilient — individual failures don't break the batch)\n const metadataCacheKey = `metadata:${registry}:${fromIndex}:${clampedToIndex}`;\n let metadataItems = this.#getCached<TokenWrapperPairWithMetadata[]>(metadataCacheKey);\n if (metadataItems === undefined) {\n const settled = await Promise.allSettled(items.map((pair) => this.#pairWithMetadata(pair)));\n const hasFailures = settled.some((r) => r.status === \"rejected\");\n const enriched = settled.map((result, i) =>\n result.status === \"fulfilled\"\n ? result.value\n : Object.assign({}, items[i], {\n metadataFailed: true as const,\n underlying: {\n name: \"Unknown\",\n symbol: \"???\",\n decimals: 0,\n totalSupply: 0n,\n },\n confidential: { name: \"Unknown\", symbol: \"???\", decimals: 0 },\n }),\n );\n // Use negative cache TTL when any metadata fetch failed so retries happen sooner\n metadataItems = this.#setCached(\n metadataCacheKey,\n enriched,\n hasFailures ? NEGATIVE_CACHE_TTL_MS : undefined,\n );\n }\n\n return { items: metadataItems, total, page, pageSize };\n }\n\n async #pairWithMetadata(pair: TokenWrapperPair): Promise<TokenWrapperPairWithMetadata> {\n const [uName, uSymbol, uDecimals, uTotalSupply, cName, cSymbol, cDecimals] = await Promise.all([\n this.signer.readContract(nameContract(pair.tokenAddress)),\n this.signer.readContract(symbolContract(pair.tokenAddress)),\n this.signer.readContract(decimalsContract(pair.tokenAddress)),\n this.signer.readContract(erc20TotalSupplyContract(pair.tokenAddress)),\n this.signer.readContract(nameContract(pair.confidentialTokenAddress)),\n this.signer.readContract(symbolContract(pair.confidentialTokenAddress)),\n this.signer.readContract(decimalsContract(pair.confidentialTokenAddress)),\n ]);\n\n return {\n ...pair,\n underlying: {\n name: uName,\n symbol: uSymbol,\n decimals: uDecimals,\n totalSupply: uTotalSupply,\n },\n confidential: { name: cName, symbol: cSymbol, decimals: cDecimals },\n };\n }\n\n // ---------------------------------------------------------------------------\n // Structured single-pair lookups\n // ---------------------------------------------------------------------------\n\n /**\n * Look up the confidential token for a given plain ERC-20 address.\n *\n * @param tokenAddress - The plain ERC-20 token address.\n * @returns The lookup result, or `null` if no pair is registered.\n *\n * @example\n * ```ts\n * const result = await registry.getConfidentialToken(usdcAddress);\n * if (result) {\n * console.log(result.confidentialTokenAddress, result.isValid);\n * }\n * ```\n */\n async getConfidentialToken(\n tokenAddress: Address,\n ): Promise<{ confidentialTokenAddress: Address; isValid: boolean } | null> {\n const registry = await this.getRegistryAddress();\n const normalized = getAddress(tokenAddress);\n\n const cacheKey = `ct:${registry}:${normalized}`;\n const cached = this.#getCached<{\n confidentialTokenAddress: Address;\n isValid: boolean;\n } | null>(cacheKey);\n if (cached !== undefined) {\n return cached;\n }\n\n const [found, confidentialTokenAddress] = await this.signer.readContract(\n getConfidentialTokenAddressContract(registry, normalized),\n );\n\n if (!found) {\n return this.#setCached(cacheKey, null, NEGATIVE_CACHE_TTL_MS);\n }\n\n // Check validity via isConfidentialTokenValid\n const isValid = await this.signer.readContract(\n isConfidentialTokenValidContract(registry, confidentialTokenAddress),\n );\n\n return this.#setCached(cacheKey, { confidentialTokenAddress, isValid });\n }\n\n /**\n * Reverse lookup — find the plain ERC-20 for a given confidential token.\n *\n * @param confidentialTokenAddress - The confidential token address.\n * @returns The lookup result, or `null` if no pair is registered.\n *\n * @example\n * ```ts\n * const result = await registry.getUnderlyingToken(cUsdcAddress);\n * if (result) {\n * console.log(result.tokenAddress, result.isValid);\n * }\n * ```\n */\n async getUnderlyingToken(\n confidentialTokenAddress: Address,\n ): Promise<{ tokenAddress: Address; isValid: boolean } | null> {\n const registry = await this.getRegistryAddress();\n const normalized = getAddress(confidentialTokenAddress);\n\n const cacheKey = `ut:${registry}:${normalized}`;\n const cached = this.#getCached<{\n tokenAddress: Address;\n isValid: boolean;\n } | null>(cacheKey);\n if (cached !== undefined) {\n return cached;\n }\n\n const [found, tokenAddress] = await this.signer.readContract(\n getTokenAddressContract(registry, normalized),\n );\n\n if (!found) {\n return this.#setCached(cacheKey, null, NEGATIVE_CACHE_TTL_MS);\n }\n\n const isValid = await this.signer.readContract(\n isConfidentialTokenValidContract(registry, normalized),\n );\n\n return this.#setCached(cacheKey, { tokenAddress, isValid });\n }\n\n // ---------------------------------------------------------------------------\n // Low-level pass-through methods (backward compatible)\n // ---------------------------------------------------------------------------\n\n /**\n * Fetch all token wrapper pairs from the registry.\n *\n * @returns All registered `TokenWrapperPair` entries.\n */\n async getTokenPairs(): Promise<readonly TokenWrapperPair[]> {\n const registry = await this.getRegistryAddress();\n return this.signer.readContract(getTokenPairsContract(registry));\n }\n\n /**\n * Get the total number of token wrapper pairs.\n *\n * @returns The count as a bigint.\n */\n async getTokenPairsLength(): Promise<bigint> {\n const registry = await this.getRegistryAddress();\n return this.signer.readContract(getTokenPairsLengthContract(registry));\n }\n\n /**\n * Fetch a range of token wrapper pairs (paginated by index).\n *\n * @param fromIndex - Start index (inclusive).\n * @param toIndex - End index (exclusive).\n * @returns The slice of `TokenWrapperPair` entries.\n */\n async getTokenPairsSlice(\n fromIndex: bigint,\n toIndex: bigint,\n ): Promise<readonly TokenWrapperPair[]> {\n const registry = await this.getRegistryAddress();\n return this.signer.readContract(getTokenPairsSliceContract(registry, fromIndex, toIndex));\n }\n\n /**\n * Fetch a single token wrapper pair by index.\n *\n * @param index - Zero-based pair index.\n * @returns The `TokenWrapperPair` at that index.\n */\n async getTokenPair(index: bigint): Promise<TokenWrapperPair> {\n const registry = await this.getRegistryAddress();\n return this.signer.readContract(getTokenPairContract(registry, index));\n }\n\n /**\n * Look up the confidential token address for a given plain ERC-20 token.\n *\n * @param tokenAddress - The plain ERC-20 token address.\n * @returns A tuple `[found, confidentialTokenAddress]`.\n */\n async getConfidentialTokenAddress(tokenAddress: Address): Promise<readonly [boolean, Address]> {\n const registry = await this.getRegistryAddress();\n return this.signer.readContract(\n getConfidentialTokenAddressContract(registry, getAddress(tokenAddress)),\n );\n }\n\n /**\n * Reverse lookup — find the plain ERC-20 for a given confidential token.\n *\n * @param confidentialTokenAddress - The confidential token address.\n * @returns A tuple `[found, tokenAddress]`.\n */\n async getTokenAddress(confidentialTokenAddress: Address): Promise<readonly [boolean, Address]> {\n const registry = await this.getRegistryAddress();\n return this.signer.readContract(\n getTokenAddressContract(registry, getAddress(confidentialTokenAddress)),\n );\n }\n\n /**\n * Check whether a confidential token is registered and valid.\n *\n * @param confidentialTokenAddress - The confidential token address to check.\n * @returns `true` if the token is a known valid wrapper in the registry.\n */\n async isConfidentialTokenValid(confidentialTokenAddress: Address): Promise<boolean> {\n const registry = await this.getRegistryAddress();\n return this.signer.readContract(\n isConfidentialTokenValidContract(registry, getAddress(confidentialTokenAddress)),\n );\n }\n}\n","import { getAddress, type Address } from \"viem\";\nimport { CredentialsManager } from \"./credentials/credentials-manager\";\nimport { DelegatedCredentialsManager } from \"./credentials/delegated-credentials-manager\";\nimport type { ZamaSDKEventListener } from \"./events/sdk-events\";\nimport { ZamaSDKEvents } from \"./events/sdk-events\";\nimport type { RelayerSDK } from \"./relayer/relayer-sdk\";\nimport { MemoryStorage } from \"./storage/memory-storage\";\nimport { ReadonlyToken } from \"./token/readonly-token\";\nimport { Token } from \"./token/token\";\nimport type { GenericSigner, GenericStorage, SignerLifecycleCallbacks } from \"./types\";\nimport { toError } from \"./utils\";\nimport { WrappersRegistry } from \"./wrappers-registry\";\n\n/** Configuration for {@link ZamaSDK}. */\nexport interface ZamaSDKConfig {\n /** FHE relayer backend (`RelayerWeb` for browser, `RelayerNode` for server). */\n relayer: RelayerSDK;\n /** Wallet signer (`ViemSigner`, `EthersSigner`, or custom {@link GenericSigner}). */\n signer: GenericSigner;\n /** Credential storage backend (`IndexedDBStorage` for browser, `MemoryStorage` for tests). */\n storage: GenericStorage;\n /**\n * Session storage for wallet signatures. Shared across all tokens created by this SDK instance.\n * Defaults to an in-memory store (lost on page reload). Pass a `chrome.storage.session`-backed\n * implementation for web extensions so signatures survive service worker restarts.\n */\n sessionStorage?: GenericStorage;\n /**\n * How long the ML-KEM re-encryption keypair remains valid, in seconds.\n * Default: `2592000` (30 days). Must be a positive number — `0` is rejected\n * because the keypair is required to establish the relayer connection.\n */\n keypairTTL?: number;\n /**\n * Controls how long session signatures (EIP-712 wallet signatures) remain valid, in seconds.\n * Default: `2592000` (30 days).\n * - `0`: never persist — every operation triggers a signing prompt (high-security mode).\n * - `\"infinite\"`: session never expires.\n * - Positive number: seconds until the session signature expires and requires re-authentication.\n */\n sessionTTL?: number | \"infinite\";\n /** Optional structured event listener for debugging and telemetry. Never receives sensitive data. */\n onEvent?: ZamaSDKEventListener;\n /**\n * Per-chain wrappers registry address overrides, merged on top of built-in defaults.\n * Use this for custom or local chains (e.g. Hardhat) where no default registry exists.\n */\n registryAddresses?: Record<number, Address>;\n /**\n * How long cached registry results remain valid, in seconds.\n * Default: `86400` (24 hours).\n */\n registryTTL?: number;\n /** Optional signer lifecycle callbacks composed with the SDK's internal session handling. */\n signerLifecycleCallbacks?: SignerLifecycleCallbacks;\n}\n\n/**\n * ZamaSDK — composes a RelayerSDK with contract abstraction.\n * Provides signer, storage, and high-level confidential contract interface.\n */\nexport class ZamaSDK {\n readonly relayer: RelayerSDK;\n readonly signer: GenericSigner;\n readonly storage: GenericStorage;\n readonly sessionStorage: GenericStorage;\n readonly credentials: CredentialsManager;\n readonly delegatedCredentials: DelegatedCredentialsManager;\n /**\n * A {@link WrappersRegistry} instance auto-configured for the current chain.\n * Uses built-in defaults merged with any `registryAddresses` overrides, and the SDK's `registryTTL` if configured.\n *\n * @example\n * ```ts\n * const pairs = await sdk.registry.listPairs({ page: 1 });\n * const result = await sdk.registry.getConfidentialToken(erc20Address);\n * ```\n */\n readonly registry: WrappersRegistry;\n readonly #registryTTL: number | undefined;\n readonly #onEvent: ZamaSDKEventListener;\n #unsubscribeSigner?: () => void;\n // oxlint false positive: awaited in #revokeByTrackedIdentity() and revokeSession()\n // eslint-disable-next-line no-unused-private-class-members\n #identityReady: Promise<void>;\n #lastAddress: Address | null = null;\n #lastChainId: number | null = null;\n\n constructor(config: ZamaSDKConfig) {\n this.relayer = config.relayer;\n this.signer = config.signer;\n this.storage = config.storage;\n this.sessionStorage = config.sessionStorage ?? new MemoryStorage();\n this.#onEvent = config.onEvent ?? function () {};\n this.registry = new WrappersRegistry({\n signer: this.signer,\n registryAddresses: config.registryAddresses,\n registryTTL: config.registryTTL,\n });\n this.#registryTTL = config.registryTTL;\n const credentialsConfig = {\n relayer: this.relayer,\n signer: this.signer,\n storage: this.storage,\n sessionStorage: this.sessionStorage,\n keypairTTL: (() => {\n const ttl = config.keypairTTL ?? 2592000;\n if (ttl <= 0) {\n throw new Error(\"keypairTTL must be a positive number (seconds)\");\n }\n return ttl;\n })(),\n sessionTTL: config.sessionTTL ?? 2592000,\n onEvent: this.#onEvent,\n };\n this.credentials = new CredentialsManager(credentialsConfig);\n this.delegatedCredentials = new DelegatedCredentialsManager(credentialsConfig);\n this.#identityReady = this.#initIdentity();\n\n if (this.signer.subscribe) {\n const lifecycleCallbacks = config.signerLifecycleCallbacks;\n const runLifecycleEffect = (operation: string, effect: () => Promise<void>) => {\n void effect().catch((error) => {\n this.#onEvent?.({\n type: ZamaSDKEvents.TransactionError,\n operation,\n error: toError(error),\n timestamp: Date.now(),\n });\n });\n };\n this.#unsubscribeSigner = this.signer.subscribe({\n onDisconnect: () => {\n runLifecycleEffect(\"signerDisconnect\", async () => {\n await this.#revokeByTrackedIdentity();\n this.#lastAddress = null;\n this.#lastChainId = null;\n lifecycleCallbacks?.onDisconnect?.();\n });\n },\n onAccountChange: (newAddress: Address) => {\n runLifecycleEffect(\"signerAccountChange\", async () => {\n await this.#revokeByTrackedIdentity();\n this.#lastAddress = getAddress(newAddress);\n try {\n this.#lastChainId = await this.signer.getChainId();\n } catch {\n // Signer may not be ready — keep previous chainId\n }\n lifecycleCallbacks?.onAccountChange?.(newAddress);\n });\n },\n onChainChange: (newChainId: number) => {\n runLifecycleEffect(\"signerChainChange\", async () => {\n await this.#revokeByTrackedIdentity();\n this.#lastChainId = newChainId;\n try {\n this.#lastAddress = await this.signer.getAddress();\n } catch {\n // Signer may not be ready — keep previous address\n }\n lifecycleCallbacks?.onChainChange?.(newChainId);\n });\n },\n });\n }\n }\n\n async #initIdentity(): Promise<void> {\n try {\n const address = await this.signer.getAddress();\n const chainId = await this.signer.getChainId();\n // Only commit both values atomically so revokeByTrackedIdentity\n // never sees a partial (address-only) state.\n this.#lastAddress = address;\n this.#lastChainId = chainId;\n } catch {\n // Signer not ready yet — identity will be set on first lifecycle event\n }\n }\n\n async #revokeByTrackedIdentity(): Promise<void> {\n await this.#identityReady;\n if (this.#lastAddress === null || this.#lastChainId === null) {\n return;\n }\n const storeKey = await CredentialsManager.computeStoreKey(this.#lastAddress, this.#lastChainId);\n await this.credentials.revokeByKey(storeKey);\n }\n\n /**\n * Create a read-only interface for a confidential token.\n * Supports balance queries and authorization without a wrapper address.\n *\n * @param address - The confidential token contract address.\n * @returns A {@link ReadonlyToken} instance bound to this SDK's relayer, signer, and storage.\n */\n createReadonlyToken(address: Address): ReadonlyToken {\n return new ReadonlyToken({\n relayer: this.relayer,\n signer: this.signer,\n storage: this.storage,\n sessionStorage: this.sessionStorage,\n credentials: this.credentials,\n delegatedCredentials: this.delegatedCredentials,\n address: getAddress(address),\n onEvent: this.#onEvent,\n });\n }\n\n /**\n * Create a high-level ERC-20-like interface for a confidential token.\n * Includes write operations (transfer, shield, unshield).\n *\n * @param address - The confidential token contract address (also used as wrapper by default).\n * @param wrapper - Optional explicit wrapper address, if it differs from the token address.\n * @returns A {@link Token} instance bound to this SDK's relayer, signer, and storage.\n */\n createToken(address: Address, wrapper?: Address): Token {\n return new Token({\n relayer: this.relayer,\n signer: this.signer,\n storage: this.storage,\n sessionStorage: this.sessionStorage,\n credentials: this.credentials,\n delegatedCredentials: this.delegatedCredentials,\n address: getAddress(address),\n wrapper: wrapper ? getAddress(wrapper) : undefined,\n onEvent: this.#onEvent,\n });\n }\n\n /**\n * Create a {@link WrappersRegistry} instance bound to this SDK's signer.\n * On Mainnet and Sepolia the registry address is resolved automatically.\n *\n * @param registryAddresses - Optional per-chain overrides (e.g. Hardhat).\n * @returns A {@link WrappersRegistry} instance.\n *\n * @example\n * ```ts\n * // Mainnet / Sepolia — resolved automatically\n * const registry = sdk.createWrappersRegistry();\n *\n * // Hardhat or custom chain — override per chain\n * const registry = sdk.createWrappersRegistry({ [31337]: \"0xYourRegistry\" });\n *\n * const pairs = await registry.getTokenPairs();\n * ```\n */\n createWrappersRegistry(registryAddresses?: Record<number, Address>): WrappersRegistry {\n return new WrappersRegistry({\n signer: this.signer,\n registryAddresses,\n registryTTL: this.#registryTTL,\n });\n }\n\n /**\n * Pre-authorize FHE credentials for one or more contract addresses.\n * A single wallet signature covers all addresses, so subsequent decrypt\n * operations on any of these contracts reuse cached credentials.\n *\n * @param contractAddresses - Contract addresses to authorize.\n *\n * @example\n * ```ts\n * await sdk.allow(\"0xContractA\", \"0xContractB\");\n * ```\n */\n async allow(...contractAddresses: Address[]): Promise<void> {\n await this.credentials.allow(...contractAddresses);\n }\n\n /**\n * Revoke the session signature for the current signer.\n * The next decrypt operation will require a fresh wallet signature.\n *\n * @param contractAddresses - Optional addresses included in the\n * `credentials:revoked` event for observability.\n *\n * @example\n * ```ts\n * wallet.on(\"disconnect\", () => sdk.revoke());\n * await sdk.revoke(\"0xContractA\", \"0xContractB\");\n * ```\n */\n async revoke(...contractAddresses: Address[]): Promise<void> {\n await this.credentials.revoke(...contractAddresses);\n }\n\n /**\n * Revoke the session signature for the current signer without requiring\n * contract addresses. Uses the tracked identity when available (safe during\n * account switches), falling back to querying the signer directly.\n *\n * @example\n * ```ts\n * wallet.on(\"disconnect\", () => sdk.revokeSession());\n * ```\n */\n async revokeSession(): Promise<void> {\n await this.#identityReady;\n const address = this.#lastAddress ?? (await this.signer.getAddress());\n const chainId = this.#lastChainId ?? (await this.signer.getChainId());\n const storeKey = await CredentialsManager.computeStoreKey(address, chainId);\n await this.credentials.revokeByKey(storeKey);\n }\n\n /**\n * Whether a session signature is currently cached for the connected wallet.\n * Use this to check if decrypt operations can proceed without a wallet prompt.\n */\n async isAllowed(): Promise<boolean> {\n return this.credentials.isAllowed();\n }\n\n /**\n * Unsubscribe from signer lifecycle events without terminating the relayer.\n * Call this when the SDK instance is being replaced but the relayer is shared\n * (e.g. React provider remount in Strict Mode).\n */\n dispose(): void {\n this.#unsubscribeSigner?.();\n this.#unsubscribeSigner = undefined;\n }\n\n /**\n * Terminate the relayer backend and clean up resources.\n * Call this when the SDK is no longer needed (e.g. on unmount or shutdown).\n */\n terminate(): void {\n this.dispose();\n this.relayer.terminate();\n }\n\n /**\n * Implements the TC39 Explicit Resource Management protocol.\n * Calls {@link terminate} when the `using` binding goes out of scope,\n * unsubscribing signer events and shutting down the relayer.\n *\n * @example\n * ```ts\n * {\n * using sdk = new ZamaSDK({ relayer, signer, storage });\n * await sdk.allow(cUSDT);\n * const balance = await sdk.createReadonlyToken(cUSDT).balanceOf();\n * } // sdk.terminate() called automatically here\n * ```\n */\n [Symbol.dispose](): void {\n this.terminate();\n }\n}\n","import type { Address, Hex } from \"viem\";\nimport type { GenericStorage } from \"../types\";\n\nconst STORAGE_PREFIX = \"zama:pending-unshield:\";\n\nfunction storageKey(wrapperAddress: Address): string {\n return `${STORAGE_PREFIX}${wrapperAddress}`;\n}\n\n/**\n * Persist the unwrap tx hash so an interrupted unshield can be resumed later\n * (e.g. after a page reload).\n */\nexport async function savePendingUnshield(\n storage: GenericStorage,\n wrapperAddress: Address,\n unwrapTxHash: Hex,\n): Promise<void> {\n await storage.set(storageKey(wrapperAddress), unwrapTxHash);\n}\n\n/**\n * Load a previously saved unwrap tx hash, or `null` if none exists.\n */\nexport async function loadPendingUnshield(\n storage: GenericStorage,\n wrapperAddress: Address,\n): Promise<Hex | null> {\n return storage.get<Hex>(storageKey(wrapperAddress));\n}\n\n/**\n * Clear the saved unwrap tx hash after a successful finalization.\n */\nexport async function clearPendingUnshield(\n storage: GenericStorage,\n wrapperAddress: Address,\n): Promise<void> {\n await storage.delete(storageKey(wrapperAddress));\n}\n","import type { GenericStorage } from \"../types\";\n\n/** Minimal chrome.storage.session typings (avoids depending on @types/chrome). */\ndeclare const chrome: {\n storage: {\n session: {\n get(key: string): Promise<Record<string, unknown>>;\n set(items: Record<string, unknown>): Promise<void>;\n remove(key: string): Promise<void>;\n };\n };\n};\n\n/**\n * {@link GenericStorage} backed by `chrome.storage.session`.\n *\n * Use this in MV3 web extensions so the wallet signature survives\n * service worker restarts and is shared across popup, background,\n * and content script contexts.\n *\n * @example\n * ```ts\n * import { ZamaSDK, indexedDBStorage, chromeSessionStorage } from \"@zama-fhe/sdk\";\n *\n * const sdk = new ZamaSDK({\n * relayer,\n * signer,\n * storage: indexedDBStorage,\n * sessionStorage: chromeSessionStorage,\n * });\n * ```\n */\nexport class ChromeSessionStorage implements GenericStorage {\n async get<T = unknown>(key: string): Promise<T | null> {\n const result = await chrome.storage.session.get(key);\n return (result[key] as T) ?? null;\n }\n\n async set(key: string, value: unknown): Promise<void> {\n await chrome.storage.session.set({ [key]: value });\n }\n\n async delete(key: string): Promise<void> {\n await chrome.storage.session.remove(key);\n }\n}\n\n/** Default singleton for application-wide use. */\nexport const chromeSessionStorage = new ChromeSessionStorage();\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["#dbName","#dbVersion","#storeName","#db","#dbPromise","#withTransaction","#getDB","workerFilename","workerCode","#config","#status","#initError","#getWorkerConfig","#ensureWorker","#ensureLock","#ensureWorkerInner","#workerClient","#initPromise","#artifactCache","#terminated","#resolvedChainId","#tearDown","#artifactStorage","#setStatus","#initWorker","#refreshCsrfToken","#getUnderlying","#underlying","#underlyingPromise","#assertConfidentialBalance","#ensureAllowance","#waitAndFinalizeUnshield","#batchDelegationOp","#addresses","#ttlMs","#cache","#getCached","#setCached","#pairWithMetadata","#registryTTL","#onEvent","#identityReady","#initIdentity","#unsubscribeSigner","#revokeByTrackedIdentity","#lastAddress","#lastChainId"],"sources":["../../src/errors/transaction.ts","../../src/errors/balance.ts","../../src/errors/acl-revert.ts","../../src/storage/indexeddb-storage.ts","../../src/worker/browser-extension.ts","../../src/worker/worker.client.ts","../../src/relayer/relayer-web.ts","../../src/token/token.ts","../../src/wrappers-registry.ts","../../src/zama-sdk.ts","../../src/token/pending-unshield.ts","../../src/storage/chrome-session-storage.ts"],"sourcesContent":["import { ZamaError, ZamaErrorCode } from \"./base\";\n\n/** ERC-20 approval transaction failed. */\nexport class ApprovalFailedError extends ZamaError {\n constructor(message: string, options?: ErrorOptions) {\n super(ZamaErrorCode.ApprovalFailed, message, options);\n this.name = \"ApprovalFailedError\";\n }\n}\n\n/** On-chain transaction reverted. */\nexport class TransactionRevertedError extends ZamaError {\n constructor(message: string, options?: ErrorOptions) {\n super(ZamaErrorCode.TransactionReverted, message, options);\n this.name = \"TransactionRevertedError\";\n }\n}\n","import type { Address } from \"viem\";\nimport { ZamaError, ZamaErrorCode } from \"./base\";\n\n/** Structured details shared by balance-related errors. */\nexport interface BalanceErrorDetails {\n readonly requested: bigint;\n readonly available: bigint;\n readonly token: Address;\n}\n\n/** Confidential (cToken) balance is insufficient for the requested operation. */\nexport class InsufficientConfidentialBalanceError extends ZamaError {\n /** The amount the caller requested. */\n readonly requested: bigint;\n /** The available balance at the time of the check. */\n readonly available: bigint;\n /** The token contract address. */\n readonly token: Address;\n\n constructor(message: string, details: BalanceErrorDetails, options?: ErrorOptions) {\n super(ZamaErrorCode.InsufficientConfidentialBalance, message, options);\n this.name = \"InsufficientConfidentialBalanceError\";\n this.requested = details.requested;\n this.available = details.available;\n this.token = details.token;\n }\n}\n\n/** ERC-20 balance is insufficient for the requested shield amount. */\nexport class InsufficientERC20BalanceError extends ZamaError {\n /** The amount the caller requested. */\n readonly requested: bigint;\n /** The available balance at the time of the check. */\n readonly available: bigint;\n /** The ERC-20 token contract address. */\n readonly token: Address;\n\n constructor(message: string, details: BalanceErrorDetails, options?: ErrorOptions) {\n super(ZamaErrorCode.InsufficientERC20Balance, message, options);\n this.name = \"InsufficientERC20BalanceError\";\n this.requested = details.requested;\n this.available = details.available;\n this.token = details.token;\n }\n}\n\n/** Balance validation could not be performed (no cached credentials and decryption not possible). */\nexport class BalanceCheckUnavailableError extends ZamaError {\n constructor(message: string, options?: ErrorOptions) {\n super(ZamaErrorCode.BalanceCheckUnavailable, message, options);\n this.name = \"BalanceCheckUnavailableError\";\n }\n}\n\n/** A public ERC-20 read (e.g. balanceOf) failed due to a network or contract error. */\nexport class ERC20ReadFailedError extends ZamaError {\n constructor(message: string, options?: ErrorOptions) {\n super(ZamaErrorCode.ERC20ReadFailed, message, options);\n this.name = \"ERC20ReadFailedError\";\n }\n}\n","import type { ZamaError } from \"./base\";\nimport {\n AclPausedError,\n DelegationContractIsSelfError,\n DelegationCooldownError,\n DelegationDelegateEqualsContractError,\n DelegationExpirationTooSoonError,\n DelegationExpiryUnchangedError,\n DelegationNotFoundError,\n DelegationSelfNotAllowedError,\n} from \"./delegation\";\n\n/** Extract the decoded error name from a viem ContractFunctionRevertedError. */\nfunction extractRevertErrorName(error: unknown): string | null {\n if (!(error instanceof Error)) {\n return null;\n }\n const cause = error.cause;\n if (typeof cause !== \"object\" || cause === null || !(\"data\" in cause)) {\n return null;\n }\n const { data } = cause;\n if (typeof data !== \"object\" || data === null || !(\"errorName\" in data)) {\n return null;\n }\n return typeof data.errorName === \"string\" ? data.errorName : null;\n}\n\n/** ACL error name -> typed SDK error mapping. */\nconst ACL_ERROR_MAP: Record<string, (cause: Error | undefined) => ZamaError> = {\n AlreadyDelegatedOrRevokedInSameBlock: (cause) =>\n new DelegationCooldownError(\n \"Only one delegate/revoke per (delegator, delegate, contract) per block. Wait for the next block before retrying.\",\n { cause },\n ),\n SenderCannotBeContractAddress: (cause) =>\n new DelegationContractIsSelfError(\"The contract address cannot be the caller address.\", {\n cause,\n }),\n EnforcedPause: (cause) =>\n new AclPausedError(\n \"The ACL contract is paused. Delegation operations are temporarily disabled.\",\n { cause },\n ),\n SenderCannotBeDelegate: (cause) =>\n new DelegationSelfNotAllowedError(\"Cannot delegate to yourself (delegate === msg.sender).\", {\n cause,\n }),\n DelegateCannotBeContractAddress: (cause) =>\n new DelegationDelegateEqualsContractError(\n \"Delegate address cannot be the same as the contract address.\",\n { cause },\n ),\n ExpirationDateBeforeOneHour: (cause) =>\n new DelegationExpirationTooSoonError(\"Expiration date must be at least 1 hour in the future.\", {\n cause,\n }),\n ExpirationDateAlreadySetToSameValue: (cause) =>\n new DelegationExpiryUnchangedError(\"The new expiration date is the same as the current one.\", {\n cause,\n }),\n NotDelegatedYet: (cause) =>\n new DelegationNotFoundError(\"Cannot revoke: no active delegation exists.\", { cause }),\n};\n\n/**\n * Map known ACL Solidity revert error names to typed ZamaError subclasses.\n * Prefers viem's structured `error.cause.data.errorName` when available,\n * falling back to string-includes matching on the error message.\n * Returns `null` if the revert reason is not recognized.\n * @public\n */\nexport function matchAclRevert(error: unknown): ZamaError | null {\n const cause = error instanceof Error ? error : undefined;\n\n // Prefer structured error data from viem's ContractFunctionRevertedError\n const errorName = extractRevertErrorName(error);\n if (errorName && errorName in ACL_ERROR_MAP) {\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- guarded by `in` check above\n return ACL_ERROR_MAP[errorName]!(cause);\n }\n\n // Fallback: string matching for non-viem RPC providers\n const message = error instanceof Error ? error.message : String(error);\n for (const [name, factory] of Object.entries(ACL_ERROR_MAP)) {\n if (message.includes(name)) {\n return factory(cause);\n }\n }\n\n return null;\n}\n","\"use client\";\n\nimport type { GenericStorage } from \"../types\";\n\n/**\n * IndexedDB-backed {@link GenericStorage}.\n *\n * Stores encrypted credential objects keyed by a hashed wallet address.\n * Encryption is handled by {@link CredentialsManager} — this store only\n * persists opaque values.\n */\nexport class IndexedDBStorage implements GenericStorage {\n #db: IDBDatabase | null = null;\n #dbPromise: Promise<IDBDatabase> | null = null;\n #dbName: string;\n #dbVersion: number;\n #storeName: string;\n\n constructor(dbName = \"CredentialStore\", dbVersion = 1, storeName = \"credentials\") {\n this.#dbName = dbName;\n this.#dbVersion = dbVersion;\n this.#storeName = storeName;\n }\n\n #getDB(): Promise<IDBDatabase> {\n if (this.#db) {\n return Promise.resolve(this.#db);\n }\n if (this.#dbPromise) {\n return this.#dbPromise;\n }\n\n this.#dbPromise = new Promise((resolve, reject) => {\n const request = indexedDB.open(this.#dbName, this.#dbVersion);\n\n request.onupgradeneeded = () => {\n const db = request.result;\n if (!db.objectStoreNames.contains(this.#storeName)) {\n db.createObjectStore(this.#storeName, { keyPath: \"key\" });\n }\n };\n\n request.onsuccess = () => {\n this.#db = request.result;\n this.#dbPromise = null;\n this.#db.onversionchange = () => {\n // oxlint-disable-next-line no-console\n console.warn(\n `IndexedDB \"${this.#dbName}\" closing due to version change from another tab`,\n );\n this.#db?.close();\n this.#db = null;\n this.#dbPromise = null;\n };\n this.#db.onclose = () => {\n this.#db = null;\n this.#dbPromise = null;\n };\n resolve(this.#db);\n };\n\n request.onerror = () => {\n this.#db = null;\n this.#dbPromise = null;\n reject(request.error);\n };\n });\n\n return this.#dbPromise;\n }\n\n async #withTransaction<T>(\n mode: IDBTransactionMode,\n fn: (store: IDBObjectStore) => IDBRequest,\n ): Promise<T> {\n const db = await this.#getDB();\n return new Promise((resolve, reject) => {\n const tx = db.transaction(this.#storeName, mode);\n tx.onabort = () => reject(tx.error ?? new Error(\"Transaction aborted\"));\n const request = fn(tx.objectStore(this.#storeName));\n if (mode === \"readonly\") {\n request.onsuccess = () => resolve(request.result);\n } else {\n tx.oncomplete = () => resolve(request.result);\n }\n request.onerror = () => reject(request.error);\n });\n }\n\n async get<T = unknown>(key: string): Promise<T | null> {\n const result = await this.#withTransaction<{ value: T } | undefined>(\"readonly\", (store) =>\n store.get(key),\n );\n return result?.value ?? null;\n }\n\n async set<T = unknown>(key: string, value: T): Promise<void> {\n await this.#withTransaction<void>(\"readwrite\", (store) => store.put({ key, value }));\n }\n\n async delete(key: string): Promise<void> {\n await this.#withTransaction<void>(\"readwrite\", (store) => store.delete(key));\n }\n\n async clear(): Promise<void> {\n await this.#withTransaction<void>(\"readwrite\", (store) => store.clear());\n }\n}\n\n/** Default singleton for application-wide use. */\nexport const indexedDBStorage = new IndexedDBStorage();\n","import { assertFunctionProp, assertObject, assertStringProp } from \"../utils/assertions\";\n\n/**\n * Subset of the WebExtensions `runtime` API used by the SDK.\n * @see https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/runtime\n */\nexport interface BrowserExtensionRuntime {\n /** The ID of the extension. */\n id: string;\n /** Convert a relative path within the extension to a fully-qualified URL. */\n getURL: (path: string) => string;\n}\n\nfunction isValidRuntime(runtime: unknown): runtime is BrowserExtensionRuntime {\n try {\n assertObject(runtime, \"runtime\");\n assertStringProp(runtime, \"id\", \"runtime.id\");\n assertFunctionProp<\"getURL\", (path: string) => string>(runtime, \"getURL\", \"runtime.getURL\");\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Return the browser extension runtime object, or `undefined` outside extensions.\n * Works across Chrome/Edge (`chrome.runtime`) and Firefox/Safari (`browser.runtime`).\n * Extensions have restricted CSP that blocks `blob:` URLs, so callers use\n * this to detect the environment and resolve file URLs via `runtime.getURL`.\n */\nexport function getBrowserExtensionRuntime(): BrowserExtensionRuntime | undefined {\n const g = globalThis as unknown as Record<string, unknown>;\n for (const ns of [g.chrome, g.browser]) {\n try {\n assertObject(ns, \"ns\");\n if (isValidRuntime(ns.runtime)) {\n return ns.runtime;\n }\n } catch {\n continue;\n }\n }\n return undefined;\n}\n","import type { FhevmInstanceConfig } from \"@zama-fhe/relayer-sdk/bundle\";\nimport type {\n GenericLogger,\n UpdateCsrfResponseData,\n WorkerRequest,\n WorkerRequestType,\n WorkerResponse,\n} from \"./worker.types\";\nimport { BaseWorkerClient } from \"./worker.base-client\";\nimport { getBrowserExtensionRuntime } from \"./browser-extension\";\nimport { default as workerCode, filename as workerFilename } from \"./relayer-sdk.worker.ts?iife\";\n\n/** Configuration for the worker client */\nexport interface WorkerClientConfig {\n cdnUrl: string;\n fhevmConfig: FhevmInstanceConfig;\n csrfToken: string;\n /** Expected SHA-384 hex digest of the CDN bundle for integrity verification. */\n integrity?: string;\n /** Optional logger for tracing worker request lifecycle. */\n logger?: GenericLogger;\n /** Number of WASM threads for parallel FHE operations (passed to `initSDK({ thread })`). */\n thread?: number;\n}\n\n/**\n * Client for communicating with the RelayerSDK Web Worker.\n * Provides a promise-based API for FHE operations.\n */\nexport class RelayerWorkerClient extends BaseWorkerClient<Worker, WorkerClientConfig> {\n constructor(config: WorkerClientConfig) {\n super(config, config.logger);\n }\n\n protected createWorker(): Worker {\n const runtime = getBrowserExtensionRuntime();\n if (runtime) {\n return new Worker(runtime.getURL(workerFilename));\n }\n const blobUrl = URL.createObjectURL(new Blob([workerCode], { type: \"application/javascript\" }));\n try {\n return new Worker(blobUrl);\n } finally {\n URL.revokeObjectURL(blobUrl);\n }\n }\n\n protected wireEvents(worker: Worker): void {\n worker.onmessage = (event: MessageEvent<WorkerResponse<unknown>>) =>\n this.handleResponse(event.data);\n worker.onerror = (event: ErrorEvent) => this.handleWorkerError(event.message);\n worker.onmessageerror = () => this.handleWorkerMessageError();\n }\n\n protected postMessage(worker: Worker, request: WorkerRequest): void {\n worker.postMessage(request);\n }\n\n protected terminateWorker(worker: Worker): void {\n worker.terminate();\n }\n\n protected generateRequestId(): string {\n return crypto.randomUUID();\n }\n\n protected getInitPayload(): {\n type: WorkerRequestType;\n payload: WorkerRequest[\"payload\"];\n } {\n // Explicitly construct the payload from serializable fields only.\n // Functions (e.g. `logger`) cannot be cloned by the structured clone\n // algorithm used by `worker.postMessage()`.\n const { cdnUrl, fhevmConfig, csrfToken, integrity, thread } = this.config;\n return { type: \"INIT\", payload: { cdnUrl, fhevmConfig, csrfToken, integrity, thread } };\n }\n\n /**\n * Update the CSRF token in the worker.\n * Call this before making authenticated requests to ensure the token is fresh.\n */\n async updateCsrf(csrfToken: string): Promise<void> {\n await this.sendRequest<UpdateCsrfResponseData>(\"UPDATE_CSRF\", {\n csrfToken,\n });\n }\n}\n","import type {\n InputProofBytesType,\n KeypairType,\n KmsDelegatedUserDecryptEIP712Type,\n ZKProofLike,\n} from \"@zama-fhe/relayer-sdk/bundle\";\nimport type { Address, Hex } from \"viem\";\nimport { ConfigurationError, ZamaError } from \"../errors\";\nimport { IndexedDBStorage } from \"../storage/indexeddb-storage\";\nimport type { GenericStorage } from \"../types\";\nimport { RelayerWorkerClient, type WorkerClientConfig } from \"../worker/worker.client\";\nimport { FheArtifactCache } from \"./fhe-artifact-cache\";\nimport type { RelayerSDK } from \"./relayer-sdk\";\nimport type {\n ClearValueType,\n DelegatedUserDecryptParams,\n EIP712TypedData,\n EncryptParams,\n EncryptResult,\n Handle,\n PublicDecryptResult,\n RelayerSDKStatus,\n RelayerWebConfig,\n UserDecryptParams,\n} from \"./relayer-sdk.types\";\nimport { buildEIP712DomainType, DefaultConfigs, withRetry } from \"./relayer-utils\";\n\n/**\n * Pinned relayer SDK version used for the WASM CDN bundle.\n * Update this when upgrading @zama-fhe/relayer-sdk, and keep the\n * peerDependencies range in package.json in sync (~x.y.z).\n */\nconst RELAYER_SDK_VERSION = \"0.4.2\";\nconst CDN_URL = `https://cdn.zama.org/relayer-sdk-js/${RELAYER_SDK_VERSION}/relayer-sdk-js.umd.cjs`;\n/** SHA-384 hex digest of the pinned CDN bundle for integrity verification. */\nconst CDN_INTEGRITY =\n \"114438b01d518b53a447fa3e8bfbe6e71031cb42ac43219bb9f53488456fdfa4bbc8989628366d436e68f6526c7647eb\";\n\n/**\n * RelayerWeb — browser encryption/decryption layer using a Web Worker.\n * Handles WASM initialization in a Web Worker for non-blocking operations.\n *\n * ## Worker initialization / promise lock pattern\n *\n * Every public method calls `#ensureWorker()` before proceeding.\n * Initialization is managed by three private fields:\n *\n * - `#workerClient` — the live worker instance (null until first init)\n * - `#initPromise` — cached promise from `#initWorker()`; once resolved,\n * all subsequent callers reuse the same worker without re-initializing.\n * Cleared on error so the next caller retries a fresh init.\n * - `#ensureLock` — short-lived promise that serializes concurrent calls\n * to `#ensureWorkerInner()`. While one caller is checking chain IDs and\n * potentially tearing down an old worker, all other callers await the\n * same lock instead of racing through the same logic. Cleared in\n * `finally` so it's never leaked.\n *\n * Chain switching: when `getChainId()` returns a value different from the\n * previously resolved chain, the old worker is terminated, `#initPromise`\n * is cleared, and a fresh worker is created for the new chain — all within\n * the `#ensureLock` critical section.\n */\nexport class RelayerWeb implements RelayerSDK, Disposable {\n #workerClient: RelayerWorkerClient | null = null;\n #initPromise: Promise<RelayerWorkerClient> | null = null;\n #ensureLock: Promise<RelayerWorkerClient> | null = null;\n #terminated = false;\n #resolvedChainId: number | null = null;\n #artifactCache: FheArtifactCache | null = null;\n #artifactStorage: GenericStorage | null = null;\n #status: RelayerSDKStatus = \"idle\";\n #initError: Error | undefined;\n readonly #config: RelayerWebConfig;\n\n constructor(config: RelayerWebConfig) {\n this.#config = config;\n }\n\n /** Current WASM initialization status. */\n get status(): RelayerSDKStatus {\n return this.#status;\n }\n\n /** The error that caused initialization to fail, if `status` is `\"error\"`. */\n get initError(): Error | undefined {\n return this.#initError;\n }\n\n #setStatus(status: RelayerSDKStatus, error?: Error): void {\n this.#status = status;\n this.#initError = error;\n this.#config.onStatusChange?.(status, error);\n }\n\n async #getWorkerConfig(): Promise<WorkerClientConfig> {\n const chainId = await this.#config.getChainId();\n const { transports, security, threads } = this.#config;\n\n if (threads !== undefined && (!Number.isInteger(threads) || threads < 1)) {\n throw new Error(`Invalid thread count: ${threads}. Must be a positive integer.`);\n }\n\n if (threads !== undefined && globalThis.SharedArrayBuffer === undefined) {\n this.#config.logger?.warn(\n \"threads option requires SharedArrayBuffer (COOP/COEP headers). Falling back to single-threaded.\",\n );\n }\n\n return {\n cdnUrl: CDN_URL,\n fhevmConfig: Object.assign({}, DefaultConfigs[chainId], transports[chainId]),\n csrfToken: security?.getCsrfToken?.() ?? \"\",\n integrity: security?.integrityCheck === false ? undefined : CDN_INTEGRITY,\n logger: this.#config.logger,\n // Public API uses `threads` (plural, \"how many threads\"); upstream\n // `initSDK` expects `thread` (singular) — rename at the boundary.\n thread: threads,\n };\n }\n\n /**\n * Ensure the worker is initialized.\n * Uses a promise lock to prevent concurrent initialization.\n * Resets on failure to allow retries.\n */\n async #ensureWorker(): Promise<RelayerWorkerClient> {\n if (this.#ensureLock) {\n return this.#ensureLock;\n }\n this.#ensureLock = this.#ensureWorkerInner();\n try {\n return await this.#ensureLock;\n } finally {\n this.#ensureLock = null;\n }\n }\n\n #tearDown(): void {\n this.#workerClient?.terminate();\n this.#workerClient = null;\n this.#initPromise = null;\n this.#artifactCache = null;\n }\n\n async #ensureWorkerInner(): Promise<RelayerWorkerClient> {\n // Auto-restart after terminate() — supports React StrictMode's\n // unmount→remount cycle and HMR without permanently killing the worker.\n if (this.#terminated) {\n this.#terminated = false;\n this.#workerClient = null;\n this.#initPromise = null;\n this.#resolvedChainId = null;\n }\n\n const chainId = await this.#config.getChainId();\n\n // Chain changed → tear down old worker, re-init\n if (this.#resolvedChainId !== null && chainId !== this.#resolvedChainId) {\n this.#tearDown();\n }\n\n this.#resolvedChainId = chainId;\n\n // Create cache for current chain.\n // Storage is chain-independent — reuse across chain switches.\n if (!this.#artifactStorage) {\n this.#artifactStorage =\n this.#config.fheArtifactStorage ?? new IndexedDBStorage(\"FheArtifactCache\", 1, \"artifacts\");\n }\n if (!this.#artifactCache) {\n const config = Object.assign({}, DefaultConfigs[chainId], this.#config.transports[chainId]);\n this.#artifactCache = new FheArtifactCache({\n storage: this.#artifactStorage,\n chainId,\n relayerUrl: config.relayerUrl,\n ttl: this.#config.fheArtifactCacheTTL,\n logger: this.#config.logger,\n });\n }\n\n // Revalidate cached artifacts if due — never let revalidation block init\n if (this.#artifactCache) {\n let stale = false;\n try {\n stale = await this.#artifactCache.revalidateIfDue();\n } catch (err) {\n this.#config.logger?.warn(\n \"Artifact revalidation failed, proceeding with potentially stale cache\",\n { error: err instanceof Error ? err.message : String(err) },\n );\n }\n if (stale) {\n this.#config.logger?.info(\"Cached FHE artifacts are stale — reinitializing\");\n this.#tearDown();\n }\n }\n\n if (!this.#initPromise) {\n this.#setStatus(\"initializing\");\n this.#initPromise = this.#initWorker()\n .then((client) => {\n this.#setStatus(\"ready\");\n return client;\n })\n .catch((error) => {\n this.#initPromise = null;\n const wrappedError =\n error instanceof ZamaError\n ? error\n : new ConfigurationError(\"Failed to initialize FHE worker\", {\n cause: error,\n });\n this.#setStatus(\"error\", wrappedError);\n throw wrappedError;\n });\n }\n return this.#initPromise;\n }\n\n /**\n * Initialize the worker (called once via promise lock).\n */\n async #initWorker(): Promise<RelayerWorkerClient> {\n const workerConfig = await this.#getWorkerConfig();\n const client = new RelayerWorkerClient(workerConfig);\n await client.initWorker();\n // If terminate() was called while we were initializing, clean up immediately\n if (this.#terminated) {\n client.terminate();\n throw new Error(\"RelayerWeb was terminated during initialization\");\n }\n this.#workerClient = client;\n return client;\n }\n\n /**\n * Terminate the worker and clean up resources.\n * Call this when the SDK is no longer needed.\n */\n terminate(): void {\n this.#terminated = true;\n if (this.#workerClient) {\n this.#workerClient.terminate();\n this.#workerClient = null;\n }\n this.#initPromise = null;\n this.#ensureLock = null;\n }\n\n /** Calls {@link terminate}, shutting down the Web Worker. */\n [Symbol.dispose](): void {\n this.terminate();\n }\n\n /**\n * Refresh the CSRF token in the worker.\n * Call this before making authenticated network requests.\n */\n async #refreshCsrfToken(): Promise<void> {\n if (this.#workerClient) {\n const token = this.#config.security?.getCsrfToken?.() ?? \"\";\n if (token) {\n await this.#workerClient.updateCsrf(token);\n }\n }\n }\n\n /**\n * Generate a keypair for FHE operations.\n */\n async generateKeypair(): Promise<KeypairType<Hex>> {\n const worker = await this.#ensureWorker();\n const result = await worker.generateKeypair();\n return {\n publicKey: result.publicKey,\n privateKey: result.privateKey,\n };\n }\n\n /**\n * Create EIP712 typed data for user decryption authorization.\n */\n async createEIP712(\n publicKey: Hex,\n contractAddresses: Address[],\n startTimestamp: number,\n durationDays = 7,\n ): Promise<EIP712TypedData> {\n const worker = await this.#ensureWorker();\n const result = await worker.createEIP712({\n publicKey,\n contractAddresses,\n startTimestamp,\n durationDays,\n });\n\n const domain = {\n name: result.domain.name,\n version: result.domain.version,\n chainId: result.domain.chainId,\n verifyingContract: result.domain.verifyingContract,\n };\n\n return {\n domain,\n types: {\n EIP712Domain: buildEIP712DomainType(domain),\n UserDecryptRequestVerification: result.types.UserDecryptRequestVerification,\n },\n message: {\n publicKey: result.message.publicKey,\n contractAddresses: result.message.contractAddresses,\n startTimestamp: result.message.startTimestamp,\n durationDays: result.message.durationDays,\n extraData: result.message.extraData,\n },\n };\n }\n\n /**\n * Encrypt values for use in smart contract calls.\n * Each value must specify its FHE type (ebool, euint8–256, eaddress).\n */\n async encrypt(params: EncryptParams): Promise<EncryptResult> {\n const { values, contractAddress, userAddress } = params;\n\n return withRetry(async () => {\n const worker = await this.#ensureWorker();\n await this.#refreshCsrfToken();\n const result = await worker.encrypt({\n values,\n contractAddress,\n userAddress,\n });\n return { handles: result.handles, inputProof: result.inputProof };\n });\n }\n\n /**\n * Decrypt ciphertexts using user's private key.\n * Requires a valid EIP712 signature.\n */\n async userDecrypt(params: UserDecryptParams): Promise<Readonly<Record<Handle, ClearValueType>>> {\n return withRetry(async () => {\n const worker = await this.#ensureWorker();\n await this.#refreshCsrfToken();\n const result = await worker.userDecrypt(params);\n return result.clearValues;\n });\n }\n\n /**\n * Public decryption - no authorization needed.\n * Used for publicly visible encrypted values.\n */\n async publicDecrypt(handles: Handle[]): Promise<PublicDecryptResult> {\n return withRetry(async () => {\n const worker = await this.#ensureWorker();\n await this.#refreshCsrfToken();\n const result = await worker.publicDecrypt(handles);\n return {\n clearValues: result.clearValues,\n abiEncodedClearValues: result.abiEncodedClearValues,\n decryptionProof: result.decryptionProof,\n };\n });\n }\n\n /**\n * Create EIP712 typed data for delegated user decryption authorization.\n */\n async createDelegatedUserDecryptEIP712(\n publicKey: Hex,\n contractAddresses: Address[],\n delegatorAddress: Address,\n startTimestamp: number,\n durationDays = 7,\n ): Promise<KmsDelegatedUserDecryptEIP712Type> {\n const worker = await this.#ensureWorker();\n return worker.createDelegatedUserDecryptEIP712({\n publicKey,\n contractAddresses,\n delegatorAddress,\n startTimestamp,\n durationDays,\n });\n }\n\n /**\n * Decrypt ciphertexts via delegation.\n * Requires a valid EIP712 signature from the delegator.\n */\n async delegatedUserDecrypt(\n params: DelegatedUserDecryptParams,\n ): Promise<Readonly<Record<Handle, ClearValueType>>> {\n return withRetry(async () => {\n const worker = await this.#ensureWorker();\n await this.#refreshCsrfToken();\n const result = await worker.delegatedUserDecrypt(params);\n return result.clearValues;\n });\n }\n\n /**\n * Submit a ZK proof to the relayer for verification.\n */\n async requestZKProofVerification(zkProof: ZKProofLike): Promise<InputProofBytesType> {\n return withRetry(async () => {\n const worker = await this.#ensureWorker();\n await this.#refreshCsrfToken();\n return worker.requestZKProofVerification(zkProof);\n });\n }\n\n /**\n * Get the TFHE compact public key.\n * When storage is configured, the result is cached persistently.\n */\n async getPublicKey(): Promise<{\n publicKeyId: string;\n publicKey: Uint8Array;\n } | null> {\n const worker = await this.#ensureWorker();\n if (this.#artifactCache) {\n return this.#artifactCache.getPublicKey(async () => (await worker.getPublicKey()).result);\n }\n return (await worker.getPublicKey()).result;\n }\n\n /**\n * Get public parameters for encryption capacity.\n * When storage is configured, the result is cached persistently.\n */\n async getPublicParams(\n bits: number,\n ): Promise<{ publicParams: Uint8Array; publicParamsId: string } | null> {\n const worker = await this.#ensureWorker();\n if (this.#artifactCache) {\n return this.#artifactCache.getPublicParams(\n bits,\n async () => (await worker.getPublicParams(bits)).result,\n );\n }\n return (await worker.getPublicParams(bits)).result;\n }\n\n async getAclAddress(): Promise<Address> {\n const chainId = await this.#config.getChainId();\n const config = Object.assign({}, DefaultConfigs[chainId], this.#config.transports[chainId]);\n if (!config.aclContractAddress) {\n throw new ConfigurationError(`No ACL address configured for chain ${chainId}`);\n }\n return config.aclContractAddress as Address;\n }\n}\n","import { type Address, getAddress, type Hex, hexToBigInt } from \"viem\";\nimport {\n allowanceContract,\n approveContract,\n balanceOfContract,\n confidentialTransferContract,\n confidentialTransferFromContract,\n delegateForUserDecryptionContract,\n finalizeUnwrapContract,\n isOperatorContract,\n MAX_UINT64,\n revokeDelegationContract,\n setOperatorContract,\n underlyingContract,\n unwrapContract,\n unwrapFromBalanceContract,\n wrapContract,\n wrapETHContract,\n} from \"../contracts\";\nimport { findUnwrapRequested } from \"../events/onchain-events\";\nimport { ZamaSDKEvents } from \"../events/sdk-events\";\nimport type { Handle } from \"../relayer/relayer-sdk.types\";\nimport { toError } from \"../utils\";\nimport { loadCachedBalance } from \"./balance-cache\";\nimport {\n ApprovalFailedError,\n BalanceCheckUnavailableError,\n DecryptionFailedError,\n ERC20ReadFailedError,\n DelegationDelegateEqualsContractError,\n DelegationExpirationTooSoonError,\n DelegationExpiryUnchangedError,\n DelegationNotFoundError,\n DelegationSelfNotAllowedError,\n EncryptionFailedError,\n InsufficientConfidentialBalanceError,\n InsufficientERC20BalanceError,\n TransactionRevertedError,\n ZamaError,\n matchAclRevert,\n} from \"../errors\";\nimport { ReadonlyToken, type ReadonlyTokenConfig } from \"./readonly-token\";\nimport type {\n ShieldCallbacks,\n ShieldOptions,\n TransactionResult,\n TransferCallbacks,\n TransferOptions,\n UnshieldCallbacks,\n UnshieldOptions,\n} from \"../types\";\n\n/**\n * ERC-20-like interface for a single confidential token.\n * Hides all FHE complexity (encryption, decryption, EIP-712 signing)\n * behind familiar methods.\n *\n * Extends ReadonlyToken with write operations\n * (transfer, shield, unshield).\n */\nexport interface TokenConfig extends ReadonlyTokenConfig {\n /** Override the wrapper address. Defaults to `address` (the token IS the wrapper). */\n wrapper?: Address;\n}\n\nexport class Token extends ReadonlyToken {\n static readonly ZERO_ADDRESS: Address = \"0x0000000000000000000000000000000000000000\";\n\n readonly wrapper: Address;\n #underlying: Address | undefined;\n #underlyingPromise: Promise<Address> | null = null;\n\n constructor(config: TokenConfig) {\n super(config);\n this.wrapper = config.wrapper ? getAddress(config.wrapper) : this.address;\n }\n\n async #getUnderlying(): Promise<Address> {\n if (this.#underlying !== undefined) {\n return this.#underlying;\n }\n if (!this.#underlyingPromise) {\n this.#underlyingPromise = this.signer\n .readContract(underlyingContract(this.wrapper))\n .then((v) => {\n this.#underlying = v;\n this.#underlyingPromise = null;\n return v;\n })\n .catch((error) => {\n this.#underlyingPromise = null;\n throw error;\n });\n }\n return this.#underlyingPromise;\n }\n\n // WRITE OPERATIONS\n\n /**\n * Confidential transfer. Encrypts the amount via FHE, then calls the contract.\n * Returns the transaction hash.\n *\n * By default, the SDK validates the confidential balance before submitting.\n * If a cached plaintext balance exists it is used; otherwise, if credentials\n * are cached, it decrypts on the fly. Set `skipBalanceCheck: true` to bypass\n * this validation (e.g. for smart wallets).\n *\n * @param to - Recipient address.\n * @param amount - Plaintext amount to transfer (encrypted automatically via FHE).\n * @param options - Optional: `skipBalanceCheck` (default `false`).\n * @returns The transaction hash and mined receipt.\n * @throws {@link InsufficientConfidentialBalanceError} if the confidential balance is less than `amount`.\n * @throws {@link BalanceCheckUnavailableError} if balance validation is required but decryption is not possible (no cached credentials).\n * @throws {@link EncryptionFailedError} if FHE encryption fails.\n * @throws {@link TransactionRevertedError} if the on-chain transfer reverts.\n *\n * @example\n * ```ts\n * const txHash = await token.confidentialTransfer(\"0xRecipient\", 1000n);\n * // Smart wallet (skip balance check):\n * const txHash = await token.confidentialTransfer(\"0xRecipient\", 1000n, { skipBalanceCheck: true });\n * ```\n */\n async confidentialTransfer(\n to: Address,\n amount: bigint,\n options?: TransferOptions,\n ): Promise<TransactionResult> {\n const { skipBalanceCheck = false, onEncryptComplete, onTransferSubmitted } = options ?? {};\n\n const normalizedTo = getAddress(to);\n\n if (!skipBalanceCheck) {\n await this.#assertConfidentialBalance(amount);\n }\n\n let handles: Uint8Array[];\n let inputProof: Uint8Array;\n const t0 = Date.now();\n try {\n this.emit({ type: ZamaSDKEvents.EncryptStart });\n ({ handles, inputProof } = await this.relayer.encrypt({\n values: [{ value: amount, type: \"euint64\" }],\n contractAddress: this.address,\n userAddress: await this.signer.getAddress(),\n }));\n this.emit({\n type: ZamaSDKEvents.EncryptEnd,\n durationMs: Date.now() - t0,\n });\n safeCallback(() => onEncryptComplete?.());\n } catch (error) {\n this.emit({\n type: ZamaSDKEvents.EncryptError,\n error: toError(error),\n durationMs: Date.now() - t0,\n });\n if (error instanceof ZamaError) {\n throw error;\n }\n throw new EncryptionFailedError(\"Failed to encrypt transfer amount\", {\n cause: error,\n });\n }\n\n if (handles.length === 0) {\n throw new EncryptionFailedError(\"Encryption returned no handles\");\n }\n\n try {\n const txHash = await this.signer.writeContract(\n confidentialTransferContract(this.address, normalizedTo, handles[0]!, inputProof),\n );\n this.emit({ type: ZamaSDKEvents.TransferSubmitted, txHash });\n safeCallback(() => onTransferSubmitted?.(txHash));\n const receipt = await this.signer.waitForTransactionReceipt(txHash);\n return { txHash, receipt };\n } catch (error) {\n this.emit({\n type: ZamaSDKEvents.TransactionError,\n operation: \"transfer\",\n error: toError(error),\n });\n if (error instanceof ZamaError) {\n throw error;\n }\n throw new TransactionRevertedError(\"Transfer transaction failed\", {\n cause: error,\n });\n }\n }\n\n /**\n * Operator encrypted transfer on behalf of another address.\n * The caller must be an approved operator for `from`.\n *\n * @param from - The address to transfer from (caller must be an approved operator).\n * @param to - Recipient address.\n * @param amount - Plaintext amount to transfer (encrypted automatically via FHE).\n * @returns The transaction hash and mined receipt.\n * @throws {@link EncryptionFailedError} if FHE encryption fails.\n * @throws {@link TransactionRevertedError} if the on-chain transfer reverts.\n *\n * @example\n * ```ts\n * const txHash = await token.confidentialTransferFrom(\"0xFrom\", \"0xTo\", 500n);\n * ```\n */\n async confidentialTransferFrom(\n from: Address,\n to: Address,\n amount: bigint,\n callbacks?: TransferCallbacks,\n ): Promise<TransactionResult> {\n const normalizedFrom = getAddress(from);\n const normalizedTo = getAddress(to);\n\n let handles: Uint8Array[];\n let inputProof: Uint8Array;\n const t0 = Date.now();\n try {\n this.emit({ type: ZamaSDKEvents.EncryptStart });\n ({ handles, inputProof } = await this.relayer.encrypt({\n values: [{ value: amount, type: \"euint64\" }],\n contractAddress: this.address,\n userAddress: normalizedFrom,\n }));\n this.emit({\n type: ZamaSDKEvents.EncryptEnd,\n durationMs: Date.now() - t0,\n });\n safeCallback(() => callbacks?.onEncryptComplete?.());\n } catch (error) {\n this.emit({\n type: ZamaSDKEvents.EncryptError,\n error: toError(error),\n durationMs: Date.now() - t0,\n });\n if (error instanceof ZamaError) {\n throw error;\n }\n throw new EncryptionFailedError(\"Failed to encrypt transferFrom amount\", {\n cause: error,\n });\n }\n\n if (handles.length === 0) {\n throw new EncryptionFailedError(\"Encryption returned no handles\");\n }\n\n try {\n const txHash = await this.signer.writeContract(\n confidentialTransferFromContract(\n this.address,\n normalizedFrom,\n normalizedTo,\n handles[0]!,\n inputProof,\n ),\n );\n this.emit({ type: ZamaSDKEvents.TransferFromSubmitted, txHash });\n safeCallback(() => callbacks?.onTransferSubmitted?.(txHash));\n const receipt = await this.signer.waitForTransactionReceipt(txHash);\n return { txHash, receipt };\n } catch (error) {\n this.emit({\n type: ZamaSDKEvents.TransactionError,\n operation: \"transferFrom\",\n error: toError(error),\n });\n if (error instanceof ZamaError) {\n throw error;\n }\n throw new TransactionRevertedError(\"TransferFrom transaction failed\", {\n cause: error,\n });\n }\n }\n\n /**\n * Set operator approval for the confidential token.\n * Defaults to 1 hour from now if `until` is not specified.\n *\n * @param spender - The address to approve as an operator.\n * @param until - Optional Unix timestamp for approval expiry. Defaults to now + 1 hour.\n * @returns The transaction hash and mined receipt.\n * @throws {@link ApprovalFailedError} if the approval transaction fails.\n *\n * @example\n * ```ts\n * const txHash = await token.approve(\"0xSpender\");\n * ```\n */\n async approve(spender: Address, until?: number): Promise<TransactionResult> {\n const normalizedSpender = getAddress(spender);\n try {\n const txHash = await this.signer.writeContract(\n setOperatorContract(this.address, normalizedSpender, until),\n );\n this.emit({ type: ZamaSDKEvents.ApproveSubmitted, txHash });\n const receipt = await this.signer.waitForTransactionReceipt(txHash);\n return { txHash, receipt };\n } catch (error) {\n this.emit({\n type: ZamaSDKEvents.TransactionError,\n operation: \"approve\",\n error: toError(error),\n });\n if (error instanceof ZamaError) {\n throw error;\n }\n throw new ApprovalFailedError(\"Operator approval failed\", {\n cause: error,\n });\n }\n }\n\n /**\n * Check if a spender is an approved operator for a given holder.\n *\n * @param spender - The address to check operator approval for.\n * @param holder - The token holder address. Defaults to the connected wallet.\n * @returns `true` if the spender is an approved operator for the holder.\n *\n * @example\n * ```ts\n * if (await token.isApproved(\"0xSpender\")) {\n * // spender can call transferFrom on behalf of connected wallet\n * }\n * // or check for a specific holder:\n * if (await token.isApproved(\"0xSpender\", \"0xHolder\")) { ... }\n * ```\n */\n async isApproved(spender: Address, holder?: Address): Promise<boolean> {\n const normalizedSpender = getAddress(spender);\n const resolvedHolder = holder ? getAddress(holder) : await this.signer.getAddress();\n return this.signer.readContract(\n isOperatorContract(this.address, resolvedHolder, normalizedSpender),\n );\n }\n\n /**\n * Shield public ERC-20 tokens into confidential tokens.\n * Handles ERC-20 approval automatically based on `approvalStrategy`\n * (`\"exact\"` by default, `\"max\"` for unlimited approval, `\"skip\"` to opt out).\n *\n * The ERC-20 balance is validated before submitting (public read, no signing\n * required). For native ETH shields (`underlying === address(0)`), the ERC-20\n * check is skipped — the chain validates ETH balance natively.\n *\n * @param amount - The plaintext amount to shield.\n * @param options - Optional configuration: `approvalStrategy` (`\"exact\"` | `\"max\"` | `\"skip\"`, default `\"exact\"`), `fees` (extra ETH for native wrappers).\n * @returns The transaction hash and mined receipt.\n * @throws {@link InsufficientERC20BalanceError} if the ERC-20 balance is less than `amount`.\n * @throws {@link ApprovalFailedError} if the ERC-20 approval step fails.\n * @throws {@link TransactionRevertedError} if the shield transaction reverts.\n *\n * @example\n * ```ts\n * const txHash = await token.shield(1000n);\n * // or with exact approval:\n * const txHash = await token.shield(1000n, { approvalStrategy: \"exact\" });\n * ```\n */\n async shield(amount: bigint, options?: ShieldOptions): Promise<TransactionResult> {\n const underlying = await this.#getUnderlying();\n\n if (underlying === Token.ZERO_ADDRESS) {\n return this.shieldETH(amount, amount + (options?.fees ?? 0n));\n }\n\n // ERC-20 balance check always runs (public read, no signing needed, works for all wallet types)\n let erc20Balance: bigint;\n try {\n const userAddress = await this.signer.getAddress();\n erc20Balance = await this.signer.readContract(balanceOfContract(underlying, userAddress));\n } catch (error) {\n if (error instanceof ZamaError) {\n throw error;\n }\n throw new ERC20ReadFailedError(\n `Could not read ERC-20 balance for shield validation (token: ${underlying})`,\n { cause: toError(error) },\n );\n }\n if (erc20Balance < amount) {\n throw new InsufficientERC20BalanceError(\n `Insufficient ERC-20 balance: requested ${amount}, available ${erc20Balance} (token: ${underlying})`,\n { requested: amount, available: erc20Balance, token: underlying },\n );\n }\n\n const strategy = options?.approvalStrategy ?? \"exact\";\n if (strategy !== \"skip\") {\n await this.#ensureAllowance(amount, strategy === \"max\", options);\n }\n\n try {\n const recipient = options?.to ? getAddress(options.to) : await this.signer.getAddress();\n const txHash = await this.signer.writeContract(wrapContract(this.wrapper, recipient, amount));\n this.emit({ type: ZamaSDKEvents.ShieldSubmitted, txHash });\n safeCallback(() => options?.onShieldSubmitted?.(txHash));\n const receipt = await this.signer.waitForTransactionReceipt(txHash);\n return { txHash, receipt };\n } catch (error) {\n this.emit({\n type: ZamaSDKEvents.TransactionError,\n operation: \"shield\",\n error: toError(error),\n });\n if (error instanceof ZamaError) {\n throw error;\n }\n throw new TransactionRevertedError(\"Shield transaction failed\", {\n cause: error,\n });\n }\n }\n\n /**\n * Shield native ETH into confidential tokens. `value` defaults to `amount`.\n *\n * @param amount - The amount of ETH to shield (in wei).\n * @param value - Optional ETH value to send. Defaults to `amount`.\n * @returns The transaction hash and mined receipt.\n * @throws {@link TransactionRevertedError} if the shield transaction reverts.\n *\n * @example\n * ```ts\n * const txHash = await token.shieldETH(1000000000000000000n); // 1 ETH\n * ```\n */\n async shieldETH(amount: bigint, value?: bigint): Promise<TransactionResult> {\n try {\n const userAddress = await this.signer.getAddress();\n const txHash = await this.signer.writeContract(\n wrapETHContract(this.wrapper, userAddress, amount, value ?? amount),\n );\n this.emit({ type: ZamaSDKEvents.ShieldSubmitted, txHash });\n const receipt = await this.signer.waitForTransactionReceipt(txHash);\n return { txHash, receipt };\n } catch (error) {\n this.emit({\n type: ZamaSDKEvents.TransactionError,\n operation: \"shieldETH\",\n error: toError(error),\n });\n if (error instanceof ZamaError) {\n throw error;\n }\n throw new TransactionRevertedError(\"Shield ETH transaction failed\", {\n cause: error,\n });\n }\n }\n\n /**\n * Request an unwrap for a specific amount. Encrypts the amount first.\n * Call {@link finalizeUnwrap} after the request is processed on-chain.\n *\n * @param amount - The plaintext amount to unwrap (encrypted automatically).\n * @returns The transaction hash and mined receipt.\n * @throws {@link EncryptionFailedError} if FHE encryption fails.\n * @throws {@link TransactionRevertedError} if the unwrap transaction reverts.\n *\n * @example\n * ```ts\n * const txHash = await token.unwrap(500n);\n * ```\n */\n async unwrap(amount: bigint): Promise<TransactionResult> {\n const userAddress = await this.signer.getAddress();\n\n let handles: Uint8Array[];\n let inputProof: Uint8Array;\n const t0 = Date.now();\n try {\n this.emit({ type: ZamaSDKEvents.EncryptStart });\n ({ handles, inputProof } = await this.relayer.encrypt({\n values: [{ value: amount, type: \"euint64\" }],\n contractAddress: this.wrapper,\n userAddress,\n }));\n this.emit({\n type: ZamaSDKEvents.EncryptEnd,\n durationMs: Date.now() - t0,\n });\n } catch (error) {\n this.emit({\n type: ZamaSDKEvents.EncryptError,\n error: toError(error),\n durationMs: Date.now() - t0,\n });\n if (error instanceof ZamaError) {\n throw error;\n }\n throw new EncryptionFailedError(\"Failed to encrypt unshield amount\", {\n cause: error,\n });\n }\n\n if (handles.length === 0) {\n throw new EncryptionFailedError(\"Encryption returned no handles\");\n }\n\n try {\n const txHash = await this.signer.writeContract(\n unwrapContract(this.address, userAddress, userAddress, handles[0]!, inputProof),\n );\n this.emit({ type: ZamaSDKEvents.UnwrapSubmitted, txHash });\n const receipt = await this.signer.waitForTransactionReceipt(txHash);\n return { txHash, receipt };\n } catch (error) {\n this.emit({\n type: ZamaSDKEvents.TransactionError,\n operation: \"unwrap\",\n error: toError(error),\n });\n if (error instanceof ZamaError) {\n throw error;\n }\n throw new TransactionRevertedError(\"Unshield transaction failed\", {\n cause: error,\n });\n }\n }\n\n /**\n * Request an unwrap for the entire confidential balance.\n * Uses the on-chain balance handle directly (no encryption needed).\n * Throws if the balance is zero.\n *\n * @returns The transaction hash and mined receipt.\n * @throws {@link DecryptionFailedError} if the balance is zero.\n * @throws {@link TransactionRevertedError} if the unwrap transaction reverts.\n *\n * @example\n * ```ts\n * const txHash = await token.unwrapAll();\n * ```\n */\n async unwrapAll(): Promise<TransactionResult> {\n const userAddress = await this.signer.getAddress();\n const handle = await this.readConfidentialBalanceOf(userAddress);\n\n if (this.isZeroHandle(handle)) {\n throw new DecryptionFailedError(\"Cannot unshield: balance is zero\");\n }\n\n try {\n const txHash = await this.signer.writeContract(\n unwrapFromBalanceContract(this.address, userAddress, userAddress, handle),\n );\n this.emit({ type: ZamaSDKEvents.UnwrapSubmitted, txHash });\n const receipt = await this.signer.waitForTransactionReceipt(txHash);\n return { txHash, receipt };\n } catch (error) {\n this.emit({\n type: ZamaSDKEvents.TransactionError,\n operation: \"unwrap\",\n error: toError(error),\n });\n if (error instanceof ZamaError) {\n throw error;\n }\n throw new TransactionRevertedError(\"Unshield-all transaction failed\", {\n cause: error,\n });\n }\n }\n\n /**\n * Unshield a specific amount and finalize in one call.\n * Orchestrates: unshield → wait for receipt → parse event → finalize.\n *\n * By default, the SDK validates the confidential balance before submitting.\n * Set `skipBalanceCheck: true` to bypass this validation (e.g. for smart wallets).\n *\n * @param amount - The plaintext amount to unshield.\n * @param options - Optional: `skipBalanceCheck` (default `false`), `callbacks`.\n * @returns The finalize transaction hash and mined receipt.\n * @throws {@link InsufficientConfidentialBalanceError} if the confidential balance is less than `amount`.\n * @throws {@link BalanceCheckUnavailableError} if balance validation is required but decryption is not possible.\n * @throws {@link EncryptionFailedError} if FHE encryption fails.\n * @throws {@link TransactionRevertedError} if any transaction in the flow reverts.\n *\n * @example\n * ```ts\n * const txHash = await token.unshield(500n);\n * // Smart wallet (skip balance check):\n * const txHash = await token.unshield(500n, { skipBalanceCheck: true });\n * ```\n */\n async unshield(amount: bigint, options?: UnshieldOptions): Promise<TransactionResult> {\n const {\n skipBalanceCheck = false,\n onUnwrapSubmitted,\n onFinalizing,\n onFinalizeSubmitted,\n } = options ?? {};\n\n if (!skipBalanceCheck) {\n await this.#assertConfidentialBalance(amount);\n }\n\n const callbacks: UnshieldCallbacks = {\n onFinalizing,\n onFinalizeSubmitted,\n };\n const operationId = crypto.randomUUID();\n const unwrapResult = await this.unwrap(amount);\n safeCallback(() => onUnwrapSubmitted?.(unwrapResult.txHash));\n return this.#waitAndFinalizeUnshield(unwrapResult.txHash, operationId, callbacks);\n }\n\n /**\n * Unshield the entire balance and finalize in one call.\n * Orchestrates: unshieldAll → wait for receipt → parse event → finalize.\n *\n * @param callbacks - Optional progress callbacks for each phase.\n * @returns The finalize transaction hash and mined receipt.\n * @throws {@link DecryptionFailedError} if the balance is zero.\n * @throws {@link TransactionRevertedError} if any transaction in the flow reverts.\n *\n * @example\n * ```ts\n * const txHash = await token.unshieldAll();\n * ```\n */\n async unshieldAll(callbacks?: UnshieldCallbacks): Promise<TransactionResult> {\n const operationId = crypto.randomUUID();\n const unwrapResult = await this.unwrapAll();\n safeCallback(() => callbacks?.onUnwrapSubmitted?.(unwrapResult.txHash));\n return this.#waitAndFinalizeUnshield(unwrapResult.txHash, operationId, callbacks);\n }\n\n /**\n * Resume an in-progress unshield from an existing unwrap tx hash.\n * Useful when the user already submitted the unwrap but the finalize step\n * was interrupted (e.g. page reload, network error).\n *\n * @param unwrapTxHash - The transaction hash of the previously submitted unwrap.\n * @param callbacks - Optional progress callbacks.\n * @returns The finalize transaction hash and mined receipt.\n * @throws {@link TransactionRevertedError} if finalization fails.\n *\n * @example\n * ```ts\n * const txHash = await token.resumeUnshield(previousUnwrapTxHash);\n * ```\n */\n async resumeUnshield(\n unwrapTxHash: Hex,\n callbacks?: UnshieldCallbacks,\n ): Promise<TransactionResult> {\n return this.#waitAndFinalizeUnshield(unwrapTxHash, crypto.randomUUID(), callbacks);\n }\n\n /**\n * Complete an unwrap by providing the public decryption proof.\n * Call this after an unshield request has been processed on-chain.\n *\n * @param burnAmountHandle - The encrypted amount handle from the `UnwrapRequested` event.\n * @returns The transaction hash and mined receipt.\n * @throws {@link DecryptionFailedError} if public decryption fails.\n * @throws {@link TransactionRevertedError} if the finalize transaction reverts.\n *\n * @example\n * ```ts\n * const event = findUnwrapRequested(receipt.logs);\n * const txHash = await token.finalizeUnwrap(event.encryptedAmount);\n * ```\n */\n async finalizeUnwrap(burnAmountHandle: Handle): Promise<TransactionResult> {\n let clearValue: bigint;\n let decryptionProof: Hex;\n\n const t0 = Date.now();\n try {\n this.emit({ type: ZamaSDKEvents.DecryptStart });\n const result = await this.relayer.publicDecrypt([burnAmountHandle]);\n this.emit({\n type: ZamaSDKEvents.DecryptEnd,\n durationMs: Date.now() - t0,\n });\n decryptionProof = result.decryptionProof;\n try {\n clearValue = hexToBigInt(result.abiEncodedClearValues);\n } catch (error) {\n throw new DecryptionFailedError(\n `Cannot parse decrypted value: ${result.abiEncodedClearValues}`,\n { cause: error },\n );\n }\n } catch (error) {\n this.emit({\n type: ZamaSDKEvents.DecryptError,\n error: toError(error),\n durationMs: Date.now() - t0,\n });\n if (error instanceof ZamaError) {\n throw error;\n }\n throw new DecryptionFailedError(\"Failed to finalize unshield\", {\n cause: error,\n });\n }\n\n try {\n const txHash = await this.signer.writeContract(\n finalizeUnwrapContract(this.wrapper, burnAmountHandle, clearValue, decryptionProof),\n );\n this.emit({ type: ZamaSDKEvents.FinalizeUnwrapSubmitted, txHash });\n const receipt = await this.signer.waitForTransactionReceipt(txHash);\n return { txHash, receipt };\n } catch (error) {\n this.emit({\n type: ZamaSDKEvents.TransactionError,\n operation: \"finalizeUnwrap\",\n error: toError(error),\n });\n if (error instanceof ZamaError) {\n throw error;\n }\n throw new TransactionRevertedError(\"Failed to finalize unshield\", {\n cause: error,\n });\n }\n }\n\n /**\n * Approve this token contract to spend the underlying ERC-20.\n * Defaults to max uint256. Resets to zero first if there's an existing\n * non-zero allowance (required by tokens like USDT).\n *\n * @param amount - Optional approval amount. Defaults to max uint256.\n * @returns The transaction hash and mined receipt.\n * @throws {@link ApprovalFailedError} if the approval transaction fails.\n *\n * @example\n * ```ts\n * await token.approveUnderlying(); // max approval\n * await token.approveUnderlying(1000n); // exact amount\n * ```\n */\n async approveUnderlying(amount?: bigint): Promise<TransactionResult> {\n const underlying = await this.#getUnderlying();\n\n const approvalAmount = amount ?? 2n ** 256n - 1n;\n\n try {\n if (approvalAmount > 0n) {\n const userAddress = await this.signer.getAddress();\n const currentAllowance = await this.signer.readContract(\n allowanceContract(underlying, userAddress, this.wrapper),\n );\n\n if (currentAllowance > 0n) {\n await this.signer.writeContract(approveContract(underlying, this.wrapper, 0n));\n }\n }\n\n const txHash = await this.signer.writeContract(\n approveContract(underlying, this.wrapper, approvalAmount),\n );\n this.emit({ type: ZamaSDKEvents.ApproveUnderlyingSubmitted, txHash });\n const receipt = await this.signer.waitForTransactionReceipt(txHash);\n return { txHash, receipt };\n } catch (error) {\n this.emit({\n type: ZamaSDKEvents.TransactionError,\n operation: \"approveUnderlying\",\n error: toError(error),\n });\n if (error instanceof ZamaError) {\n throw error;\n }\n throw new ApprovalFailedError(\"ERC-20 approval failed\", {\n cause: error,\n });\n }\n }\n\n // DELEGATION OPERATIONS\n\n /**\n * Delegate decryption rights for this token to another address.\n * Calls `ACL.delegateForUserDecryption()` on-chain.\n *\n * **Important:** After the transaction is mined, allow **1–2 minutes** before\n * calling {@link ReadonlyToken.decryptBalanceAs | decryptBalanceAs}. The delegation\n * is recorded on L1 immediately, but the gateway (on Arbitrum) must sync the\n * ACL state via cross-chain event propagation. Attempting delegated decryption\n * before propagation completes will throw a\n * {@link DelegationNotPropagatedError}.\n *\n * @param delegateAddress - Address to delegate decryption rights to.\n * @param expirationDate - Optional expiration date (defaults to permanent delegation via `uint64.max`).\n * @returns The transaction hash and mined receipt.\n * @throws {@link TransactionRevertedError} if the delegation transaction reverts.\n */\n async delegateDecryption({\n delegateAddress,\n expirationDate,\n }: {\n delegateAddress: Address;\n expirationDate?: Date;\n }): Promise<TransactionResult> {\n if (expirationDate && expirationDate.getTime() < Date.now() + 3600_000) {\n throw new DelegationExpirationTooSoonError(\n \"Expiration date must be at least 1 hour in the future\",\n );\n }\n\n const normalizedDelegate = getAddress(delegateAddress);\n\n // Pre-flight: delegate cannot be the connected wallet (SenderCannotBeDelegate)\n const signerAddress = await this.signer.getAddress();\n if (normalizedDelegate === getAddress(signerAddress)) {\n throw new DelegationSelfNotAllowedError(\n \"Cannot delegate to yourself (delegate === msg.sender).\",\n );\n }\n\n // Pre-flight: delegate cannot be the contract address (DelegateCannotBeContractAddress)\n if (normalizedDelegate === this.address) {\n throw new DelegationDelegateEqualsContractError(\n `Delegate address cannot be the same as the contract address (${this.address}).`,\n );\n }\n\n const acl = await this.getAclAddress();\n // uint64 max → no practical expiry\n const expDate = expirationDate\n ? BigInt(Math.floor(expirationDate.getTime() / 1000))\n : MAX_UINT64;\n\n // Pre-flight with RPC: new expiry must differ from current (ExpirationDateAlreadySetToSameValue)\n const currentExpiry = await this.getDelegationExpiry({\n delegatorAddress: signerAddress,\n delegateAddress: normalizedDelegate,\n });\n if (currentExpiry === expDate) {\n throw new DelegationExpiryUnchangedError(\n `The new expiration date (${expDate}) is the same as the current one. No on-chain change needed.`,\n );\n }\n\n try {\n const txHash = await this.signer.writeContract(\n delegateForUserDecryptionContract(acl, normalizedDelegate, this.address, expDate),\n );\n this.emit({ type: ZamaSDKEvents.DelegationSubmitted, txHash });\n const receipt = await this.signer.waitForTransactionReceipt(txHash);\n return { txHash, receipt };\n } catch (error) {\n this.emit({\n type: ZamaSDKEvents.TransactionError,\n operation: \"delegateDecryption\",\n error: toError(error),\n });\n if (error instanceof ZamaError) {\n throw error;\n }\n const mapped = matchAclRevert(error);\n if (mapped) {\n throw mapped;\n }\n throw new TransactionRevertedError(\"Delegation transaction failed\", {\n cause: error,\n });\n }\n }\n\n /**\n * Revoke decryption delegation for this token.\n * Calls `ACL.revokeDelegationForUserDecryption()` on-chain.\n *\n * @param delegateAddress - Address to revoke delegation from.\n * @returns The transaction hash and mined receipt.\n * @throws {@link TransactionRevertedError} if the revocation transaction reverts.\n */\n async revokeDelegation({\n delegateAddress,\n }: {\n delegateAddress: Address;\n }): Promise<TransactionResult> {\n const normalizedDelegate = getAddress(delegateAddress);\n const signerAddress = await this.signer.getAddress();\n const acl = await this.getAclAddress();\n\n // Pre-flight: reject if never delegated (expiry === 0).\n // Expired delegations (non-zero expiry in the past) are allowed through —\n // the ACL contract accepts revocation of expired delegations.\n const currentExpiry = await this.getDelegationExpiry({\n delegatorAddress: signerAddress,\n delegateAddress: normalizedDelegate,\n });\n if (currentExpiry === 0n) {\n throw new DelegationNotFoundError(\n `No active delegation found for delegate ${normalizedDelegate} on contract ${this.address}.`,\n );\n }\n\n try {\n const txHash = await this.signer.writeContract(\n revokeDelegationContract(acl, normalizedDelegate, this.address),\n );\n this.emit({ type: ZamaSDKEvents.RevokeDelegationSubmitted, txHash });\n const receipt = await this.signer.waitForTransactionReceipt(txHash);\n return { txHash, receipt };\n } catch (error) {\n this.emit({\n type: ZamaSDKEvents.TransactionError,\n operation: \"revokeDelegation\",\n error: toError(error),\n });\n if (error instanceof ZamaError) {\n throw error;\n }\n const mapped = matchAclRevert(error);\n if (mapped) {\n throw mapped;\n }\n throw new TransactionRevertedError(\"Revoke delegation transaction failed\", {\n cause: error,\n });\n }\n }\n\n // BATCH DELEGATION\n\n /**\n * Delegate decryption rights across multiple tokens in parallel.\n * Returns a per-token result map with partial success semantics.\n *\n * @param tokens - Array of Token instances to delegate on.\n * @param delegateAddress - Address to delegate decryption rights to.\n * @param expirationDate - Optional expiration date.\n * @returns Map from token address to TransactionResult or ZamaError.\n */\n static async batchDelegateDecryption({\n tokens,\n delegateAddress,\n expirationDate,\n }: {\n tokens: Token[];\n delegateAddress: Address;\n expirationDate?: Date;\n }): Promise<Map<Address, TransactionResult | ZamaError>> {\n return Token.#batchDelegationOp(\n tokens,\n (t) => t.delegateDecryption({ delegateAddress, expirationDate }),\n \"Delegation failed\",\n );\n }\n\n /**\n * Revoke delegation across multiple tokens in parallel.\n * Returns a per-token result map with partial success semantics.\n *\n * @param tokens - Array of Token instances to revoke delegation on.\n * @param delegateAddress - Address to revoke delegation from.\n * @returns Map from token address to TransactionResult or ZamaError.\n */\n static async batchRevokeDelegation({\n tokens,\n delegateAddress,\n }: {\n tokens: Token[];\n delegateAddress: Address;\n }): Promise<Map<Address, TransactionResult | ZamaError>> {\n return Token.#batchDelegationOp(\n tokens,\n (t) => t.revokeDelegation({ delegateAddress }),\n \"Revoke delegation failed\",\n );\n }\n\n static async #batchDelegationOp(\n tokens: Token[],\n op: (token: Token) => Promise<TransactionResult>,\n errorMessage: string,\n ): Promise<Map<Address, TransactionResult | ZamaError>> {\n const results = new Map<Address, TransactionResult | ZamaError>();\n // Run sequentially: parallel writeContract calls from the same signer\n // cause nonce contention. The value of the batch API is partial-success\n // semantics (per-token results without throwing), not parallelism.\n for (let i = 0; i < tokens.length; i++) {\n try {\n results.set(tokens[i]!.address, await op(tokens[i]!));\n } catch (error) {\n if (error instanceof ZamaError) {\n results.set(tokens[i]!.address, error);\n } else {\n results.set(\n tokens[i]!.address,\n new TransactionRevertedError(errorMessage, {\n cause: error,\n }),\n );\n }\n }\n }\n return results;\n }\n\n // PRIVATE HELPERS\n\n /**\n * Pre-flight check: decrypt the confidential balance and compare against the\n * requested amount. If credentials are cached the decrypt happens silently;\n * if not, throws {@link BalanceCheckUnavailableError} instead of triggering\n * a surprise EIP-712 popup.\n */\n async #assertConfidentialBalance(amount: bigint): Promise<void> {\n // Zero-amount operations trivially satisfy the balance constraint.\n if (amount === 0n) {\n return;\n }\n\n let userAddress: Address;\n let handle: Handle;\n try {\n userAddress = await this.signer.getAddress();\n handle = await this.readConfidentialBalanceOf(userAddress);\n } catch (error) {\n if (error instanceof ZamaError) {\n throw error;\n }\n throw new BalanceCheckUnavailableError(\n `Could not read confidential balance handle (token: ${this.address})`,\n { cause: toError(error) },\n );\n }\n\n if (this.isZeroHandle(handle)) {\n throw new InsufficientConfidentialBalanceError(\n `Insufficient confidential balance: requested ${amount}, available 0 (token: ${this.address})`,\n { requested: amount, available: 0n, token: this.address },\n );\n }\n\n // Check the persistent plaintext cache first — if the balance was decrypted\n // in a previous session, we can validate without credentials or a new decrypt.\n const cached = await loadCachedBalance({\n storage: this.storage,\n tokenAddress: this.address,\n owner: userAddress,\n handle,\n });\n if (cached !== null) {\n if (cached < amount) {\n throw new InsufficientConfidentialBalanceError(\n `Insufficient confidential balance: requested ${amount}, available ${cached} (token: ${this.address})`,\n { requested: amount, available: cached, token: this.address },\n );\n }\n return;\n }\n\n // Cache miss — only attempt decryption when credentials are already cached.\n // This avoids triggering an unexpected EIP-712 signing popup during\n // a transfer/unshield flow (respects the explicit-action pattern from SDK-42).\n //\n // Note: isAllowed() is a wallet-scoped session check. If credentials exist\n // but don't yet cover this token's contract address, decryptBalance() may\n // still trigger a signing prompt for contract extension. This is acceptable:\n // it only happens when the user interacts with a new token for the first\n // time while having an active session — a signing prompt is expected there.\n let hasCredentials: boolean;\n try {\n hasCredentials = await this.isAllowed();\n } catch (error) {\n if (error instanceof ZamaError) {\n throw error;\n }\n throw new BalanceCheckUnavailableError(\n `Could not check credential status for balance validation (token: ${this.address})`,\n { cause: error },\n );\n }\n if (!hasCredentials) {\n throw new BalanceCheckUnavailableError(\n `Cannot validate confidential balance: no cached credentials. ` +\n `Call allow() first or use skipBalanceCheck: true for smart wallets (token: ${this.address})`,\n );\n }\n\n let balance: bigint;\n try {\n balance = await this.decryptBalance(handle, userAddress);\n } catch (error) {\n if (error instanceof ZamaError) {\n throw error;\n }\n throw new BalanceCheckUnavailableError(\n `Balance validation failed: could not decrypt confidential balance (token: ${this.address})`,\n { cause: error },\n );\n }\n\n if (balance < amount) {\n throw new InsufficientConfidentialBalanceError(\n `Insufficient confidential balance: requested ${amount}, available ${balance} (token: ${this.address})`,\n { requested: amount, available: balance, token: this.address },\n );\n }\n }\n\n async #waitAndFinalizeUnshield(\n unshieldHash: Hex,\n operationId: string,\n callbacks: UnshieldCallbacks | undefined,\n ): Promise<TransactionResult> {\n this.emit({\n type: ZamaSDKEvents.UnshieldPhase1Submitted,\n txHash: unshieldHash,\n operationId,\n });\n let receipt;\n try {\n receipt = await this.signer.waitForTransactionReceipt(unshieldHash);\n } catch (error) {\n if (error instanceof ZamaError) {\n throw error;\n }\n throw new TransactionRevertedError(\"Failed to get unshield receipt\", {\n cause: error,\n });\n }\n const event = findUnwrapRequested(receipt.logs);\n if (!event) {\n throw new TransactionRevertedError(\"No UnwrapRequested event found in unshield receipt\");\n }\n this.emit({ type: ZamaSDKEvents.UnshieldPhase2Started, operationId });\n safeCallback(() => callbacks?.onFinalizing?.());\n const finalizeResult = await this.finalizeUnwrap(event.encryptedAmount);\n this.emit({\n type: ZamaSDKEvents.UnshieldPhase2Submitted,\n txHash: finalizeResult.txHash,\n operationId,\n });\n safeCallback(() => callbacks?.onFinalizeSubmitted?.(finalizeResult.txHash));\n return finalizeResult;\n }\n\n async #ensureAllowance(\n amount: bigint,\n maxApproval: boolean,\n callbacks?: ShieldCallbacks,\n ): Promise<void> {\n const underlying = await this.#getUnderlying();\n\n const userAddress = await this.signer.getAddress();\n const allowance = await this.signer.readContract(\n allowanceContract(underlying, userAddress, this.wrapper),\n );\n\n if (allowance >= amount) {\n return;\n }\n\n try {\n // Reset to zero first when there's an existing non-zero allowance.\n // Required by non-standard tokens like USDT, and also mitigates the\n // ERC-20 approve race condition for all tokens.\n if (allowance > 0n) {\n await this.signer.writeContract(approveContract(underlying, this.wrapper, 0n));\n }\n\n const approvalAmount = maxApproval ? 2n ** 256n - 1n : amount;\n\n const txHash = await this.signer.writeContract(\n approveContract(underlying, this.wrapper, approvalAmount),\n );\n this.emit({ type: ZamaSDKEvents.ApproveUnderlyingSubmitted, txHash });\n safeCallback(() => callbacks?.onApprovalSubmitted?.(txHash));\n } catch (error) {\n if (error instanceof ZamaError) {\n throw error;\n }\n throw new ApprovalFailedError(\"ERC-20 approval failed\", {\n cause: error,\n });\n }\n }\n}\n\n/**\n * Invoke a callback inside a try/catch so a throwing listener\n * can never break the unshield flow (unwrap already on-chain).\n */\nfunction safeCallback(fn: () => void): void {\n try {\n fn();\n } catch (error) {\n console.warn(\"[zama-sdk] Callback threw:\", error);\n }\n}\n","import { type Address, getAddress } from \"viem\";\nimport type { TokenWrapperPairWithMetadata, PaginatedResult, TokenWrapperPair } from \"./contracts\";\nimport {\n decimalsContract,\n erc20TotalSupplyContract,\n getConfidentialTokenAddressContract,\n getTokenAddressContract,\n getTokenPairContract,\n getTokenPairsContract,\n getTokenPairsLengthContract,\n getTokenPairsSliceContract,\n isConfidentialTokenValidContract,\n nameContract,\n symbolContract,\n} from \"./contracts\";\nimport { ConfigurationError } from \"./errors/relayer\";\nimport { hoodiCleartextConfig } from \"./relayer/cleartext\";\nimport { MainnetConfig, SepoliaConfig } from \"./relayer/relayer-utils\";\nimport type { GenericSigner } from \"./types/signer\";\n\n/**\n * Default wrappers registry addresses for known chains.\n * Only includes chains where a registry is deployed (excludes Hardhat).\n */\nexport const DefaultRegistryAddresses: Record<number, Address> = {\n [MainnetConfig.chainId]: MainnetConfig.registryAddress,\n [SepoliaConfig.chainId]: SepoliaConfig.registryAddress,\n [hoodiCleartextConfig.chainId]: hoodiCleartextConfig.registryAddress,\n};\n\n/** Default page size for {@link WrappersRegistry.listPairs}. */\nconst DEFAULT_PAGE_SIZE = 100;\n\n/** Default registry TTL in seconds (24 hours). */\nconst DEFAULT_REGISTRY_TTL = 86400;\n\n/** Configuration for {@link WrappersRegistry}. */\nexport interface WrappersRegistryConfig {\n /** The connected wallet signer. Must satisfy the full `GenericSigner` interface. */\n signer: GenericSigner;\n /**\n * Per-chain registry address overrides, merged on top of\n * {@link DefaultRegistryAddresses}. Use this to supply a registry\n * address for custom or local chains (e.g. Hardhat).\n *\n * @example\n * ```ts\n * new WrappersRegistry({\n * signer,\n * registryAddresses: { [31337]: \"0xYourHardhatRegistry\" },\n * });\n * ```\n */\n registryAddresses?: Record<number, Address>;\n /**\n * How long cached registry results remain valid, in seconds.\n * Default: `86400` (24 hours).\n */\n registryTTL?: number;\n}\n\n/** Options for {@link WrappersRegistry.listPairs}. */\nexport interface ListPairsOptions {\n /** Page number (1-indexed). Default: `1`. */\n page?: number;\n /** Number of items per page. Default: `100`. */\n pageSize?: number;\n /**\n * When `true`, fetches on-chain metadata (name, symbol, decimals) for both\n * the ERC-20 and confidential token, plus totalSupply for the ERC-20.\n * Default: `false`.\n */\n metadata?: boolean;\n}\n\n/** Shorter TTL for negative lookups (5 minutes) so newly registered tokens are discoverable quickly. */\nconst NEGATIVE_CACHE_TTL_MS = 5 * 60 * 1000;\n\n/** Cache entry with expiry timestamp. */\ninterface CacheEntry<T> {\n data: T;\n expiresAt: number;\n}\n\n/**\n * High-level interface for the on-chain token wrappers registry.\n *\n * Uses the connected signer to resolve the correct registry contract\n * address for the current chain and exposes typed read helpers for\n * every registry query. Results are cached in memory with a\n * configurable TTL (default 24 hours).\n *\n * @example\n * ```ts\n * const registry = new WrappersRegistry({ signer });\n *\n * // Paginated listing\n * const page1 = await registry.listPairs({ page: 1, pageSize: 20 });\n *\n * // Structured lookups\n * const result = await registry.getConfidentialToken(erc20Address);\n * if (result) console.log(result.confidentialTokenAddress);\n *\n * // Force refresh\n * registry.refresh();\n * ```\n */\nexport class WrappersRegistry {\n readonly signer: GenericSigner;\n readonly #addresses: Record<number, Address>;\n readonly #ttlMs: number;\n readonly #cache = new Map<string, CacheEntry<unknown>>();\n\n constructor(config: WrappersRegistryConfig) {\n this.signer = config.signer;\n this.#addresses = Object.assign({}, DefaultRegistryAddresses, config.registryAddresses);\n this.#ttlMs = (config.registryTTL ?? DEFAULT_REGISTRY_TTL) * 1000;\n }\n\n /**\n * Synchronous lookup of the registry address for a given chain ID.\n * Returns `undefined` if no address is configured for that chain.\n */\n getAddress(chainId: number): Address | undefined {\n return this.#addresses[chainId];\n }\n\n // ---------------------------------------------------------------------------\n // Cache helpers\n // ---------------------------------------------------------------------------\n\n #getCached<T>(key: string): T | undefined {\n const entry = this.#cache.get(key);\n if (!entry) {\n return undefined;\n }\n if (Date.now() >= entry.expiresAt) {\n this.#cache.delete(key);\n return undefined;\n }\n return entry.data as T;\n }\n\n #setCached<T>(key: string, data: T, ttlMs = this.#ttlMs): T {\n this.#cache.set(key, {\n data,\n expiresAt: Date.now() + ttlMs,\n });\n return data;\n }\n\n /**\n * Force-invalidate the in-memory cache. The next call to any read method\n * will fetch fresh data from the chain.\n */\n refresh(): void {\n this.#cache.clear();\n }\n\n /**\n * The cache TTL in milliseconds.\n * Exposed so query option factories can set a matching `staleTime`.\n */\n get ttlMs(): number {\n return this.#ttlMs;\n }\n\n // ---------------------------------------------------------------------------\n // Registry address resolution\n // ---------------------------------------------------------------------------\n\n /**\n * Resolve the registry contract address for the current chain.\n *\n * Priority: `registryAddresses[chainId]` \\> built-in default.\n *\n * @returns The registry contract address for the connected chain.\n * @throws {@link ConfigurationError} if no address is configured for the chain.\n */\n async getRegistryAddress(): Promise<Address> {\n const chainId = await this.signer.getChainId();\n const address = this.#addresses[chainId];\n\n if (!address) {\n throw new ConfigurationError(\n `No wrappers registry address configured for chain ${chainId}.\\n` +\n `Pass a registryAddresses entry for this chain.`,\n );\n }\n\n return getAddress(address);\n }\n\n // ---------------------------------------------------------------------------\n // Paginated listing\n // ---------------------------------------------------------------------------\n\n /**\n * List token wrapper pairs with page-based pagination.\n *\n * Internally maps to `getTokenConfidentialTokenPairsSlice` on-chain.\n *\n * @param options - Pagination and enrichment options.\n * @returns A {@link PaginatedResult} of pairs.\n *\n * @example\n * ```ts\n * const result = await registry.listPairs({ page: 1, pageSize: 20 });\n * console.log(`${result.total} pairs, showing page ${result.page}`);\n *\n * // With on-chain metadata\n * const withMeta = await registry.listPairs({ metadata: true, pageSize: 10 });\n * for (const pair of withMeta.items) {\n * console.log(pair.underlying.symbol, \"→\", pair.confidential.symbol);\n * }\n * ```\n */\n async listPairs(\n options: ListPairsOptions & { metadata: true },\n ): Promise<PaginatedResult<TokenWrapperPairWithMetadata>>;\n async listPairs(options?: ListPairsOptions): Promise<PaginatedResult<TokenWrapperPair>>;\n async listPairs(\n options: ListPairsOptions = {},\n ): Promise<PaginatedResult<TokenWrapperPair | TokenWrapperPairWithMetadata>> {\n const page = options.page ?? 1;\n const pageSize = options.pageSize ?? DEFAULT_PAGE_SIZE;\n const metadata = options.metadata ?? false;\n\n if (page < 1) {\n throw new ConfigurationError(`page must be >= 1, got ${page}`);\n }\n if (pageSize < 1) {\n throw new ConfigurationError(`pageSize must be >= 1, got ${pageSize}`);\n }\n\n const registry = await this.getRegistryAddress();\n\n // Fetch total (cached)\n const totalCacheKey = `total:${registry}`;\n let total = this.#getCached<number>(totalCacheKey);\n if (total === undefined) {\n const raw = await this.signer.readContract(getTokenPairsLengthContract(registry));\n total = this.#setCached(totalCacheKey, Number(raw));\n }\n\n // Compute slice indices, clamping toIndex to total\n const fromIndex = BigInt((page - 1) * pageSize);\n const clampedToIndex =\n fromIndex + BigInt(pageSize) > BigInt(total) ? BigInt(total) : fromIndex + BigInt(pageSize);\n\n // Page beyond total — return empty\n if (fromIndex >= BigInt(total)) {\n return { items: [], total, page, pageSize };\n }\n\n // Fetch slice (cached)\n const sliceCacheKey = `slice:${registry}:${fromIndex}:${clampedToIndex}`;\n let items = this.#getCached<TokenWrapperPair[]>(sliceCacheKey);\n if (items === undefined) {\n const raw = await this.signer.readContract(\n getTokenPairsSliceContract(registry, fromIndex, clampedToIndex),\n );\n items = this.#setCached(sliceCacheKey, [...raw]);\n }\n\n if (!metadata) {\n return { items, total, page, pageSize };\n }\n\n // Enrich with on-chain metadata (resilient — individual failures don't break the batch)\n const metadataCacheKey = `metadata:${registry}:${fromIndex}:${clampedToIndex}`;\n let metadataItems = this.#getCached<TokenWrapperPairWithMetadata[]>(metadataCacheKey);\n if (metadataItems === undefined) {\n const settled = await Promise.allSettled(items.map((pair) => this.#pairWithMetadata(pair)));\n const hasFailures = settled.some((r) => r.status === \"rejected\");\n const enriched = settled.map((result, i) =>\n result.status === \"fulfilled\"\n ? result.value\n : Object.assign({}, items[i], {\n metadataFailed: true as const,\n underlying: {\n name: \"Unknown\",\n symbol: \"???\",\n decimals: 0,\n totalSupply: 0n,\n },\n confidential: { name: \"Unknown\", symbol: \"???\", decimals: 0 },\n }),\n );\n // Use negative cache TTL when any metadata fetch failed so retries happen sooner\n metadataItems = this.#setCached(\n metadataCacheKey,\n enriched,\n hasFailures ? NEGATIVE_CACHE_TTL_MS : undefined,\n );\n }\n\n return { items: metadataItems, total, page, pageSize };\n }\n\n async #pairWithMetadata(pair: TokenWrapperPair): Promise<TokenWrapperPairWithMetadata> {\n const [uName, uSymbol, uDecimals, uTotalSupply, cName, cSymbol, cDecimals] = await Promise.all([\n this.signer.readContract(nameContract(pair.tokenAddress)),\n this.signer.readContract(symbolContract(pair.tokenAddress)),\n this.signer.readContract(decimalsContract(pair.tokenAddress)),\n this.signer.readContract(erc20TotalSupplyContract(pair.tokenAddress)),\n this.signer.readContract(nameContract(pair.confidentialTokenAddress)),\n this.signer.readContract(symbolContract(pair.confidentialTokenAddress)),\n this.signer.readContract(decimalsContract(pair.confidentialTokenAddress)),\n ]);\n\n return {\n ...pair,\n underlying: {\n name: uName,\n symbol: uSymbol,\n decimals: uDecimals,\n totalSupply: uTotalSupply,\n },\n confidential: { name: cName, symbol: cSymbol, decimals: cDecimals },\n };\n }\n\n // ---------------------------------------------------------------------------\n // Structured single-pair lookups\n // ---------------------------------------------------------------------------\n\n /**\n * Look up the confidential token for a given plain ERC-20 address.\n *\n * @param tokenAddress - The plain ERC-20 token address.\n * @returns The lookup result, or `null` if no pair is registered.\n *\n * @example\n * ```ts\n * const result = await registry.getConfidentialToken(usdcAddress);\n * if (result) {\n * console.log(result.confidentialTokenAddress, result.isValid);\n * }\n * ```\n */\n async getConfidentialToken(\n tokenAddress: Address,\n ): Promise<{ confidentialTokenAddress: Address; isValid: boolean } | null> {\n const registry = await this.getRegistryAddress();\n const normalized = getAddress(tokenAddress);\n\n const cacheKey = `ct:${registry}:${normalized}`;\n const cached = this.#getCached<{\n confidentialTokenAddress: Address;\n isValid: boolean;\n } | null>(cacheKey);\n if (cached !== undefined) {\n return cached;\n }\n\n const [found, confidentialTokenAddress] = await this.signer.readContract(\n getConfidentialTokenAddressContract(registry, normalized),\n );\n\n if (!found) {\n return this.#setCached(cacheKey, null, NEGATIVE_CACHE_TTL_MS);\n }\n\n // Check validity via isConfidentialTokenValid\n const isValid = await this.signer.readContract(\n isConfidentialTokenValidContract(registry, confidentialTokenAddress),\n );\n\n return this.#setCached(cacheKey, { confidentialTokenAddress, isValid });\n }\n\n /**\n * Reverse lookup — find the plain ERC-20 for a given confidential token.\n *\n * @param confidentialTokenAddress - The confidential token address.\n * @returns The lookup result, or `null` if no pair is registered.\n *\n * @example\n * ```ts\n * const result = await registry.getUnderlyingToken(cUsdcAddress);\n * if (result) {\n * console.log(result.tokenAddress, result.isValid);\n * }\n * ```\n */\n async getUnderlyingToken(\n confidentialTokenAddress: Address,\n ): Promise<{ tokenAddress: Address; isValid: boolean } | null> {\n const registry = await this.getRegistryAddress();\n const normalized = getAddress(confidentialTokenAddress);\n\n const cacheKey = `ut:${registry}:${normalized}`;\n const cached = this.#getCached<{\n tokenAddress: Address;\n isValid: boolean;\n } | null>(cacheKey);\n if (cached !== undefined) {\n return cached;\n }\n\n const [found, tokenAddress] = await this.signer.readContract(\n getTokenAddressContract(registry, normalized),\n );\n\n if (!found) {\n return this.#setCached(cacheKey, null, NEGATIVE_CACHE_TTL_MS);\n }\n\n const isValid = await this.signer.readContract(\n isConfidentialTokenValidContract(registry, normalized),\n );\n\n return this.#setCached(cacheKey, { tokenAddress, isValid });\n }\n\n // ---------------------------------------------------------------------------\n // Low-level pass-through methods (backward compatible)\n // ---------------------------------------------------------------------------\n\n /**\n * Fetch all token wrapper pairs from the registry.\n *\n * @returns All registered `TokenWrapperPair` entries.\n */\n async getTokenPairs(): Promise<readonly TokenWrapperPair[]> {\n const registry = await this.getRegistryAddress();\n return this.signer.readContract(getTokenPairsContract(registry));\n }\n\n /**\n * Get the total number of token wrapper pairs.\n *\n * @returns The count as a bigint.\n */\n async getTokenPairsLength(): Promise<bigint> {\n const registry = await this.getRegistryAddress();\n return this.signer.readContract(getTokenPairsLengthContract(registry));\n }\n\n /**\n * Fetch a range of token wrapper pairs (paginated by index).\n *\n * @param fromIndex - Start index (inclusive).\n * @param toIndex - End index (exclusive).\n * @returns The slice of `TokenWrapperPair` entries.\n */\n async getTokenPairsSlice(\n fromIndex: bigint,\n toIndex: bigint,\n ): Promise<readonly TokenWrapperPair[]> {\n const registry = await this.getRegistryAddress();\n return this.signer.readContract(getTokenPairsSliceContract(registry, fromIndex, toIndex));\n }\n\n /**\n * Fetch a single token wrapper pair by index.\n *\n * @param index - Zero-based pair index.\n * @returns The `TokenWrapperPair` at that index.\n */\n async getTokenPair(index: bigint): Promise<TokenWrapperPair> {\n const registry = await this.getRegistryAddress();\n return this.signer.readContract(getTokenPairContract(registry, index));\n }\n\n /**\n * Look up the confidential token address for a given plain ERC-20 token.\n *\n * @param tokenAddress - The plain ERC-20 token address.\n * @returns A tuple `[found, confidentialTokenAddress]`.\n */\n async getConfidentialTokenAddress(tokenAddress: Address): Promise<readonly [boolean, Address]> {\n const registry = await this.getRegistryAddress();\n return this.signer.readContract(\n getConfidentialTokenAddressContract(registry, getAddress(tokenAddress)),\n );\n }\n\n /**\n * Reverse lookup — find the plain ERC-20 for a given confidential token.\n *\n * @param confidentialTokenAddress - The confidential token address.\n * @returns A tuple `[found, tokenAddress]`.\n */\n async getTokenAddress(confidentialTokenAddress: Address): Promise<readonly [boolean, Address]> {\n const registry = await this.getRegistryAddress();\n return this.signer.readContract(\n getTokenAddressContract(registry, getAddress(confidentialTokenAddress)),\n );\n }\n\n /**\n * Check whether a confidential token is registered and valid.\n *\n * @param confidentialTokenAddress - The confidential token address to check.\n * @returns `true` if the token is a known valid wrapper in the registry.\n */\n async isConfidentialTokenValid(confidentialTokenAddress: Address): Promise<boolean> {\n const registry = await this.getRegistryAddress();\n return this.signer.readContract(\n isConfidentialTokenValidContract(registry, getAddress(confidentialTokenAddress)),\n );\n }\n}\n","import { getAddress, type Address } from \"viem\";\nimport { CredentialsManager } from \"./credentials/credentials-manager\";\nimport { DelegatedCredentialsManager } from \"./credentials/delegated-credentials-manager\";\nimport type { ZamaSDKEventListener } from \"./events/sdk-events\";\nimport { ZamaSDKEvents } from \"./events/sdk-events\";\nimport type { RelayerSDK } from \"./relayer/relayer-sdk\";\nimport { MemoryStorage } from \"./storage/memory-storage\";\nimport { ReadonlyToken } from \"./token/readonly-token\";\nimport { Token } from \"./token/token\";\nimport type { GenericSigner, GenericStorage, SignerLifecycleCallbacks } from \"./types\";\nimport { toError } from \"./utils\";\nimport { WrappersRegistry } from \"./wrappers-registry\";\n\n/** Configuration for {@link ZamaSDK}. */\nexport interface ZamaSDKConfig {\n /** FHE relayer backend (`RelayerWeb` for browser, `RelayerNode` for server). */\n relayer: RelayerSDK;\n /** Wallet signer (`ViemSigner`, `EthersSigner`, or custom {@link GenericSigner}). */\n signer: GenericSigner;\n /** Credential storage backend (`IndexedDBStorage` for browser, `MemoryStorage` for tests). */\n storage: GenericStorage;\n /**\n * Session storage for wallet signatures. Shared across all tokens created by this SDK instance.\n * Defaults to an in-memory store (lost on page reload). Pass a `chrome.storage.session`-backed\n * implementation for web extensions so signatures survive service worker restarts.\n */\n sessionStorage?: GenericStorage;\n /**\n * How long the ML-KEM re-encryption keypair remains valid, in seconds.\n * Default: `2592000` (30 days). Must be a positive number — `0` is rejected\n * because the keypair is required to establish the relayer connection.\n */\n keypairTTL?: number;\n /**\n * Controls how long session signatures (EIP-712 wallet signatures) remain valid, in seconds.\n * Default: `2592000` (30 days).\n * - `0`: never persist — every operation triggers a signing prompt (high-security mode).\n * - `\"infinite\"`: session never expires.\n * - Positive number: seconds until the session signature expires and requires re-authentication.\n */\n sessionTTL?: number | \"infinite\";\n /** Optional structured event listener for debugging and telemetry. Never receives sensitive data. */\n onEvent?: ZamaSDKEventListener;\n /**\n * Per-chain wrappers registry address overrides, merged on top of built-in defaults.\n * Use this for custom or local chains (e.g. Hardhat) where no default registry exists.\n */\n registryAddresses?: Record<number, Address>;\n /**\n * How long cached registry results remain valid, in seconds.\n * Default: `86400` (24 hours).\n */\n registryTTL?: number;\n /** Optional signer lifecycle callbacks composed with the SDK's internal session handling. */\n signerLifecycleCallbacks?: SignerLifecycleCallbacks;\n}\n\n/**\n * ZamaSDK — composes a RelayerSDK with contract abstraction.\n * Provides signer, storage, and high-level confidential contract interface.\n */\nexport class ZamaSDK {\n readonly relayer: RelayerSDK;\n readonly signer: GenericSigner;\n readonly storage: GenericStorage;\n readonly sessionStorage: GenericStorage;\n readonly credentials: CredentialsManager;\n readonly delegatedCredentials: DelegatedCredentialsManager;\n /**\n * A {@link WrappersRegistry} instance auto-configured for the current chain.\n * Uses built-in defaults merged with any `registryAddresses` overrides, and the SDK's `registryTTL` if configured.\n *\n * @example\n * ```ts\n * const pairs = await sdk.registry.listPairs({ page: 1 });\n * const result = await sdk.registry.getConfidentialToken(erc20Address);\n * ```\n */\n readonly registry: WrappersRegistry;\n readonly #registryTTL: number | undefined;\n readonly #onEvent: ZamaSDKEventListener;\n #unsubscribeSigner?: () => void;\n // oxlint false positive: awaited in #revokeByTrackedIdentity() and revokeSession()\n // eslint-disable-next-line no-unused-private-class-members\n #identityReady: Promise<void>;\n #lastAddress: Address | null = null;\n #lastChainId: number | null = null;\n\n constructor(config: ZamaSDKConfig) {\n this.relayer = config.relayer;\n this.signer = config.signer;\n this.storage = config.storage;\n this.sessionStorage = config.sessionStorage ?? new MemoryStorage();\n this.#onEvent = config.onEvent ?? function () {};\n this.registry = new WrappersRegistry({\n signer: this.signer,\n registryAddresses: config.registryAddresses,\n registryTTL: config.registryTTL,\n });\n this.#registryTTL = config.registryTTL;\n const credentialsConfig = {\n relayer: this.relayer,\n signer: this.signer,\n storage: this.storage,\n sessionStorage: this.sessionStorage,\n keypairTTL: (() => {\n const ttl = config.keypairTTL ?? 2592000;\n if (ttl <= 0) {\n throw new Error(\"keypairTTL must be a positive number (seconds)\");\n }\n return ttl;\n })(),\n sessionTTL: config.sessionTTL ?? 2592000,\n onEvent: this.#onEvent,\n };\n this.credentials = new CredentialsManager(credentialsConfig);\n this.delegatedCredentials = new DelegatedCredentialsManager(credentialsConfig);\n this.#identityReady = this.#initIdentity();\n\n if (this.signer.subscribe) {\n const lifecycleCallbacks = config.signerLifecycleCallbacks;\n const runLifecycleEffect = (operation: string, effect: () => Promise<void>) => {\n void effect().catch((error) => {\n this.#onEvent?.({\n type: ZamaSDKEvents.TransactionError,\n operation,\n error: toError(error),\n timestamp: Date.now(),\n });\n });\n };\n this.#unsubscribeSigner = this.signer.subscribe({\n onDisconnect: () => {\n runLifecycleEffect(\"signerDisconnect\", async () => {\n await this.#revokeByTrackedIdentity();\n this.#lastAddress = null;\n this.#lastChainId = null;\n lifecycleCallbacks?.onDisconnect?.();\n });\n },\n onAccountChange: (newAddress: Address) => {\n runLifecycleEffect(\"signerAccountChange\", async () => {\n await this.#revokeByTrackedIdentity();\n this.#lastAddress = getAddress(newAddress);\n try {\n this.#lastChainId = await this.signer.getChainId();\n } catch {\n // Signer may not be ready — keep previous chainId\n }\n lifecycleCallbacks?.onAccountChange?.(newAddress);\n });\n },\n onChainChange: (newChainId: number) => {\n runLifecycleEffect(\"signerChainChange\", async () => {\n await this.#revokeByTrackedIdentity();\n this.#lastChainId = newChainId;\n try {\n this.#lastAddress = await this.signer.getAddress();\n } catch {\n // Signer may not be ready — keep previous address\n }\n lifecycleCallbacks?.onChainChange?.(newChainId);\n });\n },\n });\n }\n }\n\n async #initIdentity(): Promise<void> {\n try {\n const address = await this.signer.getAddress();\n const chainId = await this.signer.getChainId();\n // Only commit both values atomically so revokeByTrackedIdentity\n // never sees a partial (address-only) state.\n this.#lastAddress = address;\n this.#lastChainId = chainId;\n } catch {\n // Signer not ready yet — identity will be set on first lifecycle event\n }\n }\n\n async #revokeByTrackedIdentity(): Promise<void> {\n await this.#identityReady;\n if (this.#lastAddress === null || this.#lastChainId === null) {\n return;\n }\n const storeKey = await CredentialsManager.computeStoreKey(this.#lastAddress, this.#lastChainId);\n await this.credentials.revokeByKey(storeKey);\n }\n\n /**\n * Create a read-only interface for a confidential token.\n * Supports balance queries and authorization without a wrapper address.\n *\n * @param address - The confidential token contract address.\n * @returns A {@link ReadonlyToken} instance bound to this SDK's relayer, signer, and storage.\n */\n createReadonlyToken(address: Address): ReadonlyToken {\n return new ReadonlyToken({\n relayer: this.relayer,\n signer: this.signer,\n storage: this.storage,\n sessionStorage: this.sessionStorage,\n credentials: this.credentials,\n delegatedCredentials: this.delegatedCredentials,\n address: getAddress(address),\n onEvent: this.#onEvent,\n });\n }\n\n /**\n * Create a high-level ERC-20-like interface for a confidential token.\n * Includes write operations (transfer, shield, unshield).\n *\n * @param address - The confidential token contract address (also used as wrapper by default).\n * @param wrapper - Optional explicit wrapper address, if it differs from the token address.\n * @returns A {@link Token} instance bound to this SDK's relayer, signer, and storage.\n */\n createToken(address: Address, wrapper?: Address): Token {\n return new Token({\n relayer: this.relayer,\n signer: this.signer,\n storage: this.storage,\n sessionStorage: this.sessionStorage,\n credentials: this.credentials,\n delegatedCredentials: this.delegatedCredentials,\n address: getAddress(address),\n wrapper: wrapper ? getAddress(wrapper) : undefined,\n onEvent: this.#onEvent,\n });\n }\n\n /**\n * Create a {@link WrappersRegistry} instance bound to this SDK's signer.\n * On Mainnet and Sepolia the registry address is resolved automatically.\n *\n * @param registryAddresses - Optional per-chain overrides (e.g. Hardhat).\n * @returns A {@link WrappersRegistry} instance.\n *\n * @example\n * ```ts\n * // Mainnet / Sepolia — resolved automatically\n * const registry = sdk.createWrappersRegistry();\n *\n * // Hardhat or custom chain — override per chain\n * const registry = sdk.createWrappersRegistry({ [31337]: \"0xYourRegistry\" });\n *\n * const pairs = await registry.getTokenPairs();\n * ```\n */\n createWrappersRegistry(registryAddresses?: Record<number, Address>): WrappersRegistry {\n return new WrappersRegistry({\n signer: this.signer,\n registryAddresses,\n registryTTL: this.#registryTTL,\n });\n }\n\n /**\n * Pre-authorize FHE credentials for one or more contract addresses.\n * A single wallet signature covers all addresses, so subsequent decrypt\n * operations on any of these contracts reuse cached credentials.\n *\n * @param contractAddresses - Contract addresses to authorize.\n *\n * @example\n * ```ts\n * await sdk.allow(\"0xContractA\", \"0xContractB\");\n * ```\n */\n async allow(...contractAddresses: Address[]): Promise<void> {\n await this.credentials.allow(...contractAddresses);\n }\n\n /**\n * Revoke the session signature for the current signer.\n * The next decrypt operation will require a fresh wallet signature.\n *\n * @param contractAddresses - Optional addresses included in the\n * `credentials:revoked` event for observability.\n *\n * @example\n * ```ts\n * wallet.on(\"disconnect\", () => sdk.revoke());\n * await sdk.revoke(\"0xContractA\", \"0xContractB\");\n * ```\n */\n async revoke(...contractAddresses: Address[]): Promise<void> {\n await this.credentials.revoke(...contractAddresses);\n }\n\n /**\n * Revoke the session signature for the current signer without requiring\n * contract addresses. Uses the tracked identity when available (safe during\n * account switches), falling back to querying the signer directly.\n *\n * @example\n * ```ts\n * wallet.on(\"disconnect\", () => sdk.revokeSession());\n * ```\n */\n async revokeSession(): Promise<void> {\n await this.#identityReady;\n const address = this.#lastAddress ?? (await this.signer.getAddress());\n const chainId = this.#lastChainId ?? (await this.signer.getChainId());\n const storeKey = await CredentialsManager.computeStoreKey(address, chainId);\n await this.credentials.revokeByKey(storeKey);\n }\n\n /**\n * Whether a session signature is currently cached for the connected wallet.\n * Use this to check if decrypt operations can proceed without a wallet prompt.\n */\n async isAllowed(): Promise<boolean> {\n return this.credentials.isAllowed();\n }\n\n /**\n * Unsubscribe from signer lifecycle events without terminating the relayer.\n * Call this when the SDK instance is being replaced but the relayer is shared\n * (e.g. React provider remount in Strict Mode).\n */\n dispose(): void {\n this.#unsubscribeSigner?.();\n this.#unsubscribeSigner = undefined;\n }\n\n /**\n * Terminate the relayer backend and clean up resources.\n * Call this when the SDK is no longer needed (e.g. on unmount or shutdown).\n */\n terminate(): void {\n this.dispose();\n this.relayer.terminate();\n }\n\n /**\n * Implements the TC39 Explicit Resource Management protocol.\n * Calls {@link terminate} when the `using` binding goes out of scope,\n * unsubscribing signer events and shutting down the relayer.\n *\n * @example\n * ```ts\n * {\n * using sdk = new ZamaSDK({ relayer, signer, storage });\n * await sdk.allow(cUSDT);\n * const balance = await sdk.createReadonlyToken(cUSDT).balanceOf();\n * } // sdk.terminate() called automatically here\n * ```\n */\n [Symbol.dispose](): void {\n this.terminate();\n }\n}\n","import type { Address, Hex } from \"viem\";\nimport type { GenericStorage } from \"../types\";\n\nconst STORAGE_PREFIX = \"zama:pending-unshield:\";\n\nfunction storageKey(wrapperAddress: Address): string {\n return `${STORAGE_PREFIX}${wrapperAddress}`;\n}\n\n/**\n * Persist the unwrap tx hash so an interrupted unshield can be resumed later\n * (e.g. after a page reload).\n */\nexport async function savePendingUnshield(\n storage: GenericStorage,\n wrapperAddress: Address,\n unwrapTxHash: Hex,\n): Promise<void> {\n await storage.set(storageKey(wrapperAddress), unwrapTxHash);\n}\n\n/**\n * Load a previously saved unwrap tx hash, or `null` if none exists.\n */\nexport async function loadPendingUnshield(\n storage: GenericStorage,\n wrapperAddress: Address,\n): Promise<Hex | null> {\n return storage.get<Hex>(storageKey(wrapperAddress));\n}\n\n/**\n * Clear the saved unwrap tx hash after a successful finalization.\n */\nexport async function clearPendingUnshield(\n storage: GenericStorage,\n wrapperAddress: Address,\n): Promise<void> {\n await storage.delete(storageKey(wrapperAddress));\n}\n","import type { GenericStorage } from \"../types\";\n\n/** Minimal chrome.storage.session typings (avoids depending on @types/chrome). */\ndeclare const chrome: {\n storage: {\n session: {\n get(key: string): Promise<Record<string, unknown>>;\n set(items: Record<string, unknown>): Promise<void>;\n remove(key: string): Promise<void>;\n };\n };\n};\n\n/**\n * {@link GenericStorage} backed by `chrome.storage.session`.\n *\n * Use this in MV3 web extensions so the wallet signature survives\n * service worker restarts and is shared across popup, background,\n * and content script contexts.\n *\n * @example\n * ```ts\n * import { ZamaSDK, indexedDBStorage, chromeSessionStorage } from \"@zama-fhe/sdk\";\n *\n * const sdk = new ZamaSDK({\n * relayer,\n * signer,\n * storage: indexedDBStorage,\n * sessionStorage: chromeSessionStorage,\n * });\n * ```\n */\nexport class ChromeSessionStorage implements GenericStorage {\n async get<T = unknown>(key: string): Promise<T | null> {\n const result = await chrome.storage.session.get(key);\n return (result[key] as T) ?? null;\n }\n\n async set(key: string, value: unknown): Promise<void> {\n await chrome.storage.session.set({ [key]: value });\n }\n\n async delete(key: string): Promise<void> {\n await chrome.storage.session.remove(key);\n }\n}\n\n/** Default singleton for application-wide use. */\nexport const chromeSessionStorage = new ChromeSessionStorage();\n"],"mappings":"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"}