@zama-fhe/sdk 3.0.0-alpha.2 → 3.0.0-alpha.21
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.
- package/README.md +207 -122
- package/dist/cjs/build.cjs +2 -0
- package/dist/cjs/build.cjs.map +1 -0
- package/dist/cjs/chains/index.cjs +1 -0
- package/dist/cjs/chains.cjs +2 -0
- package/dist/cjs/chains.cjs.map +1 -0
- package/dist/cjs/cleartext/index.cjs +1 -1
- package/dist/cjs/eip1193-subscribe.cjs +1 -1
- package/dist/cjs/eip1193-subscribe.cjs.map +1 -1
- package/dist/cjs/encryption.cjs +2 -0
- package/dist/cjs/encryption.cjs.map +1 -0
- package/dist/cjs/ethers/index.cjs +1 -1
- package/dist/cjs/ethers/index.cjs.map +1 -1
- package/dist/cjs/index.cjs +73 -73
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/query/index.cjs +1 -1
- package/dist/cjs/query/index.cjs.map +1 -1
- package/dist/cjs/readonly-token.cjs +1 -1
- package/dist/cjs/readonly-token.cjs.map +1 -1
- package/dist/cjs/relayer-cleartext.cjs +2 -0
- package/dist/cjs/relayer-cleartext.cjs.map +1 -0
- package/dist/cjs/relayer-sdk.worker.js +71 -71
- package/dist/cjs/relayer.cjs +1 -1
- package/dist/cjs/relayer.cjs.map +1 -1
- package/dist/cjs/viem/index.cjs +1 -1
- package/dist/cjs/viem/index.cjs.map +1 -1
- package/dist/cjs/wrappers-registry.cjs +1 -1
- package/dist/cjs/wrappers-registry.cjs.map +1 -1
- package/dist/esm/{assertions-BARApuMj.js → assertions-CfqI3AJv.js} +1 -1
- package/dist/esm/{assertions-BARApuMj.js.map → assertions-CfqI3AJv.js.map} +1 -1
- package/dist/esm/build-CvenCk6R.js +2 -0
- package/dist/esm/build-CvenCk6R.js.map +1 -0
- package/dist/esm/chains/index.d.ts +3 -0
- package/dist/esm/chains/index.js +1 -0
- package/dist/esm/chains-aHmrozPh.js +2 -0
- package/dist/esm/chains-aHmrozPh.js.map +1 -0
- package/dist/esm/cleartext/index.d.ts +2 -86
- package/dist/esm/cleartext/index.js +1 -1
- package/dist/esm/cleartext-BHu6-LCv.d.ts +19 -0
- package/dist/esm/cleartext-I-etE_7S.js +2 -0
- package/dist/esm/cleartext-I-etE_7S.js.map +1 -0
- package/dist/esm/eip1193-subscribe-CcotSOIm.js +2 -0
- package/dist/esm/eip1193-subscribe-CcotSOIm.js.map +1 -0
- package/dist/esm/{encryption-CmIPBcfP.js → encryption-YS-Kb7qm.js} +2 -2
- package/dist/esm/{encryption-CmIPBcfP.js.map → encryption-YS-Kb7qm.js.map} +1 -1
- package/dist/esm/ethers/index.d.ts +53 -8
- package/dist/esm/ethers/index.js +1 -1
- package/dist/esm/ethers/index.js.map +1 -1
- package/dist/esm/{hex-D_B-zoId.js → hex-BZVTzEK6.js} +2 -2
- package/dist/esm/{hex-D_B-zoId.js.map → hex-BZVTzEK6.js.map} +1 -1
- package/dist/esm/{relayer-utils-iSPis4x-.d.ts → index-BTY0MxOt.d.ts} +50 -23
- package/dist/esm/{onchain-events-2VNiL78c.d.ts → index-BdyljG1F.d.ts} +387 -1505
- package/dist/esm/index.d.ts +61 -93
- package/dist/esm/index.js +73 -73
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/memory-storage-CFXqXUcm.js +2 -0
- package/dist/esm/memory-storage-CFXqXUcm.js.map +1 -0
- package/dist/esm/node/index.d.ts +88 -110
- package/dist/esm/node/index.js +1 -1
- package/dist/esm/node/index.js.map +1 -1
- package/dist/esm/node/relayer-sdk.node-worker.js +1 -1
- package/dist/esm/node/relayer-sdk.node-worker.js.map +1 -1
- package/dist/esm/query/index.d.ts +40 -50
- package/dist/esm/query/index.js +1 -1
- package/dist/esm/query/index.js.map +1 -1
- package/dist/esm/readonly-token-DCLOYhws.js +2 -0
- package/dist/esm/readonly-token-DCLOYhws.js.map +1 -0
- package/dist/esm/{relayer-C6u3eOlN.js → relayer-7Hd00A6X.js} +2 -2
- package/dist/esm/relayer-7Hd00A6X.js.map +1 -0
- package/dist/esm/{relayer-sdk.types-CGfXwKcB.d.ts → relayer-cleartext-DJkSUlZ2.d.ts} +263 -106
- package/dist/esm/relayer-cleartext-SZCM9wTx.js +2 -0
- package/dist/esm/relayer-cleartext-SZCM9wTx.js.map +1 -0
- package/dist/esm/relayer-sdk.worker.js +71 -71
- package/dist/esm/types-C1S426x4.d.ts +48 -0
- package/dist/esm/types-CVyJHEya.d.ts +14 -0
- package/dist/esm/types-DePjTTbo.d.ts +30 -0
- package/dist/esm/types-FY7ciI37.d.ts +615 -0
- package/dist/esm/viem/index.d.ts +39 -11
- package/dist/esm/viem/index.js +1 -1
- package/dist/esm/viem/index.js.map +1 -1
- package/dist/esm/wrappers-registry-CXNs4eR0.js +2 -0
- package/dist/esm/wrappers-registry-CXNs4eR0.js.map +1 -0
- package/package.json +17 -3
- package/dist/cjs/cleartext.cjs +0 -2
- package/dist/cjs/cleartext.cjs.map +0 -1
- package/dist/esm/cleartext-Cs28cTsa.js +0 -2
- package/dist/esm/cleartext-Cs28cTsa.js.map +0 -1
- package/dist/esm/eip1193-subscribe-Cl_wlVuQ.js +0 -2
- package/dist/esm/eip1193-subscribe-Cl_wlVuQ.js.map +0 -1
- package/dist/esm/memory-storage-F8xjMzVy.js +0 -2
- package/dist/esm/memory-storage-F8xjMzVy.js.map +0 -1
- package/dist/esm/readonly-token-D4GjTj0q.js +0 -2
- package/dist/esm/readonly-token-D4GjTj0q.js.map +0 -1
- package/dist/esm/relayer-C6u3eOlN.js.map +0 -1
- package/dist/esm/relayer-sdk-DPqytEbO.d.ts +0 -44
- package/dist/esm/relayer-utils-BeoTNDM4.js +0 -2
- package/dist/esm/relayer-utils-BeoTNDM4.js.map +0 -1
- package/dist/esm/wrappers-registry-ydyySM9g.js +0 -2
- package/dist/esm/wrappers-registry-ydyySM9g.js.map +0 -1
package/dist/cjs/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":["ZamaError","ZamaErrorCode","ZamaError","ZamaErrorCode","DelegationCooldownError","DelegationContractIsSelfError","AclPausedError","DelegationSelfNotAllowedError","DelegationDelegateEqualsContractError","DelegationExpirationTooSoonError","DelegationExpiryUnchangedError","DelegationNotFoundError","#dbName","#dbVersion","#storeName","#db","#dbPromise","#withTransaction","#getDB","#worker","#initPromise","#doInitWorker","#pendingRequests","#rejectAllPending","workerFilename","workerCode","#storage","#chainId","#relayerUrl","#ttlMs","#logger","#publicKeyMem","#publicKeyInflight","#loadPublicKey","#deleteQuietly","toError","#publicParamsMem","#publicParamsInflight","#loadPublicParams","#revalidationInflight","#revalidateIfDueInner","#lastRevalidatedAt","#collectParamEntries","#writeEntries","#clearAll","#checkArtifactFreshness","#config","#status","#initError","#getWorkerConfig","DefaultConfigs","#ensureWorker","#ensureLock","#ensureWorkerInner","#workerClient","#initPromise","#artifactCache","#terminated","#resolvedChainId","#tearDown","#artifactStorage","#setStatus","#initWorker","ZamaError","ConfigurationError","#refreshCsrfToken","buildEIP712DomainType","withRetry","#storage","#decryptNamespace","#decryptKeysNamespace","#buildStorageKey","#indexWriteQueue","#addToIndex","#doClearForRequester","#readIndex","#doClearAll","#map","#cachedDerivedKey","#cachedDerivedKeyIdentity","#deriveKey","#storage","#assertSessionEntry","#onEvent","ZamaSDKEvents","#extendContracts","ZamaError","toError","#deleteCredentials","#createPromise","#createPromiseKey","#lastExtendResult","wrapSigningError","#extendPromise","#extendCredentials","#relayer","#storeKey","#cachedStoreKey","#cachedStoreKeyIdentity","#relayer","#storeKey","#create","#signDelegated","#cachedStoreKey","#cachedStoreKeyIdentity","ReadonlyToken","#getUnderlying","#underlying","#underlyingPromise","underlyingContract","#assertConfidentialBalance","ZamaSDKEvents","toError","ZamaError","EncryptionFailedError","confidentialTransferContract","confidentialTransferFromContract","setOperatorContract","isOperatorContract","balanceOfContract","#ensureAllowance","wrapContract","unwrapContract","isZeroHandle","DecryptionFailedError","unwrapFromBalanceContract","#waitAndFinalizeUnshield","finalizeUnwrapContract","allowanceContract","approveContract","DelegationExpirationTooSoonError","DelegationSelfNotAllowedError","DelegationDelegateEqualsContractError","MAX_UINT64","DelegationExpiryUnchangedError","delegateForUserDecryptionContract","DelegationNotFoundError","revokeDelegationContract","#batchDelegationOp","MainnetConfig","SepoliaConfig","hoodiCleartextConfig","#addresses","#ttlMs","#cache","ConfigurationError","#getCached","getTokenPairsLengthContract","#setCached","getTokenPairsSliceContract","#pairWithMetadata","nameContract","symbolContract","decimalsContract","erc20TotalSupplyContract","getConfidentialTokenAddressContract","zeroAddress","getTokenAddressContract","getTokenPairsContract","getTokenPairContract","isConfidentialTokenValidContract","#registryTTL","#onEvent","#identityReady","#initIdentity","ZamaSDKEvents","toError","#unsubscribeSigner","#revokeByTrackedIdentity","#lastAddress","#lastChainId","ReadonlyToken","isZeroHandle","pLimit","wrapDecryptError"],"sources":["../../src/errors/transaction.ts","../../src/errors/balance.ts","../../src/errors/acl-revert.ts","../../src/storage/indexeddb-storage.ts","../../src/worker/worker.base-client.ts","../../src/worker/browser-extension.ts","../../src/worker/worker.client.ts","../../src/utils/hex.ts","../../src/relayer/fhe-artifact-cache.ts","../../src/relayer/relayer-web.ts","../../src/decrypt-cache.ts","../../src/storage/memory-storage.ts","../../src/credentials/credential-crypto.ts","../../src/credentials/credential-validation.ts","../../src/credentials/session-signatures.ts","../../src/credentials/credentials-manager-base.ts","../../src/credentials/credentials-manager.ts","../../src/credentials/delegated-credentials-manager.ts","../../src/events/onchain-events.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 type { Handle } from \"../relayer/relayer-sdk.types\";\nimport type { ZKProofLike } from \"@zama-fhe/relayer-sdk/bundle\";\nimport type {\n CreateDelegatedEIP712Payload,\n CreateDelegatedEIP712ResponseData,\n CreateEIP712Payload,\n CreateEIP712ResponseData,\n DelegatedUserDecryptPayload,\n DelegatedUserDecryptResponseData,\n EncryptPayload,\n EncryptResponseData,\n GenerateKeypairResponseData,\n GetPublicKeyResponseData,\n GetPublicParamsResponseData,\n InitResponseData,\n PublicDecryptResponseData,\n RequestZKProofVerificationResponseData,\n UserDecryptPayload,\n UserDecryptResponseData,\n GenericLogger,\n WorkerRequest,\n WorkerRequestType,\n WorkerResponse,\n} from \"./worker.types\";\n\n/** Pending request tracker */\ninterface PendingRequest<T> {\n resolve: (value: T) => void;\n reject: (error: Error) => void;\n timeoutId: ReturnType<typeof setTimeout>;\n startTime: number;\n type: WorkerRequestType;\n}\n\n/** Default timeout for operations (30 seconds) */\nexport const DEFAULT_TIMEOUT_MS = 30_000;\n\n/** Extended timeout for WASM initialization (60 seconds) */\nexport const INIT_TIMEOUT_MS = 60_000;\n\n/**\n * Abstract base class for worker clients (browser Web Worker and Node.js worker_threads).\n * Encapsulates all shared logic: pending request tracking, timeouts, init dedup, domain methods.\n * Subclasses implement the abstract hooks for platform-specific worker creation and messaging.\n */\nexport abstract class BaseWorkerClient<TWorker, TConfig> {\n #worker: TWorker | null = null;\n #pendingRequests = new Map<string, PendingRequest<unknown>>();\n #initPromise: Promise<TWorker> | null = null;\n protected readonly config: TConfig;\n protected readonly logger: GenericLogger | undefined;\n\n constructor(config: TConfig, logger: GenericLogger | undefined) {\n this.config = config;\n this.logger = logger;\n }\n\n // ===========================================================================\n // Abstract hooks — subclasses must implement\n // ===========================================================================\n\n /** Create the platform-specific worker instance. */\n protected abstract createWorker(): TWorker;\n\n /** Wire message/error/messageerror events on the worker. */\n protected abstract wireEvents(worker: TWorker): void;\n\n /** Post a message to the worker. */\n protected abstract postMessage(worker: TWorker, request: WorkerRequest): void;\n\n /** Terminate the platform-specific worker. */\n protected abstract terminateWorker(worker: TWorker): void;\n\n /** Generate a unique request ID. */\n protected abstract generateRequestId(): string;\n\n /** Return the init request type and payload. */\n protected abstract getInitPayload(): {\n type: WorkerRequestType;\n payload: WorkerRequest[\"payload\"];\n };\n\n /** Optional hook called after worker init succeeds (e.g. for node worker.unref()). */\n protected onWorkerReady?(_worker: TWorker): void;\n\n // ===========================================================================\n // Shared init / terminate\n // ===========================================================================\n\n async initWorker(): Promise<TWorker> {\n if (this.#worker) {\n return this.#worker;\n }\n\n if (!this.#initPromise) {\n this.#initPromise = this.#doInitWorker().catch((error) => {\n this.#initPromise = null;\n throw error;\n });\n }\n return this.#initPromise;\n }\n\n async #doInitWorker(): Promise<TWorker> {\n const worker = this.createWorker();\n this.wireEvents(worker);\n\n try {\n const { type, payload } = this.getInitPayload();\n await this.sendRequestTo<InitResponseData>(worker, type, payload, INIT_TIMEOUT_MS);\n this.onWorkerReady?.(worker);\n this.#worker = worker;\n } catch (error) {\n this.terminateWorker(worker);\n throw error;\n }\n\n return this.#worker;\n }\n\n terminate(): void {\n if (this.#worker) {\n for (const [id, pending] of this.#pendingRequests) {\n clearTimeout(pending.timeoutId);\n pending.reject(new Error(\"Worker terminated\"));\n this.#pendingRequests.delete(id);\n }\n\n this.terminateWorker(this.#worker);\n this.#worker = null;\n }\n this.#initPromise = null;\n }\n\n // ===========================================================================\n // Message handling (called by subclass event wiring)\n // ===========================================================================\n\n protected handleResponse(response: WorkerResponse<unknown>): void {\n const pending = this.#pendingRequests.get(response.id);\n\n if (!pending) {\n this.logger?.warn(\"[WorkerClient] Received response for unknown request\", {\n id: response.id,\n });\n return;\n }\n\n const elapsed = Math.round(performance.now() - pending.startTime);\n\n clearTimeout(pending.timeoutId);\n this.#pendingRequests.delete(response.id);\n\n if (response.success) {\n this.logger?.debug(`[WorkerClient] ← ${pending.type} OK`, {\n id: response.id,\n elapsed,\n });\n pending.resolve(response.data);\n } else {\n this.logger?.error(`[WorkerClient] ← ${pending.type} FAILED`, {\n id: response.id,\n elapsed,\n error: response.error,\n });\n const err = new Error(response.error);\n if (\"statusCode\" in response && typeof response.statusCode === \"number\") {\n (err as Error & { statusCode?: number }).statusCode = response.statusCode;\n }\n pending.reject(err);\n }\n }\n\n protected handleWorkerError(message: string): void {\n this.logger?.error(\"[WorkerClient] Worker error\", { error: message });\n const worker = this.#worker;\n this.#worker = null;\n this.#rejectAllPending(`Worker error: ${message}`);\n if (worker) {\n this.terminateWorker(worker);\n }\n }\n\n protected handleWorkerMessageError(): void {\n this.logger?.error(\"[WorkerClient] Message deserialization failed\");\n const worker = this.#worker;\n this.#worker = null;\n this.#rejectAllPending(\"Worker message deserialization failed\");\n if (worker) {\n this.terminateWorker(worker);\n }\n }\n\n // ===========================================================================\n // Request sending\n // ===========================================================================\n\n protected sendRequestTo<T>(\n worker: TWorker,\n type: WorkerRequestType,\n payload: WorkerRequest[\"payload\"],\n timeoutMs: number = DEFAULT_TIMEOUT_MS,\n ): Promise<T> {\n return new Promise<T>((resolve, reject) => {\n const id = this.generateRequestId();\n const startTime = performance.now();\n this.logger?.debug(`[WorkerClient] → ${type}`, { id });\n\n const timeoutId = setTimeout(() => {\n this.#pendingRequests.delete(id);\n const elapsed = Math.round(performance.now() - startTime);\n this.logger?.error(`[WorkerClient] ${type} timed out after ${timeoutMs}ms`, {\n id,\n elapsed,\n });\n reject(new Error(`Request ${type} timed out after ${timeoutMs}ms`));\n }, timeoutMs);\n\n this.#pendingRequests.set(id, {\n resolve: resolve as (value: unknown) => void,\n reject,\n timeoutId,\n startTime,\n type,\n });\n\n const request = { id, type, payload } as WorkerRequest;\n this.postMessage(worker, request);\n });\n }\n\n protected async sendRequest<T>(\n type: WorkerRequestType,\n payload: WorkerRequest[\"payload\"],\n timeoutMs: number = DEFAULT_TIMEOUT_MS,\n ): Promise<T> {\n const worker = await this.initWorker();\n return this.sendRequestTo<T>(worker, type, payload, timeoutMs);\n }\n\n // ===========================================================================\n // Domain methods\n // ===========================================================================\n\n async generateKeypair(): Promise<GenerateKeypairResponseData> {\n return this.sendRequest<GenerateKeypairResponseData>(\"GENERATE_KEYPAIR\", {});\n }\n\n async createEIP712(params: CreateEIP712Payload): Promise<CreateEIP712ResponseData> {\n return this.sendRequest<CreateEIP712ResponseData>(\"CREATE_EIP712\", params);\n }\n\n async encrypt(params: EncryptPayload): Promise<EncryptResponseData> {\n return this.sendRequest<EncryptResponseData>(\"ENCRYPT\", params);\n }\n\n async userDecrypt(params: UserDecryptPayload): Promise<UserDecryptResponseData> {\n return this.sendRequest<UserDecryptResponseData>(\"USER_DECRYPT\", params);\n }\n\n async publicDecrypt(handles: Handle[]): Promise<PublicDecryptResponseData> {\n return this.sendRequest<PublicDecryptResponseData>(\"PUBLIC_DECRYPT\", { handles });\n }\n\n async createDelegatedUserDecryptEIP712(\n params: CreateDelegatedEIP712Payload,\n ): Promise<CreateDelegatedEIP712ResponseData> {\n return this.sendRequest<CreateDelegatedEIP712ResponseData>(\"CREATE_DELEGATED_EIP712\", params);\n }\n\n async delegatedUserDecrypt(\n params: DelegatedUserDecryptPayload,\n ): Promise<DelegatedUserDecryptResponseData> {\n return this.sendRequest<DelegatedUserDecryptResponseData>(\"DELEGATED_USER_DECRYPT\", params);\n }\n\n async requestZKProofVerification(\n zkProof: ZKProofLike,\n ): Promise<RequestZKProofVerificationResponseData> {\n return this.sendRequest<RequestZKProofVerificationResponseData>(\n \"REQUEST_ZK_PROOF_VERIFICATION\",\n { zkProof },\n );\n }\n\n async getPublicKey(): Promise<GetPublicKeyResponseData> {\n return this.sendRequest<GetPublicKeyResponseData>(\"GET_PUBLIC_KEY\", {});\n }\n\n async getPublicParams(bits: number): Promise<GetPublicParamsResponseData> {\n return this.sendRequest<GetPublicParamsResponseData>(\"GET_PUBLIC_PARAMS\", { bits });\n }\n\n // ===========================================================================\n // Internal helpers\n // ===========================================================================\n\n #rejectAllPending(message: string): void {\n for (const [id, pending] of this.#pendingRequests) {\n clearTimeout(pending.timeoutId);\n pending.reject(new Error(message));\n this.#pendingRequests.delete(id);\n }\n }\n}\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 { Hex } from \"viem\";\nimport { assertCondition } from \"./assertions\";\n\n/** Normalize a un-prefixed hex payload to a 0x-prefixed `Hex` value. */\nexport function prefixHex(value: string): Hex {\n return (value.startsWith(\"0x\") ? value : `0x${value}`) as Hex;\n}\n\n/** Convert a public `Hex` value back an unprefixed format. */\nexport function unprefixHex(value: Hex): string {\n assertCondition(value.startsWith(\"0x\"), `Expected 0x-prefixed hex, got: ${value}`);\n return value.slice(2);\n}\n","import type { GenericStorage } from \"../types\";\nimport { assertObject, assertStringProp, toError } from \"../utils\";\nimport type { GenericLogger } from \"../worker/worker.types\";\n\n// ── Cached data shapes ──────────────────────────────────────\n\n/** Cached shape for the FHE network public key. */\ninterface CachedPublicKey {\n publicKeyId: string;\n /** Base64-encoded Uint8Array. */\n publicKey: string;\n /** Artifact URL from the manifest. */\n artifactUrl?: string;\n /** HTTP ETag from the artifact response. */\n etag?: string;\n /** HTTP Last-Modified from the artifact response. */\n lastModified?: string;\n /** Epoch-ms timestamp of the last successful revalidation. */\n lastValidatedAt: number;\n}\n\n/** Cached shape for FHE public params. */\ninterface CachedPublicParams {\n publicParamsId: string;\n /** Base64-encoded Uint8Array. */\n publicParams: string;\n artifactUrl?: string;\n etag?: string;\n lastModified?: string;\n lastValidatedAt: number;\n}\n\n// ── Return types ────────────────────────────────────────────\n\n/** Return type of the public key fetcher. */\ntype PublicKeyResult = { publicKeyId: string; publicKey: Uint8Array } | null;\n\n/** Return type of the public params fetcher. */\ntype PublicParamsResult = {\n publicParamsId: string;\n publicParams: Uint8Array;\n} | null;\n\n// ── Constants ───────────────────────────────────────────────\n\n/** Max chunk size for String.fromCharCode to avoid call-stack overflow on large buffers. */\nconst CHUNK_SIZE = 8192;\n\n/** On revalidation failure, retry after 5 minutes instead of the full TTL. */\nconst SHORT_RETRY_MS = 5 * 60 * 1000;\n\n// ── Helpers ─────────────────────────────────────────────────\n\nfunction toBase64(bytes: Uint8Array): string {\n const chunks: string[] = [];\n for (let i = 0; i < bytes.length; i += CHUNK_SIZE) {\n chunks.push(String.fromCharCode(...bytes.subarray(i, i + CHUNK_SIZE)));\n }\n return btoa(chunks.join(\"\"));\n}\n\nfunction fromBase64(b64: string): Uint8Array {\n let binary: string;\n try {\n binary = atob(b64);\n } catch {\n throw new Error(`Invalid base64 data (length: ${b64.length})`);\n }\n if (binary.length === 0) {\n throw new Error(\"Decoded artifact is empty\");\n }\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) {\n bytes[i] = binary.charCodeAt(i);\n }\n return bytes;\n}\n\nfunction pubkeyStorageKey(chainId: number): string {\n return `fhe:pubkey:${chainId}`;\n}\n\nfunction paramsStorageKey(chainId: number, bits: number): string {\n return `fhe:params:${chainId}:${bits}`;\n}\n\nfunction paramsIndexKey(chainId: number): string {\n return `fhe:params-index:${chainId}`;\n}\n\nfunction assertCachedPk(v: unknown): asserts v is CachedPublicKey {\n assertObject(v, \"CachedPublicKey\");\n assertStringProp(v, \"publicKeyId\", \"CachedPublicKey.publicKeyId\");\n assertStringProp(v, \"publicKey\", \"CachedPublicKey.publicKey\");\n}\n\nfunction assertCachedParams(v: unknown): asserts v is CachedPublicParams {\n assertObject(v, \"CachedPublicParams\");\n assertStringProp(v, \"publicParamsId\", \"CachedPublicParams.publicParamsId\");\n assertStringProp(v, \"publicParams\", \"CachedPublicParams.publicParams\");\n}\n\n/** Manifest shape returned by the relayer `/keyurl` endpoint. */\ninterface ManifestShape {\n fhePublicKey: { dataId: string; urls: string[] };\n crs: Record<string, { dataId: string; urls: string[] }>;\n}\n\n// ── ArtifactCache ──────────────────────────────────────────\n\n/**\n * Persistent cache for FHE network public key and public params.\n * Uses a {@link GenericStorage} backend (e.g. MemoryStorage, or any\n * user-provided async key-value adapter) to avoid re-downloading large\n * binary data on every app instantiation.\n *\n * Cache keys are scoped by chain ID.\n */\nexport class FheArtifactCache {\n readonly #storage: GenericStorage;\n readonly #chainId: number;\n readonly #relayerUrl: string;\n readonly #ttlMs: number;\n readonly #logger: GenericLogger;\n #publicKeyMem: PublicKeyResult | undefined;\n #publicParamsMem = new Map<number, PublicParamsResult>();\n #publicKeyInflight: Promise<PublicKeyResult> | null = null;\n #publicParamsInflight = new Map<number, Promise<PublicParamsResult>>();\n #revalidationInflight: Promise<boolean> | null = null;\n /** In-memory guard to skip storage reads when revalidation isn't due. */\n #lastRevalidatedAt: number | null = null;\n\n constructor(opts: {\n storage: GenericStorage;\n chainId: number;\n relayerUrl: string;\n /** Cache TTL in seconds. Default: 86 400 (24 h). Set to 0 to revalidate on every operation. */\n ttl?: number;\n logger?: GenericLogger;\n }) {\n this.#storage = opts.storage;\n this.#chainId = opts.chainId;\n this.#relayerUrl = opts.relayerUrl;\n this.#ttlMs = (opts.ttl ?? 86_400) * 1000;\n this.#logger = opts.logger ?? console;\n }\n\n // ── getPublicKey ────────────────────────────────────────\n\n async getPublicKey(fetcher: () => Promise<PublicKeyResult>): Promise<PublicKeyResult> {\n if (this.#publicKeyMem !== undefined) {\n return this.#publicKeyMem;\n }\n\n // Deduplicate concurrent calls\n if (this.#publicKeyInflight) {\n return this.#publicKeyInflight;\n }\n\n this.#publicKeyInflight = this.#loadPublicKey(fetcher);\n try {\n return await this.#publicKeyInflight;\n } finally {\n this.#publicKeyInflight = null;\n }\n }\n\n async #loadPublicKey(fetcher: () => Promise<PublicKeyResult>): Promise<PublicKeyResult> {\n const key = pubkeyStorageKey(this.#chainId);\n\n try {\n const raw = await this.#storage.get(key);\n if (raw) {\n assertCachedPk(raw);\n const result: PublicKeyResult = {\n publicKeyId: raw.publicKeyId,\n publicKey: fromBase64(raw.publicKey),\n };\n this.#publicKeyMem = result;\n return result;\n }\n } catch (err) {\n // Corrupt or unreadable entry — delete and fall through to fetcher\n await this.#deleteQuietly(key);\n this.#logger.warn(\n \"Failed to read public key from persistent storage, falling back to network fetch\",\n {\n chainId: this.#chainId,\n error: toError(err).message,\n },\n );\n }\n\n const result = await fetcher();\n if (result === null) {\n return null;\n }\n\n this.#publicKeyMem = result;\n\n try {\n const cached: CachedPublicKey = {\n publicKeyId: result.publicKeyId,\n publicKey: toBase64(result.publicKey),\n lastValidatedAt: Date.now(),\n };\n await this.#storage.set(key, cached);\n } catch (err) {\n this.#logger.warn(\"Failed to persist public key to storage\", {\n chainId: this.#chainId,\n error: toError(err).message,\n });\n }\n\n return result;\n }\n\n // ── getPublicParams ─────────────────────────────────────\n\n async getPublicParams(\n bits: number,\n fetcher: () => Promise<PublicParamsResult>,\n ): Promise<PublicParamsResult> {\n const mem = this.#publicParamsMem.get(bits);\n if (mem !== undefined) {\n return mem;\n }\n\n // Deduplicate concurrent calls\n const inflight = this.#publicParamsInflight.get(bits);\n if (inflight) {\n return inflight;\n }\n\n const promise = this.#loadPublicParams(bits, fetcher);\n this.#publicParamsInflight.set(bits, promise);\n try {\n return await promise;\n } finally {\n this.#publicParamsInflight.delete(bits);\n }\n }\n\n async #loadPublicParams(\n bits: number,\n fetcher: () => Promise<PublicParamsResult>,\n ): Promise<PublicParamsResult> {\n const key = paramsStorageKey(this.#chainId, bits);\n\n try {\n const raw = await this.#storage.get(key);\n if (raw) {\n assertCachedParams(raw);\n const result: PublicParamsResult = {\n publicParamsId: raw.publicParamsId,\n publicParams: fromBase64(raw.publicParams),\n };\n this.#publicParamsMem.set(bits, result);\n return result;\n }\n } catch (err) {\n // Corrupt or unreadable entry — delete and fall through to fetcher\n await this.#deleteQuietly(key);\n this.#logger.warn(\n \"Failed to read public params from persistent storage, falling back to network fetch\",\n {\n chainId: this.#chainId,\n bits,\n error: toError(err).message,\n },\n );\n }\n\n const result = await fetcher();\n if (result === null) {\n return null;\n }\n\n this.#publicParamsMem.set(bits, result);\n\n try {\n const cached: CachedPublicParams = {\n publicParamsId: result.publicParamsId,\n publicParams: toBase64(result.publicParams),\n lastValidatedAt: Date.now(),\n };\n await this.#storage.set(key, cached);\n\n // Update params index for cold-start CRS detection\n const idxKey = paramsIndexKey(this.#chainId);\n const existing =\n (await this.#storage.get<number[]>(idxKey).catch((err) => {\n this.#logger.warn(\"Failed to read params index from storage\", {\n chainId: this.#chainId,\n error: toError(err).message,\n });\n return null;\n })) ?? [];\n if (!existing.includes(bits)) {\n await this.#storage.set(idxKey, [...existing, bits]);\n }\n } catch (err) {\n this.#logger.warn(\"Failed to persist public params to storage\", {\n chainId: this.#chainId,\n bits,\n error: toError(err).message,\n });\n }\n\n return result;\n }\n\n // ── Artifact-level revalidation ─────────────────────────\n\n /**\n * Check whether cached FHE artifacts are still fresh by issuing\n * HTTP conditional requests (ETag / If-None-Match, Last-Modified /\n * If-Modified-Since) against the actual artifact CDN URLs.\n *\n * @returns `true` if the cache was invalidated and the caller should\n * re-fetch artifacts, `false` otherwise.\n */\n async revalidateIfDue(): Promise<boolean> {\n // Concurrency guard — coalesce overlapping calls\n if (this.#revalidationInflight) {\n return this.#revalidationInflight;\n }\n this.#revalidationInflight = this.#revalidateIfDueInner();\n try {\n return await this.#revalidationInflight;\n } finally {\n this.#revalidationInflight = null;\n }\n }\n\n async #revalidateIfDueInner(): Promise<boolean> {\n // Fast path: in-memory timestamp check avoids storage I/O on every call\n const now = Date.now();\n if (this.#lastRevalidatedAt !== null && now - this.#lastRevalidatedAt < this.#ttlMs) {\n return false;\n }\n\n // Skip revalidation when relayerUrl is not configured (e.g. Hardhat)\n if (!this.#relayerUrl) {\n return false;\n }\n\n const pkKey = pubkeyStorageKey(this.#chainId);\n\n // Track partial progress so the catch block can reuse already-read data\n let storedPk: CachedPublicKey | null = null;\n let paramEntries: Array<{\n bits: number;\n key: string;\n data: CachedPublicParams;\n }> = [];\n\n try {\n // 1. Read PK cache entry and collect params entries in parallel\n const [pkRaw, entries] = await Promise.all([\n this.#storage.get(pkKey),\n this.#collectParamEntries(),\n ]);\n\n // Validate PK shape\n if (pkRaw) {\n try {\n assertCachedPk(pkRaw);\n storedPk = { ...pkRaw, lastValidatedAt: pkRaw.lastValidatedAt ?? 0 };\n } catch (err) {\n this.#logger.warn(\"Corrupt public key cache entry detected, deleting\", {\n chainId: this.#chainId,\n error: toError(err).message,\n });\n await this.#deleteQuietly(pkKey);\n }\n }\n\n paramEntries = entries;\n\n if (!storedPk) {\n return false;\n }\n\n // 2. Check if all entries are within TTL\n const allEntries: Array<{ lastValidatedAt: number }> = [\n storedPk,\n ...paramEntries.map((e) => e.data),\n ];\n const allFresh = allEntries.every((e) => now - e.lastValidatedAt < this.#ttlMs);\n if (allFresh) {\n this.#lastRevalidatedAt = now;\n return false;\n }\n\n // 3. Fetch manifest to discover current artifact URLs\n const manifestRes = await globalThis.fetch(`${this.#relayerUrl}/keyurl`);\n if (!manifestRes.ok) {\n // Treat as transient failure — use short retry instead of full TTL\n const retryTimestamp = now - this.#ttlMs + SHORT_RETRY_MS;\n this.#logger.warn(\"Manifest fetch failed during revalidation, retrying in 5 min\", {\n status: manifestRes.status,\n relayerUrl: this.#relayerUrl,\n });\n await this.#writeEntries(\n pkKey,\n { ...storedPk, lastValidatedAt: retryTimestamp },\n paramEntries.map((e) => ({\n ...e,\n data: { ...e.data, lastValidatedAt: retryTimestamp },\n })),\n );\n this.#lastRevalidatedAt = retryTimestamp;\n return false;\n }\n\n const manifest = (await manifestRes.json()) as unknown;\n\n // Validate manifest shape — a malformed response indicates a permanent\n // config error (wrong relayer URL, API version mismatch), not a transient\n // network issue. Log at error level so it's actionable.\n if (\n !manifest ||\n typeof manifest !== \"object\" ||\n !(\"fhePublicKey\" in manifest) ||\n !(manifest as ManifestShape).fhePublicKey?.urls?.length ||\n !(\"crs\" in manifest) ||\n typeof (manifest as ManifestShape).crs !== \"object\"\n ) {\n this.#logger.error(\n \"Relayer manifest has unexpected shape — check relayer URL and API version\",\n {\n relayerUrl: this.#relayerUrl,\n manifestKeys: manifest && typeof manifest === \"object\" ? Object.keys(manifest) : [],\n },\n );\n // Fail-open with short retry — but the error-level log distinguishes this from transient failures\n const retryTimestamp = now - this.#ttlMs + SHORT_RETRY_MS;\n await this.#writeEntries(\n pkKey,\n { ...storedPk, lastValidatedAt: retryTimestamp },\n paramEntries.map((e) => ({\n ...e,\n data: { ...e.data, lastValidatedAt: retryTimestamp },\n })),\n );\n this.#lastRevalidatedAt = retryTimestamp;\n return false;\n }\n const validManifest = manifest as ManifestShape;\n\n // ── 4. Check PK artifact ──────────────────────────\n const pkArtifactUrl = validManifest.fhePublicKey.urls[0];\n\n // URL change → stale\n if (storedPk.artifactUrl && pkArtifactUrl && pkArtifactUrl !== storedPk.artifactUrl) {\n await this.#clearAll(pkKey, paramEntries);\n this.#lastRevalidatedAt = null;\n return true;\n }\n\n let updatedPk: CachedPublicKey = { ...storedPk, lastValidatedAt: now };\n if (pkArtifactUrl) {\n const freshness = await this.#checkArtifactFreshness(pkArtifactUrl, storedPk);\n if (!freshness.fresh) {\n await this.#clearAll(pkKey, paramEntries);\n this.#lastRevalidatedAt = null;\n return true;\n }\n updatedPk = {\n ...updatedPk,\n artifactUrl: pkArtifactUrl,\n etag: freshness.etag,\n lastModified: freshness.lastModified,\n };\n }\n\n // ── 5. Check each CRS artifact ────────────────────\n const updatedParamEntries: typeof paramEntries = [];\n for (const entry of paramEntries) {\n const manifestCrs = validManifest.crs[String(entry.bits)];\n const crsUrl = manifestCrs?.urls[0];\n\n // URL change → stale\n if (entry.data.artifactUrl && crsUrl && crsUrl !== entry.data.artifactUrl) {\n await this.#clearAll(pkKey, paramEntries);\n this.#lastRevalidatedAt = null;\n return true;\n }\n\n let updatedData: CachedPublicParams = {\n ...entry.data,\n lastValidatedAt: now,\n };\n if (crsUrl) {\n const freshness = await this.#checkArtifactFreshness(crsUrl, entry.data);\n if (!freshness.fresh) {\n await this.#clearAll(pkKey, paramEntries);\n this.#lastRevalidatedAt = null;\n return true;\n }\n updatedData = {\n ...updatedData,\n artifactUrl: crsUrl,\n etag: freshness.etag,\n lastModified: freshness.lastModified,\n };\n }\n updatedParamEntries.push({ ...entry, data: updatedData });\n }\n\n // 6. All fresh — update timestamps and HTTP validators\n await this.#writeEntries(pkKey, updatedPk, updatedParamEntries);\n this.#lastRevalidatedAt = now;\n return false;\n } catch (err) {\n const error = toError(err);\n const isProgrammingError =\n err instanceof TypeError ||\n err instanceof ReferenceError ||\n err instanceof RangeError ||\n err instanceof SyntaxError;\n const level = isProgrammingError ? \"error\" : \"warn\";\n this.#logger[level](\n isProgrammingError\n ? \"Unexpected error during revalidation (possible bug)\"\n : \"Revalidation failed, using cached artifacts (fail-open)\",\n {\n chainId: this.#chainId,\n relayerUrl: this.#relayerUrl,\n error: error.message,\n },\n );\n\n // Fail-open: use short retry interval (5 min) instead of full TTL\n const retryTimestamp = now - this.#ttlMs + SHORT_RETRY_MS;\n try {\n if (storedPk) {\n await this.#writeEntries(\n pkKey,\n { ...storedPk, lastValidatedAt: retryTimestamp },\n paramEntries.map((e) => ({\n ...e,\n data: { ...e.data, lastValidatedAt: retryTimestamp },\n })),\n );\n }\n } catch (innerErr) {\n this.#logger.warn(\"Failed to update validation timestamps after revalidation error\", {\n chainId: this.#chainId,\n error: toError(innerErr).message,\n });\n }\n this.#lastRevalidatedAt = retryTimestamp;\n return false;\n }\n }\n\n // ── Artifact freshness via HTTP conditional requests ───\n\n async #checkArtifactFreshness(\n url: string,\n cached: { etag?: string; lastModified?: string },\n ): Promise<{ fresh: boolean; etag?: string; lastModified?: string }> {\n const hasValidators = Boolean(cached.etag || cached.lastModified);\n const headers: Record<string, string> = {};\n if (cached.etag) {\n headers[\"If-None-Match\"] = cached.etag;\n }\n if (cached.lastModified) {\n headers[\"If-Modified-Since\"] = cached.lastModified;\n }\n\n // HEAD avoids downloading the (potentially multi-MB) artifact body.\n // With conditional headers, the server returns 304 if unchanged or 200 (no body) if stale.\n let res = await globalThis.fetch(url, { method: \"HEAD\", headers });\n\n // Fallback to GET if HEAD is not supported (e.g. some CDN/WAF configs)\n if (res.status === 405) {\n res = await globalThis.fetch(url, { headers });\n }\n\n // Treat server errors as transient — throw so the outer catch applies fail-open with short retry.\n // Without this, a CDN 5xx would be misinterpreted as \"artifact changed\" and wipe the cache.\n if (!res.ok && res.status !== 304) {\n throw new Error(`Artifact freshness check failed: HEAD ${url} returned ${res.status}`);\n }\n\n const etag = res.headers.get(\"etag\") ?? undefined;\n const lastModified = res.headers.get(\"last-modified\") ?? undefined;\n\n if (res.status === 304) {\n return {\n fresh: true,\n etag: etag ?? cached.etag,\n lastModified: lastModified ?? cached.lastModified,\n };\n }\n\n if (!hasValidators) {\n // First revalidation — capture validators, treat as fresh\n return { fresh: true, etag, lastModified };\n }\n\n // 200 = artifact changed\n return { fresh: false, etag, lastModified };\n }\n\n // ── Internal helpers ────────────────────────────────────\n\n async #collectParamEntries(): Promise<\n Array<{ bits: number; key: string; data: CachedPublicParams }>\n > {\n // Merge in-memory keys with persisted index for cold-start CRS detection\n const idxKey = paramsIndexKey(this.#chainId);\n const persistedBits =\n (await this.#storage.get<number[]>(idxKey).catch((err) => {\n this.#logger.warn(\"Failed to read params index, CRS revalidation may be incomplete\", {\n chainId: this.#chainId,\n error: toError(err).message,\n });\n return null;\n })) ?? [];\n const allBits = new Set([...this.#publicParamsMem.keys(), ...persistedBits]);\n\n const bitsArray = Array.from(allBits);\n const results = await Promise.all(\n bitsArray.map(async (bits) => {\n const pKey = paramsStorageKey(this.#chainId, bits);\n // Separate storage read from validation so we only delete on corruption\n let raw: unknown;\n try {\n raw = await this.#storage.get(pKey);\n } catch (err) {\n this.#logger.warn(\"Failed to read cached params entry during revalidation\", {\n chainId: this.#chainId,\n bits,\n error: toError(err).message,\n });\n return null;\n }\n if (!raw) {\n return null;\n }\n try {\n assertCachedParams(raw);\n return {\n bits,\n key: pKey,\n data: {\n ...raw,\n lastValidatedAt: raw.lastValidatedAt ?? 0,\n } as CachedPublicParams,\n };\n } catch (err) {\n this.#logger.warn(\"Corrupt params cache entry detected, deleting\", {\n chainId: this.#chainId,\n bits,\n error: toError(err).message,\n });\n await this.#deleteQuietly(pKey);\n return null;\n }\n }),\n );\n return results.filter(\n (e): e is { bits: number; key: string; data: CachedPublicParams } => e !== null,\n );\n }\n\n async #deleteQuietly(key: string): Promise<void> {\n await this.#storage.delete(key).catch((err) => {\n this.#logger.warn(\"Failed to delete cache entry\", {\n chainId: this.#chainId,\n key,\n error: toError(err).message,\n });\n });\n }\n\n async #clearAll(pkKey: string, paramEntries: Array<{ key: string }>): Promise<void> {\n const idxKey = paramsIndexKey(this.#chainId);\n // Delete from persistent storage first — if this fails, in-memory cache\n // still serves stale data, but the next revalidation cycle will retry.\n try {\n await Promise.all([\n this.#storage.delete(pkKey),\n this.#storage.delete(idxKey),\n ...paramEntries.map((entry) => this.#storage.delete(entry.key)),\n ]);\n } catch (err) {\n this.#logger.warn(\"Failed to clear stale artifacts from persistent storage\", {\n chainId: this.#chainId,\n error: toError(err).message,\n });\n }\n // Clear in-memory after storage to avoid re-loading stale entries on failure\n this.#publicKeyMem = undefined;\n this.#publicParamsMem.clear();\n }\n\n async #writeEntries(\n pkKey: string,\n pk: CachedPublicKey,\n paramEntries: Array<{ key: string; data: CachedPublicParams }>,\n ): Promise<void> {\n const writes = [\n this.#storage.set(pkKey, pk).catch((err) => {\n this.#logger.warn(\"Failed to update public key validation timestamp\", {\n chainId: this.#chainId,\n error: toError(err).message,\n });\n }),\n ...paramEntries.map((entry) =>\n this.#storage.set(entry.key, entry.data).catch((err) => {\n this.#logger.warn(\"Failed to update params validation timestamp\", {\n chainId: this.#chainId,\n error: toError(err).message,\n });\n }),\n ),\n ];\n await Promise.all(writes);\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 { getAddress, type Address } from \"viem\";\nimport type { ClearValueType, Handle } from \"./relayer/relayer-sdk.types\";\nimport type { GenericStorage } from \"./types\";\n\n/**\n * Storage-backed cache for decrypted FHE plaintext values.\n *\n * Each entry is keyed by `(requester, contractAddress, handle)` so that\n * different signers cannot read each other's cached decryptions — this\n * mirrors the on-chain ACL where only the handle owner (or delegate) is\n * authorized to decrypt.\n *\n * Addresses are checksummed and handles lowercased, making lookups\n * case-insensitive. A separate index (`zama:decrypt:keys`) tracks all\n * stored cache keys so {@link clearForRequester} and {@link clearAll} can\n * enumerate entries without a full storage scan. Index writes are\n * serialised through a micro-queue to prevent concurrent `set` calls\n * from losing entries.\n *\n * All public methods are **best-effort**: storage errors are caught and\n * swallowed — the cache never throws.\n *\n * Cache storage key format:\n * ```\n * zama:decrypt:{checksumAddress}:{checksumAddress}:{lowercaseHandle}\n * ```\n *\n * Lifecycle:\n * - Populated by {@link ZamaSDK.decrypt} after relayer calls.\n * - Cleared by {@link ZamaSDK.revoke} / {@link ZamaSDK.revokeSession} (per-requester).\n * - Cleared by signer lifecycle events (disconnect, account change, chain change).\n * - Survives page reloads when backed by persistent storage (e.g. IndexedDB).\n */\nexport class DecryptCache {\n readonly #storage: GenericStorage;\n readonly #decryptNamespace = \"zama:decrypt\";\n readonly #decryptKeysNamespace = `${this.#decryptNamespace}:keys`;\n /** Serialises concurrent writes to the keys index. */\n #indexWriteQueue: Promise<void> = Promise.resolve();\n\n constructor(storage: GenericStorage) {\n this.#storage = storage;\n }\n\n /** Returns the cached clear value or `null` on a miss / error. */\n async get(\n requester: Address,\n contractAddress: Address,\n handle: Handle,\n ): Promise<ClearValueType | null> {\n try {\n const key = this.#buildStorageKey(requester, contractAddress, handle);\n return await this.#storage.get<ClearValueType>(key);\n } catch (error) {\n console.warn(\"[zama-sdk] DecryptCache.get failed:\", error); // eslint-disable-line no-console\n return null;\n }\n }\n\n /** Stores `value` for the given `(requester, contractAddress, handle)` tuple. */\n async set(\n requester: Address,\n contractAddress: Address,\n handle: Handle,\n value: ClearValueType,\n ): Promise<void> {\n try {\n const key = this.#buildStorageKey(requester, contractAddress, handle);\n await this.#storage.set<ClearValueType>(key, value);\n // Track the key in the index (serialised to avoid concurrent overwrites)\n this.#indexWriteQueue = this.#indexWriteQueue.then(() =>\n this.#addToIndex(key).catch((error) => {\n console.warn(\"[zama-sdk] DecryptCache index write failed:\", error); // eslint-disable-line no-console\n }),\n );\n await this.#indexWriteQueue;\n } catch (error) {\n console.warn(\"[zama-sdk] DecryptCache.set failed:\", error); // eslint-disable-line no-console\n }\n }\n\n /** Removes all cached entries for the given `requester`. */\n async clearForRequester(requester: Address): Promise<void> {\n // Serialise with the index write queue to avoid racing with concurrent set() calls\n this.#indexWriteQueue = this.#indexWriteQueue.then(() =>\n this.#doClearForRequester(requester).catch((error) => {\n console.warn(\"[zama-sdk] DecryptCache.clearForRequester failed:\", error); // eslint-disable-line no-console\n }),\n );\n await this.#indexWriteQueue;\n }\n\n async #doClearForRequester(requester: Address): Promise<void> {\n const checksumRequester = getAddress(requester);\n const prefix = `${this.#decryptNamespace}:${checksumRequester}:`;\n const keys = await this.#readIndex();\n const toRemove: string[] = [];\n const remaining: string[] = [];\n for (const k of keys) {\n if (k.startsWith(prefix)) {\n toRemove.push(k);\n } else {\n remaining.push(k);\n }\n }\n await Promise.all(toRemove.map((k) => this.#storage.delete(k).catch(() => {})));\n await this.#storage.set(this.#decryptKeysNamespace, remaining);\n }\n\n /** Removes all cached entries. */\n async clearAll(): Promise<void> {\n // Serialise with the index write queue to avoid racing with concurrent set() calls\n this.#indexWriteQueue = this.#indexWriteQueue.then(() =>\n this.#doClearAll().catch((error) => {\n console.warn(\"[zama-sdk] DecryptCache.clearAll failed:\", error); // eslint-disable-line no-console\n }),\n );\n await this.#indexWriteQueue;\n }\n\n async #doClearAll(): Promise<void> {\n const keys = await this.#readIndex();\n await Promise.all(keys.map((k) => this.#storage.delete(k).catch(() => {})));\n await this.#storage.delete(this.#decryptKeysNamespace);\n }\n\n #buildStorageKey(requester: Address, contractAddress: Address, handle: Handle): string {\n return `${this.#decryptNamespace}:${getAddress(requester)}:${getAddress(contractAddress)}:${handle.toLowerCase()}`;\n }\n\n async #readIndex(): Promise<string[]> {\n return (await this.#storage.get<string[]>(this.#decryptKeysNamespace)) ?? [];\n }\n\n async #addToIndex(key: string): Promise<void> {\n const keys = await this.#readIndex();\n if (!keys.includes(key)) {\n keys.push(key);\n await this.#storage.set(this.#decryptKeysNamespace, keys);\n }\n }\n}\n","import type { GenericStorage } from \"../types\";\n\n/** In-memory credential store. Credentials are lost on page reload. */\nexport class MemoryStorage implements GenericStorage {\n #map = new Map<string, unknown>();\n\n async get<T = unknown>(key: string): Promise<T | null> {\n return (this.#map.get(key) as T) ?? null;\n }\n\n async set<T = unknown>(key: string, value: T): Promise<void> {\n this.#map.set(key, value);\n }\n\n async delete(key: string): Promise<void> {\n this.#map.delete(key);\n }\n}\n\n/** Default singleton for application-wide use. */\nexport const memoryStorage = new MemoryStorage();\n","import type { Address, Hex } from \"viem\";\nimport { prefixHex } from \"../utils\";\n\n/** Encrypted data format with IV for AES-GCM decryption. */\nexport interface EncryptedData {\n /** Base64-encoded initialization vector. */\n iv: string;\n /** Base64-encoded ciphertext. */\n ciphertext: string;\n}\n\n/**\n * Manages AES-GCM encryption and decryption of FHE private keys.\n *\n * The encryption key is derived from a wallet signature via PBKDF2\n * (600 000 iterations, SHA-256). The signature is a secret known only\n * to the wallet holder, providing meaningful encryption protection\n * for the stored private key.\n *\n * The derived key is cached internally so that repeated encrypt/decrypt\n * calls with the same (signature, address) pair skip the expensive\n * PBKDF2 derivation.\n */\nexport class CredentialCrypto {\n #cachedDerivedKey: CryptoKey | null = null;\n #cachedDerivedKeyIdentity: string | null = null;\n\n /** Clear the cached derived key. Call when the session is revoked or the signer changes. */\n clearCache(): void {\n this.#cachedDerivedKey = null;\n this.#cachedDerivedKeyIdentity = null;\n }\n\n /** Encrypt an FHE private key using AES-GCM with a key derived from the wallet signature. */\n async encrypt(plaintext: Hex, signature: Hex, address: Address): Promise<EncryptedData> {\n const key = await this.#deriveKey(signature, address);\n const iv = crypto.getRandomValues(new Uint8Array(12));\n const encoder = new TextEncoder();\n\n const ciphertext = await crypto.subtle.encrypt(\n { name: \"AES-GCM\", iv },\n key,\n encoder.encode(plaintext),\n );\n\n return {\n iv: btoa(String.fromCharCode(...iv)),\n ciphertext: btoa(String.fromCharCode(...new Uint8Array(ciphertext))),\n };\n }\n\n /** Decrypt an AES-GCM encrypted FHE private key using a key derived from the wallet signature. */\n async decrypt(encrypted: EncryptedData, signature: Hex, address: Address): Promise<Hex> {\n const key = await this.#deriveKey(signature, address);\n const iv = Uint8Array.from(atob(encrypted.iv), (c) => c.charCodeAt(0));\n const ciphertext = Uint8Array.from(atob(encrypted.ciphertext), (c) => c.charCodeAt(0));\n\n const plaintext = await crypto.subtle.decrypt({ name: \"AES-GCM\", iv }, key, ciphertext);\n\n return prefixHex(new TextDecoder().decode(plaintext));\n }\n\n async #deriveKey(signature: Hex, address: Address): Promise<CryptoKey> {\n const identity = `${signature}:${address}`;\n if (this.#cachedDerivedKey && this.#cachedDerivedKeyIdentity === identity) {\n return this.#cachedDerivedKey;\n }\n\n const encoder = new TextEncoder();\n const keyMaterial = await crypto.subtle.importKey(\n \"raw\",\n encoder.encode(signature),\n \"PBKDF2\",\n false,\n [\"deriveKey\"],\n );\n\n const key = await crypto.subtle.deriveKey(\n {\n name: \"PBKDF2\",\n salt: encoder.encode(address),\n iterations: 600_000,\n hash: \"SHA-256\",\n },\n keyMaterial,\n { name: \"AES-GCM\", length: 256 },\n false,\n [\"encrypt\", \"decrypt\"],\n );\n\n this.#cachedDerivedKeyIdentity = identity;\n this.#cachedDerivedKey = key;\n return key;\n }\n}\n","import { getAddress, isAddress, type Address, type Hex } from \"viem\";\nimport { assertArray, assertCondition, assertObject, assertString } from \"../utils\";\nimport type { EncryptedData } from \"./credential-crypto\";\n\n/** Encrypted credential shape stored in persistent storage (shared base fields). */\nexport interface BaseEncryptedCredentials {\n publicKey: Hex;\n contractAddresses: Address[];\n encryptedPrivateKey: EncryptedData;\n startTimestamp: number;\n durationDays: number;\n}\n\n/**\n * Assert that `data` contains the base encrypted credential fields:\n * publicKey, contractAddresses (valid hex addresses), and encryptedPrivateKey (iv + ciphertext).\n */\nexport function assertBaseEncryptedCredentials(\n data: unknown,\n): asserts data is BaseEncryptedCredentials {\n assertObject(data, \"Stored credentials\");\n assertString(data.publicKey, \"credentials.publicKey\");\n assertArray(data.contractAddresses, \"credentials.contractAddresses\");\n for (const addr of data.contractAddresses) {\n assertCondition(\n typeof addr === \"string\" && isAddress(addr, { strict: false }),\n `Expected each contractAddress to be a valid hex address`,\n );\n }\n assertObject(data.encryptedPrivateKey, \"credentials.encryptedPrivateKey\");\n assertString(data.encryptedPrivateKey.iv, \"encryptedPrivateKey.iv\");\n assertString(data.encryptedPrivateKey.ciphertext, \"encryptedPrivateKey.ciphertext\");\n assertCondition(\n typeof data.startTimestamp === \"number\",\n \"Expected credentials.startTimestamp to be a number\",\n );\n assertCondition(\n typeof data.durationDays === \"number\",\n \"Expected credentials.durationDays to be a number\",\n );\n}\n\n/**\n * Assert that `data` contains the delegated-specific fields:\n * delegatorAddress, delegateAddress (valid addresses), startTimestamp and durationDays (numbers).\n */\nexport function assertDelegatedFields(data: unknown): asserts data is BaseEncryptedCredentials & {\n delegatorAddress: Address;\n delegateAddress: Address;\n} {\n assertBaseEncryptedCredentials(data);\n const obj = data as unknown as Record<string, unknown>;\n assertCondition(\n typeof obj.delegatorAddress === \"string\" && isAddress(obj.delegatorAddress, { strict: false }),\n \"Expected credentials.delegatorAddress to be a valid address\",\n );\n assertCondition(\n typeof obj.delegateAddress === \"string\" && isAddress(obj.delegateAddress, { strict: false }),\n \"Expected credentials.delegateAddress to be a valid address\",\n );\n assertCondition(typeof obj.startTimestamp === \"number\", \"Expected startTimestamp to be a number\");\n assertCondition(typeof obj.durationDays === \"number\", \"Expected durationDays to be a number\");\n}\n\n/** Check if credentials are still within their keypair TTL. */\nexport function isTimeValid(creds: { startTimestamp: number; durationDays: number }): boolean {\n const nowSeconds = Math.floor(Date.now() / 1000);\n const expiresAt = creds.startTimestamp + creds.durationDays * 86400;\n return nowSeconds < expiresAt;\n}\n\n/** Check if the signed address set covers all required addresses. */\nexport function coversContracts(signedAddresses: Address[], requiredContracts: Address[]): boolean {\n const required = new Set(requiredContracts.map((address) => getAddress(address)));\n const signed = new Set(signedAddresses.map((address) => getAddress(address)));\n return required.isSubsetOf(signed);\n}\n\n/**\n * Check if credentials are valid: not time-expired and covering all required contracts.\n */\nexport function isCredentialValid(\n creds: { startTimestamp: number; durationDays: number; contractAddresses: Address[] },\n requiredContracts: Address[],\n): boolean {\n if (!isTimeValid(creds)) {\n return false;\n }\n return coversContracts(creds.contractAddresses, requiredContracts);\n}\n\n/** Deduplicate and sort a list of addresses by their checksummed form. */\nexport function normalizeAddresses(addresses: Address[]): Address[] {\n return [...new Set(addresses.map((address) => getAddress(address)))].toSorted();\n}\n\n/** Compute a truncated SHA-256 store key from arbitrary identity segments. */\nexport async function computeStoreKey(...segments: (string | number)[]): Promise<string> {\n const hash = await crypto.subtle.digest(\n \"SHA-256\",\n new TextEncoder().encode(segments.map(String).join(\":\")),\n );\n return Array.from(new Uint8Array(hash))\n .map((b) => b.toString(16).padStart(2, \"0\"))\n .join(\"\")\n .slice(0, 32);\n}\n","import type { Hex } from \"viem\";\nimport { assertCondition, assertObject, assertString } from \"../utils\";\nimport type { GenericStorage } from \"../types\";\n\n/** Structured session entry stored in session storage. */\nexport interface SessionEntry {\n /** EIP-712 wallet signature authorizing decryption. */\n signature: Hex;\n /** Epoch seconds when the session was created. */\n createdAt: number;\n /** TTL at creation time (not current config). `0` = always expired, `\"infinite\"` = never expires. */\n ttl: number | \"infinite\";\n}\n\n/**\n * Manages session signature entries in a {@link GenericStorage} backend.\n *\n * A session entry caches a wallet signature so that subsequent decrypt\n * operations can reuse it without prompting the user again. The TTL\n * is recorded at creation time so that changing the config later does\n * not retroactively extend or shorten existing sessions.\n */\nexport class SessionSignatures {\n #storage: GenericStorage;\n\n constructor(storage: GenericStorage) {\n this.#storage = storage;\n }\n\n #assertSessionEntry(data: unknown): asserts data is SessionEntry {\n assertObject(data, \"Session entry\");\n assertString(data.signature, \"session.signature\");\n assertCondition(\n typeof data.createdAt === \"number\",\n `Expected session.createdAt to be a number`,\n );\n assertCondition(\n typeof data.ttl === \"number\" || data.ttl === \"infinite\",\n `Expected session.ttl to be a number or \"infinite\"`,\n );\n }\n\n /** Retrieve and validate a session entry, or `null` if none exists. */\n async get(key: string): Promise<SessionEntry | null> {\n const raw = await this.#storage.get<SessionEntry>(key);\n if (raw === null) {\n return null;\n }\n this.#assertSessionEntry(raw);\n return raw;\n }\n\n /** Create and store a session entry with the given TTL. */\n async set(params: { key: string; signature: Hex; ttl: number | \"infinite\" }): Promise<void> {\n const entry: SessionEntry = {\n signature: params.signature,\n createdAt: Math.floor(Date.now() / 1000),\n ttl: params.ttl,\n };\n await this.#storage.set(params.key, entry);\n }\n\n /** Delete a session entry. */\n async delete(key: string): Promise<void> {\n await this.#storage.delete(key);\n }\n\n /**\n * Check if a session entry has expired based on its recorded TTL.\n * - `0` = always expired (every operation triggers a signing prompt).\n * - `\"infinite\"` = never expires.\n * - Positive number = seconds until expiration.\n */\n isExpired(entry: SessionEntry): boolean {\n if (entry.ttl === \"infinite\") {\n return false;\n }\n if (entry.ttl === 0) {\n return true;\n }\n return Math.floor(Date.now() / 1000) - entry.createdAt >= entry.ttl;\n }\n}\n","import type { Address, Hex } from \"viem\";\nimport { ZamaError } from \"../errors/base\";\nimport { wrapSigningError } from \"../errors/signing\";\nimport type { ZamaSDKEventInput, ZamaSDKEventListener } from \"../events/sdk-events\";\nimport { ZamaSDKEvents } from \"../events/sdk-events\";\nimport type { GenericSigner, GenericStorage, StoredCredentials } from \"../types\";\nimport { toError } from \"../utils/error\";\nimport { CredentialCrypto } from \"./credential-crypto\";\nimport type { BaseEncryptedCredentials } from \"./credential-validation\";\nimport {\n coversContracts,\n isCredentialValid,\n isTimeValid,\n normalizeAddresses,\n} from \"./credential-validation\";\nimport { SessionSignatures } from \"./session-signatures\";\n\n/** Shared configuration accepted by both credential manager variants. */\nexport interface CredentialsConfig {\n /** Backend that generates FHE keypairs (public/private). */\n relayer: { generateKeypair(): Promise<{ publicKey: Hex; privateKey: Hex }> };\n /** Wallet signer used for EIP-712 authorization signatures. */\n signer: GenericSigner;\n /** Persistent storage for encrypted credentials. */\n storage: GenericStorage;\n /** Storage for session signatures (shorter-lived than credentials). */\n sessionStorage: GenericStorage;\n /** FHE keypair lifetime in seconds. Defaults to `2592000` (30 days). */\n keypairTTL?: number;\n /** Session signature lifetime. `0` = always re-sign, `\"infinite\"` = never expire. Defaults to `2592000` (30 days). */\n sessionTTL?: number | \"infinite\";\n /** Optional listener for credential lifecycle events. */\n onEvent?: ZamaSDKEventListener;\n}\n\n/** Minimal fields needed to produce an EIP-712 signing request. */\nexport interface SigningMeta {\n /** FHE public key being authorized. */\n publicKey: Hex;\n /** Epoch seconds when the keypair authorization begins. */\n startTimestamp: number;\n /** Number of days the keypair authorization is valid for. */\n durationDays: number;\n /** Delegator address, present only for delegated credentials. */\n delegatorAddress?: string;\n}\n\n/** Options for {@link BaseCredentialsManager.resolveCredentials}. */\ninterface ResolveCredentialsOptions<TCreds> {\n /** Storage key identifying the credential entry. */\n key: string;\n /** Contract addresses the caller needs access to. */\n contracts: Address[];\n /** Deduplication key — concurrent calls with the same key share a single creation promise. */\n createKey: string;\n /** Factory that creates fresh credentials when nothing usable is cached. */\n createFn: () => Promise<TCreds>;\n}\n\n/** Options for {@link BaseCredentialsManager.createCredentials}. */\ninterface CreateCredentialsOptions<TCreds> {\n /** Storage key identifying the credential entry. */\n key: string;\n /** Contract addresses being authorized. */\n contractAddresses: Address[];\n /** Factory that builds the credential payload (keypair + signature). */\n createFn: () => Promise<TCreds>;\n /** Human-readable context included in signing error messages. */\n errorContext: string;\n}\n\n/**\n * Abstract base for credential managers. Contains the entire allow/extend/expire\n * state machine. Subclasses provide the assertion, signing, and encrypt/decrypt\n * hooks that differ between regular and delegated flows.\n *\n * @typeParam TCreds - The in-memory credential shape (includes plaintext privateKey).\n * @typeParam TEncrypted - The on-disk shape (privateKey replaced by encryptedPrivateKey).\n */\nexport abstract class BaseCredentialsManager<\n TCreds extends StoredCredentials,\n TEncrypted extends BaseEncryptedCredentials,\n> {\n protected readonly signer: GenericSigner;\n protected readonly storage: GenericStorage;\n protected readonly sessionSignatures: SessionSignatures;\n protected readonly crypto: CredentialCrypto;\n readonly keypairTTL: number;\n readonly sessionTTL: number | \"infinite\";\n\n #onEvent: ZamaSDKEventListener;\n #createPromise: Promise<TCreds> | null = null;\n #createPromiseKey: string | null = null;\n #extendPromise: Promise<TCreds> | null = null;\n /** Last successfully resolved extension result, used to recover from the race where a\n * concurrent call enters #extendContracts after #extendPromise was already cleared. */\n #lastExtendResult: TCreds | null = null;\n\n constructor(config: CredentialsConfig) {\n this.signer = config.signer;\n this.storage = config.storage;\n this.sessionSignatures = new SessionSignatures(config.sessionStorage);\n this.crypto = new CredentialCrypto();\n this.keypairTTL = config.keypairTTL ?? 2592000;\n this.sessionTTL = config.sessionTTL ?? 2592000;\n this.#onEvent = config.onEvent ?? (() => {});\n\n if (typeof this.keypairTTL === \"number\" && this.keypairTTL < 0) {\n throw new Error(\"keypairTTL must be >= 0\");\n }\n if (typeof this.sessionTTL === \"number\" && this.sessionTTL < 0) {\n throw new Error(\"sessionTTL must be >= 0\");\n }\n if (typeof this.sessionTTL === \"number\" && this.sessionTTL > this.keypairTTL) {\n this.sessionTTL = this.keypairTTL;\n // oxlint-disable-next-line no-console\n console.warn(\n `[zama-sdk] sessionTTL was clamped to keypairTTL (${this.keypairTTL}s). ` +\n \"A session that outlives the keypair causes isAllowed() to return true \" +\n \"after the keypair expires, leading to unexpected wallet prompts.\",\n );\n }\n }\n\n /** Emit a credential lifecycle event, stamped with the current time. */\n protected emit(partial: ZamaSDKEventInput): void {\n this.#onEvent({ ...partial, timestamp: Date.now() } as never);\n }\n\n // ── Abstract hooks ────────────────────────────────────────────\n\n /** Validate that raw storage data matches the expected encrypted shape. */\n protected abstract assertEncrypted(data: unknown): asserts data is TEncrypted;\n\n /** Sign an EIP-712 authorization for the given contract addresses. */\n protected abstract signForContracts(\n meta: SigningMeta,\n contractAddresses: Address[],\n ): Promise<Hex>;\n\n /** Encrypt credentials for persistent storage. */\n protected abstract encryptCredentials(creds: TCreds): Promise<TEncrypted>;\n\n /** Decrypt credentials from persistent storage. */\n protected abstract decryptCredentials(encrypted: TEncrypted, signature: Hex): Promise<TCreds>;\n\n // ── Core credential resolution ────────────────────────────────\n\n /**\n * The allow() state machine: load → validate → extend/re-sign → or create fresh.\n * Subclasses call this from their public `allow()` after computing the key.\n */\n protected async resolveCredentials({\n key,\n contracts,\n createKey,\n createFn,\n }: ResolveCredentialsOptions<TCreds>): Promise<TCreds> {\n this.emit({\n type: ZamaSDKEvents.CredentialsLoading,\n contractAddresses: contracts,\n });\n\n try {\n const encrypted = await this.storage.get<TEncrypted>(key);\n if (encrypted) {\n this.assertEncrypted(encrypted);\n\n const sessionEntry = await this.sessionSignatures.get(key);\n if (sessionEntry) {\n if (this.sessionSignatures.isExpired(sessionEntry)) {\n await this.sessionSignatures.delete(key);\n this.emit({ type: ZamaSDKEvents.SessionExpired, reason: \"ttl\" });\n } else {\n const creds = await this.decryptCredentials(encrypted, sessionEntry.signature);\n if (isCredentialValid(creds, contracts)) {\n this.emit({\n type: ZamaSDKEvents.CredentialsCached,\n contractAddresses: contracts,\n });\n this.emit({\n type: ZamaSDKEvents.CredentialsAllowed,\n contractAddresses: contracts,\n });\n return creds;\n }\n if (isTimeValid(creds)) {\n return this.#extendContracts({\n key,\n credentials: creds,\n requiredContracts: contracts,\n });\n }\n this.emit({\n type: ZamaSDKEvents.CredentialsExpired,\n contractAddresses: contracts,\n });\n }\n }\n\n // No session or expired — need to re-sign\n if (isTimeValid(encrypted)) {\n if (coversContracts(encrypted.contractAddresses, contracts)) {\n const signature = await this.signForContracts(encrypted, encrypted.contractAddresses);\n await this.sessionSignatures.set({\n key,\n signature,\n ttl: this.sessionTTL,\n });\n const creds = await this.decryptCredentials(encrypted, signature);\n this.emit({\n type: ZamaSDKEvents.CredentialsCached,\n contractAddresses: contracts,\n });\n this.emit({\n type: ZamaSDKEvents.CredentialsAllowed,\n contractAddresses: contracts,\n });\n return creds;\n }\n // Time-valid but missing contracts — sign with old set to decrypt, then extend\n const oldSignature = await this.signForContracts(encrypted, encrypted.contractAddresses);\n const creds = await this.decryptCredentials(encrypted, oldSignature);\n return this.#extendContracts({\n key,\n credentials: creds,\n requiredContracts: contracts,\n });\n }\n\n this.emit({\n type: ZamaSDKEvents.CredentialsExpired,\n contractAddresses: contracts,\n });\n }\n } catch (error) {\n if (error instanceof ZamaError) {\n throw error;\n }\n // oxlint-disable-next-line no-console\n console.warn(\"[zama-sdk] Credential resolution failed, recreating:\", error);\n this.emit({\n type: ZamaSDKEvents.CredentialsCorrupted,\n error: toError(error),\n });\n await this.#deleteCredentials(key);\n }\n\n // Nothing cached — create fresh (deduplicated)\n if (!this.#createPromise || this.#createPromiseKey !== createKey) {\n this.#createPromiseKey = createKey;\n this.#createPromise = createFn()\n .then((creds) => {\n this.emit({\n type: ZamaSDKEvents.CredentialsAllowed,\n contractAddresses: contracts,\n });\n return creds;\n })\n .finally(() => {\n this.#createPromise = null;\n this.#createPromiseKey = null;\n });\n }\n return this.#createPromise;\n }\n\n // ── Shared public method implementations ──────────────────────\n\n /**\n * Check whether stored credentials are expired or don't cover the given contract.\n * Returns `true` if stored credentials are expired or corrupted.\n * Returns `false` if no credentials exist yet.\n */\n protected async checkExpired(key: string, contractAddress?: Address): Promise<boolean> {\n try {\n const stored = await this.storage.get<TEncrypted>(key);\n if (!stored) {\n return false;\n }\n this.assertEncrypted(stored);\n const requiredContracts = contractAddress ? [contractAddress] : [];\n return !isCredentialValid(stored, requiredContracts);\n } catch (error) {\n // oxlint-disable-next-line no-console\n console.warn(\"[zama-sdk] isExpired check failed, treating as expired:\", error);\n return true;\n }\n }\n\n /** Delete the session signature and clear caches, forcing a fresh wallet signature on next use. */\n protected async revokeSession(key: string, contractAddresses?: Address[]): Promise<void> {\n await this.sessionSignatures.delete(key);\n this.clearCaches();\n this.emit({\n type: ZamaSDKEvents.CredentialsRevoked,\n ...(contractAddresses ? { contractAddresses } : {}),\n } as ZamaSDKEventInput);\n }\n\n protected async checkAllowed(\n key: string,\n contractAddresses: [Address, ...Address[]],\n ): Promise<boolean> {\n // Runtime guard: credentials are always contract-scoped,\n // so an empty contract list must never resolve to \"allowed\"\n // (the compile-time tuple type can be bypassed via casts).\n if (contractAddresses.length === 0) {\n return false;\n }\n const entry = await this.sessionSignatures.get(key);\n if (entry === null) {\n return false;\n }\n if (this.sessionSignatures.isExpired(entry)) {\n return false;\n }\n try {\n const stored = await this.storage.get<TEncrypted>(key);\n if (!stored) {\n return false;\n }\n this.assertEncrypted(stored);\n return isCredentialValid(stored, contractAddresses);\n } catch {\n return false;\n }\n }\n\n protected async clearAll(key: string): Promise<void> {\n await this.sessionSignatures.delete(key);\n this.clearCaches();\n await this.#deleteCredentials(key);\n }\n\n /** Override to also clear subclass-specific caches (e.g. key cache). */\n protected clearCaches(): void {\n this.crypto.clearCache();\n this.#lastExtendResult = null;\n }\n\n // ── Credential creation helper ────────────────────────────────\n\n /**\n * Shared wrapper for fresh credential creation:\n * emits events, persists, saves session, and wraps signing errors.\n */\n protected async createCredentials({\n key,\n contractAddresses,\n createFn,\n errorContext,\n }: CreateCredentialsOptions<TCreds>): Promise<TCreds> {\n this.emit({ type: ZamaSDKEvents.CredentialsCreating, contractAddresses });\n try {\n const creds = await createFn();\n await this.persistCredentials(key, creds);\n await this.sessionSignatures.set({\n key,\n signature: creds.signature,\n ttl: this.sessionTTL,\n });\n this.emit({ type: ZamaSDKEvents.CredentialsCreated, contractAddresses });\n return creds;\n } catch (error) {\n if (error instanceof ZamaError) {\n throw error;\n }\n return wrapSigningError(error, errorContext);\n }\n }\n\n // ── Contract extension ────────────────────────────────────────\n\n async #extendContracts({\n key,\n credentials,\n requiredContracts,\n }: {\n key: string;\n credentials: TCreds;\n requiredContracts: Address[];\n }): Promise<TCreds> {\n if (this.#extendPromise) {\n const previous = await this.#extendPromise;\n if (coversContracts(previous.contractAddresses, requiredContracts)) {\n this.emit({\n type: ZamaSDKEvents.CredentialsAllowed,\n contractAddresses: requiredContracts,\n });\n return previous;\n }\n credentials = previous;\n } else if (this.#lastExtendResult) {\n // A concurrent extension may have resolved and cleared #extendPromise before\n // this call entered. Use the last known result as the base to avoid dropping\n // contract addresses merged by the just-completed extension.\n const last = this.#lastExtendResult;\n if (coversContracts(last.contractAddresses, requiredContracts)) {\n this.emit({\n type: ZamaSDKEvents.CredentialsAllowed,\n contractAddresses: requiredContracts,\n });\n return last;\n }\n credentials = last;\n }\n\n const promise = this.#extendCredentials({\n key,\n credentials,\n requiredContracts,\n });\n this.#extendPromise = promise;\n try {\n const result = await promise;\n this.#lastExtendResult = result;\n return result;\n } finally {\n if (this.#extendPromise === promise) {\n this.#extendPromise = null;\n }\n }\n }\n\n async #extendCredentials({\n key,\n credentials,\n requiredContracts,\n }: {\n key: string;\n credentials: TCreds;\n requiredContracts: Address[];\n }): Promise<TCreds> {\n const merged = normalizeAddresses([...credentials.contractAddresses, ...requiredContracts]);\n const signature = await this.signForContracts(credentials, merged);\n\n const extended: TCreds = {\n ...credentials,\n contractAddresses: merged,\n signature,\n };\n // Persist ciphertext before session signature to prevent a window where a\n // concurrent reader sees the new signature but finds old ciphertext.\n await this.persistCredentials(key, extended);\n await this.sessionSignatures.set({\n key,\n signature,\n ttl: this.sessionTTL,\n });\n this.emit({\n type: ZamaSDKEvents.CredentialsAllowed,\n contractAddresses: requiredContracts,\n });\n return extended;\n }\n\n protected async persistCredentials(key: string, credentials: TCreds): Promise<void> {\n try {\n const encrypted = await this.encryptCredentials(credentials);\n await this.storage.set(key, encrypted);\n } catch (error) {\n // oxlint-disable-next-line no-console\n console.warn(\"[zama-sdk] Failed to encrypt credentials for persistence:\", error);\n this.emit({\n type: ZamaSDKEvents.CredentialsPersistFailed,\n error: toError(error),\n });\n }\n }\n\n async #deleteCredentials(key: string): Promise<void> {\n try {\n await this.storage.delete(key);\n } catch (error) {\n // oxlint-disable-next-line no-console\n console.warn(\"[zama-sdk] Failed to delete credentials:\", error);\n this.emit({\n type: ZamaSDKEvents.CredentialsPersistFailed,\n error: toError(error),\n });\n }\n }\n}\n","import { getAddress, type Address, type Hex } from \"viem\";\nimport type { RelayerSDK } from \"../relayer/relayer-sdk\";\nimport type { StoredCredentials } from \"../types\";\nimport { MemoryStorage } from \"../storage/memory-storage\";\nimport {\n BaseCredentialsManager,\n type CredentialsConfig,\n type SigningMeta,\n} from \"./credentials-manager-base\";\nimport {\n type BaseEncryptedCredentials,\n assertBaseEncryptedCredentials,\n normalizeAddresses,\n computeStoreKey,\n} from \"./credential-validation\";\n\n/** Internal storage shape — same as BaseEncryptedCredentials. */\ntype EncryptedCredentials = BaseEncryptedCredentials;\n\n/** Configuration for constructing a {@link CredentialsManager}. */\nexport interface CredentialsManagerConfig extends CredentialsConfig {\n /** FHE relayer backend for keypair generation and EIP-712 creation. */\n relayer: RelayerSDK;\n}\n\nfunction hasExtensionRuntimeId(value: unknown): value is { runtime: { id: string } } {\n if (typeof value !== \"object\" || value === null) {\n return false;\n }\n const runtime = Reflect.get(value, \"runtime\");\n if (typeof runtime !== \"object\" || runtime === null) {\n return false;\n }\n return typeof Reflect.get(runtime, \"id\") === \"string\";\n}\n\n/**\n * Manages FHE decrypt credentials for a single wallet.\n * Handles keypair generation, EIP-712 authorization signing, and\n * encrypted persistence scoped to a (wallet address, chain ID) pair.\n */\nexport class CredentialsManager extends BaseCredentialsManager<\n StoredCredentials,\n EncryptedCredentials\n> {\n #relayer: RelayerSDK;\n #cachedStoreKey: string | null = null;\n #cachedStoreKeyIdentity: string | null = null;\n\n /** Derive the deterministic storage key for a given wallet address and chain. */\n static async computeStoreKey(address: Address, chainId: number): Promise<string> {\n return computeStoreKey(getAddress(address), chainId);\n }\n\n constructor(config: CredentialsManagerConfig) {\n super(config);\n this.#relayer = config.relayer;\n\n // Warn when using in-memory session storage inside a Chrome extension context\n const chromeNamespace =\n typeof globalThis !== \"undefined\" ? Reflect.get(globalThis, \"chrome\") : undefined;\n if (hasExtensionRuntimeId(chromeNamespace) && config.sessionStorage instanceof MemoryStorage) {\n // oxlint-disable-next-line no-console\n console.warn(\n \"[zama-sdk] Detected Chrome extension context with in-memory session storage. \" +\n \"Session signatures will be lost on service worker restart and won't be shared across contexts. \" +\n \"Consider using chromeSessionStorage instead. \",\n );\n }\n }\n\n // ── Public API ────────────────────────────────────────────────\n\n /**\n * Authorize FHE credentials for one or more contract addresses.\n *\n * @throws {@link SigningRejectedError} if the user rejects the wallet signature prompt.\n * @throws {@link SigningFailedError} if the signing operation fails for any other reason.\n */\n async allow(...contractAddresses: Address[]): Promise<StoredCredentials> {\n const normalized = normalizeAddresses(contractAddresses);\n const key = await this.#storeKey();\n return this.resolveCredentials({\n key,\n contracts: normalized,\n createKey: normalized.join(\",\"),\n createFn: () => this.create(normalized),\n });\n }\n\n /** Check if stored credentials are expired or unusable. */\n async isExpired(contractAddress?: Address): Promise<boolean> {\n return this.checkExpired(await this.#storeKey(), contractAddress);\n }\n\n /** Revoke the session signature. Next decrypt requires a fresh wallet signature. */\n async revoke(...contractAddresses: Address[]): Promise<void> {\n await this.revokeSession(\n await this.#storeKey(),\n contractAddresses.length > 0 ? contractAddresses : undefined,\n );\n }\n\n /** Revoke the session signature for a pre-computed store key. */\n async revokeByKey(key: string): Promise<void> {\n await this.revokeSession(key);\n }\n\n /** Whether a session signature is currently cached and covers the given contracts. */\n async isAllowed(contractAddresses: [Address, ...Address[]]): Promise<boolean> {\n return this.checkAllowed(await this.#storeKey(), contractAddresses);\n }\n\n /** Delete stored credentials (best-effort). */\n async clear(): Promise<void> {\n await this.clearAll(await this.#storeKey());\n }\n\n /**\n * Generate a fresh FHE keypair, create an EIP-712 authorization, and\n * prompt the user to sign it.\n */\n async create(contractAddresses: Address[]): Promise<StoredCredentials> {\n const normalized = normalizeAddresses(contractAddresses);\n const key = await this.#storeKey();\n return this.createCredentials({\n key,\n contractAddresses: normalized,\n createFn: async () => {\n const keypair = await this.#relayer.generateKeypair();\n const startTimestamp = Math.floor(Date.now() / 1000);\n const durationDays = Math.ceil(this.keypairTTL / 86400);\n\n const eip712 = await this.#relayer.createEIP712(\n keypair.publicKey,\n normalized,\n startTimestamp,\n durationDays,\n );\n const signature = await this.signer.signTypedData(eip712);\n\n return {\n publicKey: keypair.publicKey,\n privateKey: keypair.privateKey,\n signature,\n contractAddresses: normalized,\n startTimestamp,\n durationDays,\n };\n },\n errorContext: \"Failed to create decrypt credentials\",\n });\n }\n\n // ── Abstract implementations ──────────────────────────────────\n\n protected assertEncrypted(data: unknown): asserts data is EncryptedCredentials {\n assertBaseEncryptedCredentials(data);\n }\n\n protected async signForContracts(meta: SigningMeta, contractAddresses: Address[]): Promise<Hex> {\n const eip712 = await this.#relayer.createEIP712(\n meta.publicKey,\n contractAddresses,\n meta.startTimestamp,\n meta.durationDays,\n );\n return this.signer.signTypedData(eip712);\n }\n\n protected async encryptCredentials(creds: StoredCredentials): Promise<EncryptedCredentials> {\n const address = await this.signer.getAddress();\n const encryptedPrivateKey = await this.crypto.encrypt(\n creds.privateKey,\n creds.signature,\n address,\n );\n const { privateKey: _, signature: _sig, ...rest } = creds;\n return { ...rest, encryptedPrivateKey };\n }\n\n protected async decryptCredentials(\n encrypted: EncryptedCredentials,\n signature: Hex,\n ): Promise<StoredCredentials> {\n const address = await this.signer.getAddress();\n const privateKey = await this.crypto.decrypt(encrypted.encryptedPrivateKey, signature, address);\n const { encryptedPrivateKey: _, ...rest } = encrypted;\n return { ...rest, privateKey, signature };\n }\n\n protected override clearCaches(): void {\n this.#cachedStoreKey = null;\n this.#cachedStoreKeyIdentity = null;\n super.clearCaches();\n }\n\n // ── Store key ─────────────────────────────────────────────────\n\n async #storeKey(): Promise<string> {\n const address = await this.signer.getAddress();\n const chainId = await this.signer.getChainId();\n const identity = `${getAddress(address)}:${chainId}`;\n if (this.#cachedStoreKey && this.#cachedStoreKeyIdentity === identity) {\n return this.#cachedStoreKey;\n }\n const key = await CredentialsManager.computeStoreKey(address, chainId);\n this.#cachedStoreKeyIdentity = identity;\n this.#cachedStoreKey = key;\n return key;\n }\n}\n","import { getAddress, type Address, type Hex } from \"viem\";\nimport type { RelayerSDK } from \"../relayer/relayer-sdk\";\nimport type { DelegatedStoredCredentials } from \"../types\";\nimport {\n BaseCredentialsManager,\n type CredentialsConfig,\n type SigningMeta,\n} from \"./credentials-manager-base\";\nimport {\n type BaseEncryptedCredentials,\n assertDelegatedFields,\n normalizeAddresses,\n computeStoreKey,\n} from \"./credential-validation\";\n\n/** Internal storage shape — base fields plus delegator/delegate addresses. */\ninterface EncryptedCredentials extends BaseEncryptedCredentials {\n delegatorAddress: Address;\n delegateAddress: Address;\n}\n\n/** Configuration for constructing a {@link DelegatedCredentialsManager}. */\nexport interface DelegatedCredentialsManagerConfig extends CredentialsConfig {\n /** FHE relayer backend for keypair generation and delegated EIP-712 creation. */\n relayer: RelayerSDK;\n}\n\n/** Signing metadata for delegated credentials, adding the delegator's address. */\nexport interface DelegatedSigningMeta extends SigningMeta {\n /** On-chain address of the account that delegated decryption rights. */\n delegatorAddress: Address;\n}\n\n/**\n * Manages FHE decrypt credentials for delegated decryption.\n * Scoped to a (delegate, delegator) pair.\n */\nexport class DelegatedCredentialsManager extends BaseCredentialsManager<\n DelegatedStoredCredentials,\n EncryptedCredentials\n> {\n #relayer: RelayerSDK;\n #cachedStoreKey: string | null = null;\n #cachedStoreKeyIdentity: string | null = null;\n\n /** Derive the deterministic storage key for a (delegate, delegator, chain) triple. */\n static async computeStoreKey(\n delegateAddress: Address,\n delegatorAddress: Address,\n chainId: number,\n ): Promise<string> {\n return computeStoreKey(getAddress(delegateAddress), getAddress(delegatorAddress), chainId);\n }\n\n constructor(config: DelegatedCredentialsManagerConfig) {\n super(config);\n this.#relayer = config.relayer;\n }\n\n // ── Public API ────────────────────────────────────────────────\n\n /**\n * Authorize FHE delegated credentials for one or more contract addresses.\n *\n * @throws {@link SigningRejectedError} if the user rejects the wallet signature prompt.\n * @throws {@link SigningFailedError} if the signing operation fails for any other reason.\n */\n async allow(\n delegatorAddress: Address,\n ...contractAddresses: Address[]\n ): Promise<DelegatedStoredCredentials> {\n const normalizedDelegator = getAddress(delegatorAddress);\n const normalized = normalizeAddresses(contractAddresses);\n const key = await this.#storeKey(normalizedDelegator);\n return this.resolveCredentials({\n key,\n contracts: normalized,\n createKey: `${normalizedDelegator}:${normalized.join(\",\")}`,\n createFn: () => this.#create(normalizedDelegator, normalized),\n });\n }\n\n /** Check if stored delegated credentials are expired or unusable. */\n async isExpired(delegatorAddress: Address, contractAddress?: Address): Promise<boolean> {\n return this.checkExpired(await this.#storeKey(getAddress(delegatorAddress)), contractAddress);\n }\n\n /** Revoke the session signature for a delegator. */\n async revoke(delegatorAddress: Address): Promise<void> {\n await this.revokeSession(await this.#storeKey(getAddress(delegatorAddress)));\n }\n\n /** Whether a session signature is currently cached and covers the given contracts. */\n async isAllowed(\n delegatorAddress: Address,\n contractAddresses: [Address, ...Address[]],\n ): Promise<boolean> {\n return this.checkAllowed(await this.#storeKey(getAddress(delegatorAddress)), contractAddresses);\n }\n\n /** Delete stored credentials for a delegator (best-effort). */\n async clear(delegatorAddress: Address): Promise<void> {\n await this.clearAll(await this.#storeKey(getAddress(delegatorAddress)));\n }\n\n // ── Credential creation ───────────────────────────────────────\n\n async #create(\n delegatorAddress: Address,\n contractAddresses: Address[],\n ): Promise<DelegatedStoredCredentials> {\n const key = await this.#storeKey(delegatorAddress);\n return this.createCredentials({\n key,\n contractAddresses,\n createFn: async () => {\n const keypair = await this.#relayer.generateKeypair();\n const delegateAddress = await this.signer.getAddress();\n const startTimestamp = Math.floor(Date.now() / 1000);\n const durationDays = Math.ceil(this.keypairTTL / 86400);\n\n const meta = {\n publicKey: keypair.publicKey,\n startTimestamp,\n durationDays,\n delegatorAddress,\n };\n const signature = await this.#signDelegated(meta, contractAddresses);\n\n return {\n publicKey: keypair.publicKey,\n privateKey: keypair.privateKey,\n signature,\n contractAddresses,\n startTimestamp,\n durationDays,\n delegatorAddress,\n delegateAddress,\n };\n },\n errorContext: \"Failed to create delegated decrypt credentials\",\n });\n }\n\n // ── Abstract implementations ──────────────────────────────────\n\n protected assertEncrypted(data: unknown): asserts data is EncryptedCredentials {\n assertDelegatedFields(data);\n }\n\n protected async signForContracts(\n meta: DelegatedSigningMeta,\n contractAddresses: Address[],\n ): Promise<Hex> {\n return this.#signDelegated(meta, contractAddresses);\n }\n\n protected async encryptCredentials(\n creds: DelegatedStoredCredentials,\n ): Promise<EncryptedCredentials> {\n const address = await this.signer.getAddress();\n const encryptedPrivateKey = await this.crypto.encrypt(\n creds.privateKey,\n creds.signature,\n address,\n );\n const { privateKey: _, signature: _sig, ...rest } = creds;\n return { ...rest, encryptedPrivateKey };\n }\n\n protected async decryptCredentials(\n encrypted: EncryptedCredentials,\n signature: Hex,\n ): Promise<DelegatedStoredCredentials> {\n const address = await this.signer.getAddress();\n const privateKey = await this.crypto.decrypt(encrypted.encryptedPrivateKey, signature, address);\n const { encryptedPrivateKey: _, ...rest } = encrypted;\n return { ...rest, privateKey, signature };\n }\n\n protected override clearCaches(): void {\n this.#cachedStoreKey = null;\n this.#cachedStoreKeyIdentity = null;\n super.clearCaches();\n }\n\n // ── Private helpers ───────────────────────────────────────────\n\n async #storeKey(delegatorAddress: Address): Promise<string> {\n const delegateAddress = await this.signer.getAddress();\n const chainId = await this.signer.getChainId();\n const identity = `${getAddress(delegateAddress)}:${getAddress(delegatorAddress)}:${chainId}`;\n if (this.#cachedStoreKey && this.#cachedStoreKeyIdentity === identity) {\n return this.#cachedStoreKey;\n }\n const key = await DelegatedCredentialsManager.computeStoreKey(\n delegateAddress,\n delegatorAddress,\n chainId,\n );\n this.#cachedStoreKeyIdentity = identity;\n this.#cachedStoreKey = key;\n return key;\n }\n\n async #signDelegated(meta: DelegatedSigningMeta, contractAddresses: Address[]): Promise<Hex> {\n const delegatedEIP712 = await this.#relayer.createDelegatedUserDecryptEIP712(\n meta.publicKey,\n contractAddresses,\n meta.delegatorAddress,\n meta.startTimestamp,\n meta.durationDays,\n );\n return this.signer.signTypedData({\n domain: {\n ...delegatedEIP712.domain,\n chainId: Number(delegatedEIP712.domain.chainId),\n },\n types: delegatedEIP712.types,\n message: {\n ...delegatedEIP712.message,\n startTimestamp: BigInt(delegatedEIP712.message.startTimestamp),\n durationDays: BigInt(delegatedEIP712.message.durationDays),\n },\n });\n }\n}\n","/**\n * Framework-agnostic event decoders for confidential token contracts.\n * Works with raw log data from any provider.\n */\n\nimport type { Handle } from \"../relayer/relayer-sdk.types\";\nimport { getAddress, keccak256, toBytes, type Address, type Hex } from \"viem\";\nimport { prefixHex } from \"../utils\";\nimport type { RawLog } from \"../types/transaction\";\nexport type { RawLog } from \"../types/transaction\";\n\nfunction eventTopic(signature: string): Hex {\n return keccak256(toBytes(signature));\n}\n\n// ---------------------------------------------------------------------------\n// Event topic0 constants (keccak256 of canonical signature)\n// ---------------------------------------------------------------------------\n\n/**\n * Event topic0 constants (keccak256 of the canonical Solidity signature).\n * Pass to `getLogs({ topics: [Object.values(Topics)] })` to fetch all events.\n */\nexport const Topics = {\n /** `ConfidentialTransfer(address indexed from, address indexed to, bytes32 indexed amount)` */\n ConfidentialTransfer: eventTopic(\"ConfidentialTransfer(address,address,bytes32)\"),\n // NOTE: New wrapper contracts no longer emit Wrapped — shields now emit\n // ConfidentialTransfer(from=zeroAddress, ...) instead. Retained for backward\n // compatibility with older deployments.\n /** `Wrapped(address indexed to, uint256 amountIn)` */\n Wrapped: eventTopic(\"Wrapped(address,uint256)\"),\n /** `UnwrapRequested(address indexed receiver, bytes32 indexed unwrapRequestId, bytes32 amount)` */\n UnwrapRequested: eventTopic(\"UnwrapRequested(address,bytes32,bytes32)\"),\n /** `UnwrapFinalized(address indexed receiver, bytes32 indexed unwrapRequestId, bytes32 encryptedAmount, uint64 cleartextAmount)` */\n UnwrappedFinalized: eventTopic(\"UnwrapFinalized(address,bytes32,bytes32,uint64)\"),\n /** `UnwrappedStarted(bool returnVal, uint256 indexed requestId, ...)` */\n UnwrappedStarted: eventTopic(\n \"UnwrappedStarted(bool,uint256,uint256,address,address,bytes32,bytes32)\",\n ),\n} as const;\n\n// ---------------------------------------------------------------------------\n// Typed event interfaces\n// ---------------------------------------------------------------------------\n\n/** Decoded `ConfidentialTransfer` event — an encrypted token transfer. */\nexport interface ConfidentialTransferEvent {\n readonly eventName: \"ConfidentialTransfer\";\n /** Sender address. */\n readonly from: Address;\n /** Receiver address. */\n readonly to: Address;\n /** FHE ciphertext handle for the transferred amount. */\n readonly encryptedAmountHandle: Handle;\n}\n\n// NOTE: New wrapper contracts no longer emit this event — shields now emit\n// ConfidentialTransfer(from=zeroAddress, ...) instead. Retained for backward\n// compatibility with older deployments.\n/** Decoded `Wrapped` event — an ERC-20 shield (wrap) operation. */\nexport interface WrappedEvent {\n readonly eventName: \"Wrapped\";\n /** Receiver of the minted confidential tokens. */\n readonly to: Address;\n /** Underlying ERC-20 tokens deposited. */\n readonly amountIn: bigint;\n}\n\n/** Decoded `UnwrapRequested` event — an unshield request submitted. */\nexport interface UnwrapRequestedEvent {\n readonly eventName: \"UnwrapRequested\";\n /** Address that will receive the unwrapped ERC-20 tokens. */\n readonly receiver: Address;\n /** Unique identifier for this unwrap request (bytes32). */\n readonly unwrapRequestId: Hex;\n /** FHE ciphertext handle for the requested unshield amount. */\n readonly encryptedAmount: Handle;\n}\n\n/** Decoded `UnwrapFinalized` event — an unshield completed on-chain. */\nexport interface UnwrappedFinalizedEvent {\n readonly eventName: \"UnwrappedFinalized\";\n /** Address receiving the unwrapped ERC-20 tokens. */\n readonly receiver: Address;\n /** Unique identifier for this unwrap request (bytes32). */\n readonly unwrapRequestId: Hex;\n /** FHE ciphertext handle of the burnt confidential balance. */\n readonly encryptedAmount: Handle;\n /** Cleartext amount of underlying ERC-20 tokens returned. */\n readonly cleartextAmount: bigint;\n}\n\n/** Decoded `UnwrappedStarted` event — the relayer began processing an unshield. */\nexport interface UnwrappedStartedEvent {\n readonly eventName: \"UnwrappedStarted\";\n /** Whether the unwrap start succeeded. */\n readonly returnVal: boolean;\n /** On-chain request ID. */\n readonly requestId: bigint;\n /** On-chain transaction ID. */\n readonly txId: bigint;\n /** Receiver address. */\n readonly to: Address;\n /** Refund address (if applicable). */\n readonly refund: Address;\n /** FHE handle of the requested amount. */\n readonly requestedAmount: Handle;\n /** FHE handle of the burn amount. */\n readonly burnAmount: Handle;\n}\n\n/** Union of all decoded confidential token event types. */\nexport type OnChainEvent =\n | ConfidentialTransferEvent\n | WrappedEvent\n | UnwrapRequestedEvent\n | UnwrappedFinalizedEvent\n | UnwrappedStartedEvent;\n\n// ---------------------------------------------------------------------------\n// ABI decoding helpers (no external deps)\n// ---------------------------------------------------------------------------\n\nfunction topicToAddress(topic: Hex): Address {\n return getAddress(prefixHex(topic.slice(-40)));\n}\n\nfunction topicToBigInt(topic: Hex): bigint {\n return BigInt(topic);\n}\n\nfunction topicToBytes32(topic: Hex): Handle {\n // EVM topics are already 32-byte 0x-prefixed hex — cast directly\n return topic as Handle;\n}\n\nfunction wordAt(data: Hex, index: number): string {\n // data starts with \"0x\", each word is 64 hex chars (32 bytes)\n const start = 2 + index * 64;\n const word = data.slice(start, start + 64);\n return word.length === 64 ? word : word.padEnd(64, \"0\");\n}\n\nfunction wordToAddress(data: Hex, index: number): Address {\n return getAddress(prefixHex(wordAt(data, index).slice(-40)));\n}\n\nfunction wordToBigInt(data: Hex, index: number): bigint {\n return BigInt(\"0x\" + wordAt(data, index));\n}\n\nfunction wordToBool(data: Hex, index: number): boolean {\n return BigInt(\"0x\" + wordAt(data, index)) !== 0n;\n}\n\nfunction wordToBytes32(data: Hex, index: number): Handle {\n // wordAt returns exactly 64 hex chars — prefix and cast directly\n return prefixHex(wordAt(data, index)) as Handle;\n}\n\n// ---------------------------------------------------------------------------\n// Individual decoders\n// ---------------------------------------------------------------------------\n\n/**\n * ConfidentialTransfer(address indexed from, address indexed to, bytes32 indexed amount)\n * All 3 params indexed → topics[1..3], no data.\n */\nexport function decodeConfidentialTransfer(log: RawLog): ConfidentialTransferEvent | null {\n if (log.topics[0] !== Topics.ConfidentialTransfer) {\n return null;\n }\n if (log.topics.length < 4) {\n return null;\n }\n\n return {\n eventName: \"ConfidentialTransfer\",\n from: topicToAddress(log.topics[1]!),\n to: topicToAddress(log.topics[2]!),\n encryptedAmountHandle: topicToBytes32(log.topics[3]!),\n };\n}\n\n// NOTE: New wrapper contracts no longer emit this event. Retained for backward\n// compatibility with older deployments.\n/**\n * Wrapped(address indexed to, uint256 amountIn)\n * Indexed: to (topics[1])\n * Data: amountIn (uint256)\n */\nexport function decodeWrapped(log: RawLog): WrappedEvent | null {\n if (log.topics[0] !== Topics.Wrapped) {\n return null;\n }\n if (log.topics.length < 2) {\n return null;\n }\n\n return {\n eventName: \"Wrapped\",\n to: topicToAddress(log.topics[1]!),\n amountIn: wordToBigInt(log.data, 0),\n };\n}\n\n/**\n * UnwrapRequested(address indexed receiver, bytes32 indexed unwrapRequestId, bytes32 amount)\n * Indexed: receiver (topics[1]), unwrapRequestId (topics[2])\n * Data: amount (bytes32)\n */\nexport function decodeUnwrapRequested(log: RawLog): UnwrapRequestedEvent | null {\n if (log.topics[0] !== Topics.UnwrapRequested) {\n return null;\n }\n if (log.topics.length < 3) {\n return null;\n }\n\n return {\n eventName: \"UnwrapRequested\",\n receiver: topicToAddress(log.topics[1]!),\n unwrapRequestId: topicToBytes32(log.topics[2]!),\n encryptedAmount: wordToBytes32(log.data, 0),\n };\n}\n\n/**\n * UnwrapFinalized(address indexed receiver, bytes32 indexed unwrapRequestId, bytes32 encryptedAmount, uint64 cleartextAmount)\n * Indexed: receiver (topics[1]), unwrapRequestId (topics[2])\n * Data: encryptedAmount (bytes32 FHE handle, word 0), cleartextAmount (uint64, word 1)\n */\nexport function decodeUnwrappedFinalized(log: RawLog): UnwrappedFinalizedEvent | null {\n if (log.topics[0] !== Topics.UnwrappedFinalized) {\n return null;\n }\n if (log.topics.length < 3) {\n return null;\n }\n\n return {\n eventName: \"UnwrappedFinalized\",\n receiver: topicToAddress(log.topics[1]!),\n unwrapRequestId: topicToBytes32(log.topics[2]!),\n encryptedAmount: wordToBytes32(log.data, 0),\n cleartextAmount: wordToBigInt(log.data, 1),\n };\n}\n\n/**\n * UnwrappedStarted(bool returnVal, uint256 indexed requestId, uint256 indexed txId, address indexed to,\n * address refund, bytes32 requestedAmount, bytes32 burnAmount)\n * Indexed: requestId (topics[1]), txId (topics[2]), to (topics[3])\n * Data: returnVal, refund, requestedAmount, burnAmount\n */\nexport function decodeUnwrappedStarted(log: RawLog): UnwrappedStartedEvent | null {\n if (log.topics[0] !== Topics.UnwrappedStarted) {\n return null;\n }\n if (log.topics.length < 4) {\n return null;\n }\n\n return {\n eventName: \"UnwrappedStarted\",\n requestId: topicToBigInt(log.topics[1]!),\n txId: topicToBigInt(log.topics[2]!),\n to: topicToAddress(log.topics[3]!),\n returnVal: wordToBool(log.data, 0),\n refund: wordToAddress(log.data, 1),\n requestedAmount: wordToBytes32(log.data, 2),\n burnAmount: wordToBytes32(log.data, 3),\n };\n}\n\n// ---------------------------------------------------------------------------\n// Convenience helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Try all decoders on a single log and return the first match, or `null`.\n *\n * @example\n * ```ts\n * const event = decodeOnChainEvent(log);\n * if (event?.eventName === \"ConfidentialTransfer\") {\n * console.log(event.from, event.to);\n * }\n * ```\n */\nexport function decodeOnChainEvent(log: RawLog): OnChainEvent | null {\n return (\n decodeConfidentialTransfer(log) ??\n decodeWrapped(log) ??\n decodeUnwrapRequested(log) ??\n decodeUnwrappedFinalized(log) ??\n decodeUnwrappedStarted(log)\n );\n}\n\n/**\n * Batch-decode an array of logs, skipping unrecognized entries.\n *\n * @example\n * ```ts\n * const events = decodeOnChainEvents(receipt.logs);\n * ```\n */\nexport function decodeOnChainEvents(logs: readonly RawLog[]): OnChainEvent[] {\n const events: OnChainEvent[] = [];\n for (const log of logs) {\n const event = decodeOnChainEvent(log);\n if (event) {\n events.push(event);\n }\n }\n return events;\n}\n\n/**\n * Find the first {@link UnwrapRequestedEvent} in a logs array.\n *\n * @example\n * ```ts\n * const event = findUnwrapRequested(receipt.logs);\n * if (event) console.log(event.receiver, event.encryptedAmount);\n * ```\n */\nexport function findUnwrapRequested(logs: readonly RawLog[]): UnwrapRequestedEvent | null {\n for (const log of logs) {\n const event = decodeUnwrapRequested(log);\n if (event) {\n return event;\n }\n }\n return null;\n}\n\n// NOTE: New wrapper contracts no longer emit this event. Retained for backward\n// compatibility with older deployments.\n/**\n * Find the first {@link WrappedEvent} in a logs array.\n *\n * @example\n * ```ts\n * const event = findWrapped(receipt.logs);\n * if (event) console.log(event.to, event.amountIn);\n * ```\n */\nexport function findWrapped(logs: readonly RawLog[]): WrappedEvent | null {\n for (const log of logs) {\n const event = decodeWrapped(log);\n if (event) {\n return event;\n }\n }\n return null;\n}\n\n/**\n * All 5 confidential token event topic0 hashes.\n * Pass to `getLogs({ topics: [TOKEN_TOPICS] })` to fetch\n * all confidential token events in a single RPC call.\n */\nexport const TOKEN_TOPICS = [\n Topics.ConfidentialTransfer,\n Topics.Wrapped,\n Topics.UnwrapRequested,\n Topics.UnwrappedFinalized,\n Topics.UnwrappedStarted,\n] as const;\n\n// ---------------------------------------------------------------------------\n// ACL delegation event topic0 constants\n// ---------------------------------------------------------------------------\n\n/**\n * ACL delegation event topic0 constants (keccak256 of the canonical Solidity signature).\n * These are ACL events, NOT token events — they are emitted by the ACL contract.\n */\nexport const AclTopics = {\n /** `DelegatedForUserDecryption(address indexed delegator, address indexed delegate, address contractAddress, uint64 delegationCounter, uint64 oldExpirationDate, uint64 newExpirationDate)` */\n DelegatedForUserDecryption: eventTopic(\n \"DelegatedForUserDecryption(address,address,address,uint64,uint64,uint64)\",\n ),\n /** `RevokedDelegationForUserDecryption(address indexed delegator, address indexed delegate, address contractAddress, uint64 delegationCounter, uint64 oldExpirationDate)` */\n RevokedDelegationForUserDecryption: eventTopic(\n \"RevokedDelegationForUserDecryption(address,address,address,uint64,uint64)\",\n ),\n} as const;\n\n// ---------------------------------------------------------------------------\n// ACL delegation event interfaces\n// ---------------------------------------------------------------------------\n\n/** Decoded `DelegatedForUserDecryption` event — a delegation was created or renewed. */\nexport interface DelegatedForUserDecryptionEvent {\n readonly eventName: \"DelegatedForUserDecryption\";\n /** Address of the delegator (the account granting access). */\n readonly delegator: Address;\n /** Address of the delegate (the account receiving access). */\n readonly delegate: Address;\n /** Contract address the delegation applies to. */\n readonly contractAddress: Address;\n /** Monotonic delegation counter. */\n readonly delegationCounter: bigint;\n /** Previous expiration timestamp (0 if first delegation). */\n readonly oldExpirationDate: bigint;\n /** New expiration timestamp. */\n readonly newExpirationDate: bigint;\n}\n\n/** Decoded `RevokedDelegationForUserDecryption` event — a delegation was revoked. */\nexport interface RevokedDelegationForUserDecryptionEvent {\n readonly eventName: \"RevokedDelegationForUserDecryption\";\n /** Address of the delegator. */\n readonly delegator: Address;\n /** Address of the delegate. */\n readonly delegate: Address;\n /** Contract address the revocation applies to. */\n readonly contractAddress: Address;\n /** Monotonic delegation counter. */\n readonly delegationCounter: bigint;\n /** Expiration date that was active before revocation. */\n readonly oldExpirationDate: bigint;\n}\n\n/** Union of all decoded ACL delegation event types. */\nexport type AclEvent = DelegatedForUserDecryptionEvent | RevokedDelegationForUserDecryptionEvent;\n\n// ---------------------------------------------------------------------------\n// ACL delegation event decoders\n// ---------------------------------------------------------------------------\n\n/**\n * DelegatedForUserDecryption(address indexed delegator, address indexed delegate,\n * address contractAddress, uint64 delegationCounter, uint64 oldExpirationDate, uint64 newExpirationDate)\n * Indexed: delegator (topics[1]), delegate (topics[2])\n * Data: contractAddress, delegationCounter, oldExpirationDate, newExpirationDate\n */\nexport function decodeDelegatedForUserDecryption(\n log: RawLog,\n): DelegatedForUserDecryptionEvent | null {\n if (log.topics[0] !== AclTopics.DelegatedForUserDecryption) {\n return null;\n }\n if (log.topics.length < 3) {\n return null;\n }\n\n return {\n eventName: \"DelegatedForUserDecryption\",\n delegator: topicToAddress(log.topics[1]!),\n delegate: topicToAddress(log.topics[2]!),\n contractAddress: wordToAddress(log.data, 0),\n delegationCounter: wordToBigInt(log.data, 1),\n oldExpirationDate: wordToBigInt(log.data, 2),\n newExpirationDate: wordToBigInt(log.data, 3),\n };\n}\n\n/**\n * RevokedDelegationForUserDecryption(address indexed delegator, address indexed delegate,\n * address contractAddress, uint64 delegationCounter, uint64 oldExpirationDate)\n * Indexed: delegator (topics[1]), delegate (topics[2])\n * Data: contractAddress, delegationCounter, oldExpirationDate\n */\nexport function decodeRevokedDelegationForUserDecryption(\n log: RawLog,\n): RevokedDelegationForUserDecryptionEvent | null {\n if (log.topics[0] !== AclTopics.RevokedDelegationForUserDecryption) {\n return null;\n }\n if (log.topics.length < 3) {\n return null;\n }\n\n return {\n eventName: \"RevokedDelegationForUserDecryption\",\n delegator: topicToAddress(log.topics[1]!),\n delegate: topicToAddress(log.topics[2]!),\n contractAddress: wordToAddress(log.data, 0),\n delegationCounter: wordToBigInt(log.data, 1),\n oldExpirationDate: wordToBigInt(log.data, 2),\n };\n}\n\n/**\n * Try all ACL delegation decoders on a single log and return the first match, or `null`.\n */\nexport function decodeAclEvent(log: RawLog): AclEvent | null {\n return decodeDelegatedForUserDecryption(log) ?? decodeRevokedDelegationForUserDecryption(log);\n}\n\n/**\n * Batch-decode an array of logs for ACL delegation events, skipping unrecognized entries.\n */\nexport function decodeAclEvents(logs: readonly RawLog[]): AclEvent[] {\n const events: AclEvent[] = [];\n for (const log of logs) {\n const event = decodeAclEvent(log);\n if (event) {\n events.push(event);\n }\n }\n return events;\n}\n\n/**\n * Find the first {@link DelegatedForUserDecryptionEvent} in a logs array.\n */\nexport function findDelegatedForUserDecryption(\n logs: readonly RawLog[],\n): DelegatedForUserDecryptionEvent | null {\n for (const log of logs) {\n const event = decodeDelegatedForUserDecryption(log);\n if (event) {\n return event;\n }\n }\n return null;\n}\n\n/**\n * Find the first {@link RevokedDelegationForUserDecryptionEvent} in a logs array.\n */\nexport function findRevokedDelegationForUserDecryption(\n logs: readonly RawLog[],\n): RevokedDelegationForUserDecryptionEvent | null {\n for (const log of logs) {\n const event = decodeRevokedDelegationForUserDecryption(log);\n if (event) {\n return event;\n }\n }\n return null;\n}\n\n/**\n * Both ACL delegation event topic0 hashes.\n * Pass to `getLogs({ topics: [ACL_TOPICS] })` to fetch\n * all delegation events in a single RPC call.\n */\nexport const ACL_TOPICS = [\n AclTopics.DelegatedForUserDecryption,\n AclTopics.RevokedDelegationForUserDecryption,\n] as const;\n","import { type Address, getAddress, type Hex } 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} 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 {\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 { isZeroHandle } from \"../utils/handles\";\nimport { ReadonlyToken } from \"./readonly-token\";\nimport type {\n ShieldCallbacks,\n ShieldOptions,\n TransactionResult,\n TransferCallbacks,\n TransferOptions,\n UnshieldCallbacks,\n UnshieldOptions,\n} from \"../types\";\nimport type { ZamaSDK } from \"../zama-sdk\";\nimport { assertBigint } from \"../utils/assertions\";\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 {@link ReadonlyToken} with write operations\n * (transfer, shield, unshield).\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(sdk: ZamaSDK, address: Address, wrapper?: Address) {\n super(sdk, address);\n this.wrapper = wrapper ? getAddress(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.sdk.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.sdk.relayer.encrypt({\n values: [{ value: amount, type: \"euint64\" }],\n contractAddress: this.address,\n userAddress: await this.sdk.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.sdk.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.sdk.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.sdk.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.sdk.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.sdk.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.sdk.signer.writeContract(\n setOperatorContract(this.address, normalizedSpender, until),\n );\n this.emit({ type: ZamaSDKEvents.ApproveSubmitted, txHash });\n const receipt = await this.sdk.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.sdk.signer.getAddress();\n return this.sdk.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).\n *\n * @param amount - The plaintext amount to shield.\n * @param options - Optional configuration: `approvalStrategy` (`\"exact\"` | `\"max\"` | `\"skip\"`, default `\"exact\"`).\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 // 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.sdk.signer.getAddress();\n erc20Balance = await this.sdk.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.sdk.signer.getAddress();\n const txHash = await this.sdk.signer.writeContract(\n wrapContract(this.wrapper, recipient, amount),\n );\n this.emit({ type: ZamaSDKEvents.ShieldSubmitted, txHash });\n safeCallback(() => options?.onShieldSubmitted?.(txHash));\n const receipt = await this.sdk.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 * 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.sdk.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.sdk.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.sdk.signer.writeContract(\n unwrapContract(this.address, userAddress, userAddress, handles[0]!, inputProof),\n );\n this.emit({ type: ZamaSDKEvents.UnwrapSubmitted, txHash });\n const receipt = await this.sdk.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.sdk.signer.getAddress();\n const handle = await this.readConfidentialBalanceOf(userAddress);\n\n if (isZeroHandle(handle)) {\n throw new DecryptionFailedError(\"Cannot unshield: balance is zero\");\n }\n\n try {\n const txHash = await this.sdk.signer.writeContract(\n unwrapFromBalanceContract(this.address, userAddress, userAddress, handle),\n );\n this.emit({ type: ZamaSDKEvents.UnwrapSubmitted, txHash });\n const receipt = await this.sdk.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 unwrapRequestId - The unwrap request ID 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.unwrapRequestId);\n * ```\n */\n async finalizeUnwrap(unwrapRequestId: Handle): Promise<TransactionResult> {\n const result = await this.sdk.publicDecrypt([unwrapRequestId]);\n const clearValue = result.clearValues[unwrapRequestId];\n assertBigint(clearValue, \"finalizeUnwrap: clearValue\");\n try {\n const txHash = await this.sdk.signer.writeContract(\n finalizeUnwrapContract(this.wrapper, unwrapRequestId, clearValue, result.decryptionProof),\n );\n this.emit({ type: ZamaSDKEvents.FinalizeUnwrapSubmitted, txHash });\n const receipt = await this.sdk.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.sdk.signer.getAddress();\n const currentAllowance = await this.sdk.signer.readContract(\n allowanceContract(underlying, userAddress, this.wrapper),\n );\n\n if (currentAllowance > 0n) {\n await this.sdk.signer.writeContract(approveContract(underlying, this.wrapper, 0n));\n }\n }\n\n const txHash = await this.sdk.signer.writeContract(\n approveContract(underlying, this.wrapper, approvalAmount),\n );\n this.emit({ type: ZamaSDKEvents.ApproveUnderlyingSubmitted, txHash });\n const receipt = await this.sdk.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.sdk.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 let currentExpiry: bigint;\n try {\n currentExpiry = await this.getDelegationExpiry({\n delegatorAddress: signerAddress,\n delegateAddress: normalizedDelegate,\n });\n } catch {\n currentExpiry = -1n; // RPC failure — skip client-side check, let the contract enforce\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.sdk.signer.writeContract(\n delegateForUserDecryptionContract(acl, normalizedDelegate, this.address, expDate),\n );\n this.emit({ type: ZamaSDKEvents.DelegationSubmitted, txHash });\n const receipt = await this.sdk.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.sdk.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 let currentExpiry: bigint;\n try {\n currentExpiry = await this.getDelegationExpiry({\n delegatorAddress: signerAddress,\n delegateAddress: normalizedDelegate,\n });\n } catch {\n currentExpiry = 1n; // RPC failure — skip client-side check, let the contract enforce\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.sdk.signer.writeContract(\n revokeDelegationContract(acl, normalizedDelegate, this.address),\n );\n this.emit({ type: ZamaSDKEvents.RevokeDelegationSubmitted, txHash });\n const receipt = await this.sdk.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 if (amount === 0n) {\n return;\n }\n\n let balance: bigint;\n try {\n balance = await this.balanceOf();\n } catch (error) {\n if (error instanceof ZamaError) {\n throw error;\n }\n throw new BalanceCheckUnavailableError(`Balance validation failed (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.sdk.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.unwrapRequestId);\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.sdk.signer.getAddress();\n const allowance = await this.sdk.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.sdk.signer.writeContract(approveContract(underlying, this.wrapper, 0n));\n }\n\n const approvalAmount = maxApproval ? 2n ** 256n - 1n : amount;\n\n const txHash = await this.sdk.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, zeroAddress } 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 the token has never been registered.\n * **Note:** revoked tokens (registered then invalidated) return a non-null result\n * with `isValid: false`. Check `result.isValid` explicitly rather than using\n * `if (result)` to guard against processing revoked tokens.\n *\n * @example\n * ```ts\n * const result = await registry.getConfidentialToken(usdcAddress);\n * if (result?.isValid) {\n * console.log(result.confidentialTokenAddress);\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 [isValid, confidentialTokenAddress] = await this.signer.readContract(\n getConfidentialTokenAddressContract(registry, normalized),\n );\n\n // Zero address means the token is not registered at all (never seen by the registry).\n // A non-zero address with isValid=false means it was registered but later revoked.\n if (confidentialTokenAddress === zeroAddress) {\n return this.#setCached(cacheKey, null, NEGATIVE_CACHE_TTL_MS);\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 [isValid, tokenAddress] = await this.signer.readContract(\n getTokenAddressContract(registry, normalized),\n );\n\n // Zero address means the confidential token is not registered at all.\n // A non-zero address with isValid=false means it was registered but later revoked.\n if (tokenAddress === zeroAddress) {\n return this.#setCached(cacheKey, null, NEGATIVE_CACHE_TTL_MS);\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 `[isValid, confidentialTokenAddress]`. `isValid` is `true` only for a\n * registered, non-revoked wrapper. The address is the zero address when no pair is registered.\n * A non-zero address with `isValid=false` means the wrapper was registered but later revoked.\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 `[isValid, tokenAddress]`. `isValid` is `true` only for a registered,\n * non-revoked wrapper. The address is the zero address when no pair is registered.\n * A non-zero address with `isValid=false` means the wrapper was registered but later revoked.\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 { DecryptCache } from \"./decrypt-cache\";\nimport { wrapDecryptError } from \"./errors\";\nimport type { ZamaSDKEvent, ZamaSDKEventInput, ZamaSDKEventListener } from \"./events/sdk-events\";\nimport { ZamaSDKEvents } from \"./events/sdk-events\";\nimport type { DecryptHandle } from \"./query/user-decrypt\";\nimport { isZeroHandle } from \"./utils/handles\";\nimport type { RelayerSDK } from \"./relayer/relayer-sdk\";\nimport type { ClearValueType, Handle, PublicDecryptResult } from \"./relayer/relayer-sdk.types\";\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 { pLimit } from \"./utils/concurrency\";\nimport { WrappersRegistry } from \"./wrappers-registry\";\n\n/** Maximum keypairTTL accepted by the fhevm ACL contract (365 days, in seconds). */\nconst MAX_KEYPAIR_TTL = 365 * 86400; // 31_536_000 s\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 contracts in 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 * Maximum: `31536000` (365 days) — the fhevm contract rejects `durationDays > 365`.\n * Values above this maximum are automatically capped with a console warning.\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 /** Persistent cache for decrypted FHE plaintext values, scoped by (requester, contract, handle). */\n readonly cache: DecryptCache;\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.cache = new DecryptCache(config.storage);\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 || isNaN(ttl)) {\n throw new Error(\"keypairTTL must be a positive number (seconds)\");\n }\n if (ttl > MAX_KEYPAIR_TTL) {\n // oxlint-disable-next-line no-console\n console.warn(\n `[zama-sdk] keypairTTL (${ttl}s) exceeds the fhevm maximum of 365 days (${MAX_KEYPAIR_TTL}s); capping to ${MAX_KEYPAIR_TTL}s.`,\n );\n return MAX_KEYPAIR_TTL;\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.emitEvent({\n type: ZamaSDKEvents.TransactionError,\n operation,\n error: toError(error),\n });\n });\n };\n this.#unsubscribeSigner = this.signer.subscribe({\n onDisconnect: () => {\n runLifecycleEffect(\"signerDisconnect\", async () => {\n await this.#revokeByTrackedIdentity();\n await this.cache.clearAll();\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 await this.cache.clearAll();\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 await this.cache.clearAll();\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.\n */\n createReadonlyToken(address: Address): ReadonlyToken {\n return new ReadonlyToken(this, address);\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.\n */\n createToken(address: Address, wrapper?: Address): Token {\n return new Token(this, address, wrapper);\n }\n\n /**\n * Emit a structured SDK event. Used by {@link Token}/{@link ReadonlyToken}\n * to surface lifecycle events through the unified SDK event stream.\n *\n * Listener exceptions are caught and logged so that a misbehaving subscriber\n * can never corrupt SDK operations.\n *\n * Application code should subscribe via the `onEvent` config option, never\n * call this directly.\n *\n * @internal\n */\n emitEvent(input: ZamaSDKEventInput, tokenAddress?: Address): void {\n try {\n this.#onEvent({\n ...input,\n tokenAddress,\n timestamp: Date.now(),\n } as ZamaSDKEvent);\n } catch (error) {\n // oxlint-disable-next-line no-console\n console.error(\"[zama-sdk] onEvent listener threw:\", error);\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 contract addresses for decryption, triggering a single\n * wallet signature prompt. Subsequent {@link userDecrypt} calls whose\n * handles span the same set will reuse the cached credentials without\n * an additional prompt.\n *\n * @param contractAddresses - One or more contract addresses to authorize.\n *\n * @example\n * ```ts\n * // Sign once for three tokens, then decrypt individually\n * await sdk.allow([cUSDT, cDAI, cWETH]);\n * const a = await sdk.userDecrypt([{ handle: h1, contractAddress: cUSDT }]);\n * const b = await sdk.userDecrypt([{ handle: h2, contractAddress: cDAI }]);\n * ```\n */\n async allow(contractAddresses: Address[]): Promise<void> {\n if (contractAddresses.length === 0) {\n return;\n }\n await this.credentials.allow(...contractAddresses);\n }\n\n /**\n * Decrypt one or more FHE handles. Results are cached — repeated calls\n * for the same handle skip the relayer round-trip.\n *\n * Zero handles are mapped to `0n` without hitting the relayer.\n * Events (`DecryptStart/End/Error`) are emitted uniformly.\n * Relayer errors are wrapped into typed SDK errors.\n *\n * @param handles - Handles to decrypt, each paired with its contract address.\n * @returns A record mapping each handle to its decrypted clear-text value.\n *\n * @example\n * ```ts\n * const values = await sdk.userDecrypt([\n * { handle: balanceHandle, contractAddress: cUSDT },\n * ]);\n * console.log(values[balanceHandle]); // 1000n\n * ```\n */\n async userDecrypt(handles: DecryptHandle[]): Promise<Record<Handle, ClearValueType>> {\n if (handles.length === 0) {\n return {};\n }\n\n // Normalize addresses once at the top\n const normalized = handles.map((h) => ({\n handle: h.handle,\n contractAddress: getAddress(h.contractAddress),\n }));\n\n const result: Record<Handle, ClearValueType> = {};\n const nonZero: DecryptHandle[] = [];\n\n // Filter zero handles → 0n without relayer\n for (const h of normalized) {\n if (isZeroHandle(h.handle)) {\n result[h.handle] = 0n;\n } else {\n nonZero.push(h);\n }\n }\n\n if (nonZero.length === 0) {\n return result;\n }\n\n // Cache partition\n const signerAddress = await this.signer.getAddress();\n const uncached: DecryptHandle[] = [];\n\n for (const h of nonZero) {\n const cached = await this.cache.get(signerAddress, h.contractAddress, h.handle);\n if (cached !== null) {\n result[h.handle] = cached;\n } else {\n uncached.push(h);\n }\n }\n\n if (uncached.length === 0) {\n return result;\n }\n\n // Derive contract addresses from ALL handles for stable credential cache key\n const creds = await this.credentials.allow(\n ...new Set(normalized.map((h) => h.contractAddress)),\n );\n\n // Group uncached by contract\n const byContract = new Map<Address, Handle[]>();\n for (const h of uncached) {\n const existing = byContract.get(h.contractAddress);\n if (existing) {\n existing.push(h.handle);\n } else {\n byContract.set(h.contractAddress, [h.handle]);\n }\n }\n\n // Decrypt per contract group with bounded concurrency\n const t0 = Date.now();\n const uncachedHandles = uncached.map((h) => h.handle);\n\n try {\n this.emitEvent({\n type: ZamaSDKEvents.DecryptStart,\n handles: uncachedHandles,\n });\n\n await pLimit(\n [...byContract.entries()].map(([contractAddress, contractHandles]) => async () => {\n const decrypted = await this.relayer.userDecrypt({\n handles: contractHandles,\n contractAddress,\n signedContractAddresses: creds.contractAddresses,\n privateKey: creds.privateKey,\n publicKey: creds.publicKey,\n signature: creds.signature,\n signerAddress,\n startTimestamp: creds.startTimestamp,\n durationDays: creds.durationDays,\n });\n\n for (const [handle, value] of Object.entries(decrypted)) {\n result[handle as Handle] = value;\n await this.cache.set(signerAddress, contractAddress, handle as Handle, value);\n }\n }),\n 5,\n );\n\n // Emit only the freshly-decrypted subset in `result` so its keys match\n // `handles`. Cached and zero-handle entries are intentionally excluded.\n const uncachedResult: Record<Handle, ClearValueType> = {};\n for (const handle of uncachedHandles) {\n const value = result[handle];\n if (value !== undefined) {\n uncachedResult[handle] = value;\n }\n }\n this.emitEvent({\n type: ZamaSDKEvents.DecryptEnd,\n durationMs: Date.now() - t0,\n handles: uncachedHandles,\n result: uncachedResult,\n });\n return result;\n } catch (error) {\n this.emitEvent({\n type: ZamaSDKEvents.DecryptError,\n error: toError(error),\n durationMs: Date.now() - t0,\n handles: uncachedHandles,\n });\n throw wrapDecryptError(error, \"Failed to decrypt handles\");\n }\n }\n\n /**\n * Publicly decrypt one or more FHE handles.\n *\n * Returns the decryption proof alongside the clear-text values so callers\n * can submit on-chain finalization transactions (e.g. `finalizeUnwrap`).\n *\n * @param handles - FHE handles to decrypt publicly.\n * @returns Clear-text values, ABI-encoded values, and the decryption proof.\n *\n * @example\n * ```ts\n * const { clearValues, decryptionProof, abiEncodedClearValues } =\n * await sdk.publicDecrypt([handle]);\n * ```\n */\n async publicDecrypt(handles: Handle[]): Promise<PublicDecryptResult> {\n if (handles.length === 0) {\n return { clearValues: {}, decryptionProof: \"0x\", abiEncodedClearValues: \"0x\" };\n }\n\n try {\n return await this.relayer.publicDecrypt(handles);\n } catch (error) {\n throw wrapDecryptError(error, \"Public decryption failed\");\n }\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 await this.cache.clearForRequester(address);\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.credentials.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.cjs","names":["ZamaError","ZamaErrorCode","ZamaError","ZamaErrorCode","ZamaError","ZamaErrorCode","DelegationCooldownError","DelegationContractIsSelfError","AclPausedError","DelegationSelfNotAllowedError","DelegationDelegateEqualsContractError","DelegationExpirationTooSoonError","DelegationExpiryUnchangedError","DelegationNotFoundError","#initPromise","ConfigurationError","#storage","#chainId","#relayerUrl","#ttlMs","#logger","#publicKeyMem","#publicKeyInflight","#loadPublicKey","#deleteQuietly","toError","#publicParamsMem","#publicParamsInflight","#loadPublicParams","#revalidationInflight","#revalidateIfDueInner","#lastRevalidatedAt","#collectParamEntries","#writeEntries","#clearAll","#checkArtifactFreshness","#config","#worker","#artifactCache","#artifactStorage","IndexedDBStorage","#refreshCsrfToken","#getArtifactCache","#worker","#initPromise","#doInitWorker","#pendingRequests","#rejectAllPending","workerFilename","workerCode","ConfigurationError","RelayerCleartext","buildZamaConfig","#storage","#decryptNamespace","#decryptKeysNamespace","#buildStorageKey","#indexWriteQueue","#addToIndex","#doClearForRequester","#readIndex","#doClearAll","#cachedDerivedKey","#cachedDerivedKeyIdentity","#deriveKey","#storage","#assertSessionEntry","#onEvent","ZamaSDKEvents","#extendContracts","ZamaError","toError","#deleteCredentials","#createPromise","#createPromiseKey","#lastExtendResult","wrapSigningError","#extendPromise","#extendCredentials","#relayer","MemoryStorage","#storeKey","#cachedStoreKey","#cachedStoreKeyIdentity","#relayer","#storeKey","#create","#signDelegated","#cachedStoreKey","#cachedStoreKeyIdentity","ReadonlyToken","#getUnderlying","#underlying","#underlyingPromise","underlyingContract","#assertConfidentialBalance","ZamaSDKEvents","toError","ZamaError","EncryptionFailedError","confidentialTransferContract","confidentialTransferFromContract","setOperatorContract","isOperatorContract","balanceOfContract","#ensureAllowance","wrapContract","unwrapContract","isZeroHandle","DecryptionFailedError","unwrapFromBalanceContract","#waitAndFinalizeUnshield","finalizeUnwrapContract","allowanceContract","approveContract","DelegationExpirationTooSoonError","DelegationSelfNotAllowedError","DelegationDelegateEqualsContractError","MAX_UINT64","DelegationExpiryUnchangedError","delegateForUserDecryptionContract","DelegationNotFoundError","revokeDelegationContract","#batchDelegationOp","mainnet","sepolia","hoodi","#addresses","#ttlMs","#cache","ConfigurationError","#getCached","getTokenPairsLengthContract","#setCached","getTokenPairsSliceContract","#pairWithMetadata","nameContract","symbolContract","decimalsContract","erc20TotalSupplyContract","getConfidentialTokenAddressContract","zeroAddress","getTokenAddressContract","getTokenPairsContract","getTokenPairContract","isConfidentialTokenValidContract","#registryTTL","#onEvent","#identityListeners","MemoryStorage","#unsubscribeSigner","#handleIdentityChange","ReadonlyToken","isZeroHandle","ZamaSDKEvents","pLimit","toError","wrapDecryptError"],"sources":["../../src/errors/transaction.ts","../../src/errors/chain.ts","../../src/errors/balance.ts","../../src/errors/acl-revert.ts","../../src/relayer/base-relayer.ts","../../src/utils/hex.ts","../../src/relayer/fhe-artifact-cache.ts","../../src/relayer/relayer-utils.ts","../../src/relayer/relayer-web.ts","../../src/worker/worker.base-client.ts","../../src/worker/browser-extension.ts","../../src/worker/worker.client.ts","../../src/config/web.ts","../../src/config/cleartext.ts","../../src/config/create.ts","../../src/decrypt-cache.ts","../../src/credentials/credential-crypto.ts","../../src/credentials/credential-validation.ts","../../src/credentials/session-signatures.ts","../../src/credentials/credentials-manager-base.ts","../../src/credentials/credentials-manager.ts","../../src/credentials/delegated-credentials-manager.ts","../../src/events/onchain-events.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 { ZamaError, ZamaErrorCode } from \"./base\";\n\n/**\n * Thrown when the signer and provider are connected to different chains at the\n * start of a write operation.\n *\n * Every write method calls {@link ZamaSDK.requireChainAlignment} as a pre-flight\n * check. If `signer.getChainId()` and `provider.getChainId()` return different\n * values, this error is thrown before any RPC mutation is attempted.\n *\n * @example\n * ```ts\n * try {\n * await token.shield(1000n);\n * } catch (e) {\n * if (e instanceof ChainMismatchError) {\n * console.error(\n * `Signer is on chain ${e.signerChainId} but provider is on chain ${e.providerChainId}`,\n * );\n * }\n * }\n * ```\n */\nexport class ChainMismatchError extends ZamaError {\n readonly operation: string;\n readonly signerChainId: number;\n readonly providerChainId: number;\n\n constructor(\n {\n operation,\n signerChainId,\n providerChainId,\n }: { operation: string; signerChainId: number; providerChainId: number },\n options?: ErrorOptions,\n ) {\n super(\n ZamaErrorCode.ChainMismatch,\n `Operation \"${operation}\" requires signer and provider to be on the same chain, ` +\n `but signer is on chain ${signerChainId} and provider is on chain ${providerChainId}.`,\n options,\n );\n this.name = \"ChainMismatchError\";\n this.operation = operation;\n this.signerChainId = signerChainId;\n this.providerChainId = providerChainId;\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","import type { Address } from \"viem\";\nimport type { FheChain } from \"../chains/types\";\nimport { ConfigurationError } from \"../errors\";\n\nexport abstract class BaseRelayer {\n #initPromise: Promise<void> | null = null;\n protected abstract readonly chain: FheChain;\n protected abstract init(): Promise<void>;\n\n protected async ensureInit(): Promise<void> {\n if (!this.#initPromise) {\n this.#initPromise = this.init().catch((error) => {\n this.#initPromise = null;\n throw error;\n });\n }\n return this.#initPromise;\n }\n\n protected resetInit(): void {\n this.#initPromise = null;\n }\n\n async getAclAddress(): Promise<Address> {\n if (!this.chain.aclContractAddress) {\n throw new ConfigurationError(`No ACL address configured for chain ${this.chain.id}`);\n }\n return this.chain.aclContractAddress;\n }\n}\n","import type { Hex } from \"viem\";\nimport { assertCondition } from \"./assertions\";\n\n/** Normalize a un-prefixed hex payload to a 0x-prefixed `Hex` value. */\nexport function prefixHex(value: string): Hex {\n return (value.startsWith(\"0x\") ? value : `0x${value}`) as Hex;\n}\n\n/** Convert a public `Hex` value back an unprefixed format. */\nexport function unprefixHex(value: Hex): string {\n assertCondition(value.startsWith(\"0x\"), `Expected 0x-prefixed hex, got: ${value}`);\n return value.slice(2);\n}\n","import type { GenericStorage } from \"../types\";\nimport { assertObject, assertStringProp, toError } from \"../utils\";\nimport type { GenericLogger } from \"../worker/worker.types\";\nimport type { PublicKeyData, PublicParamsData } from \"./relayer-sdk.types\";\n\n// ── Cached data shapes ──────────────────────────────────────\n\n/** Cached shape for the FHE network public key. */\ninterface CachedPublicKey {\n publicKeyId: string;\n /** Base64-encoded Uint8Array. */\n publicKey: string;\n /** Artifact URL from the manifest. */\n artifactUrl?: string;\n /** HTTP ETag from the artifact response. */\n etag?: string;\n /** HTTP Last-Modified from the artifact response. */\n lastModified?: string;\n /** Epoch-ms timestamp of the last successful revalidation. */\n lastValidatedAt: number;\n}\n\n/** Cached shape for FHE public params. */\ninterface CachedPublicParams {\n publicParamsId: string;\n /** Base64-encoded Uint8Array. */\n publicParams: string;\n artifactUrl?: string;\n etag?: string;\n lastModified?: string;\n lastValidatedAt: number;\n}\n\n// ── Return types ────────────────────────────────────────────\n\n/** Return type of the public key fetcher. */\ntype PublicKeyResult = PublicKeyData | null;\n\n/** Return type of the public params fetcher. */\ntype PublicParamsResult = PublicParamsData | null;\n\n// ── Constants ───────────────────────────────────────────────\n\n/** Max chunk size for String.fromCharCode to avoid call-stack overflow on large buffers. */\nconst CHUNK_SIZE = 8192;\n\n/** On revalidation failure, retry after 5 minutes instead of the full TTL. */\nconst SHORT_RETRY_MS = 5 * 60 * 1000;\n\n// ── Helpers ─────────────────────────────────────────────────\n\nfunction toBase64(bytes: Uint8Array): string {\n const chunks: string[] = [];\n for (let i = 0; i < bytes.length; i += CHUNK_SIZE) {\n chunks.push(String.fromCharCode(...bytes.subarray(i, i + CHUNK_SIZE)));\n }\n return btoa(chunks.join(\"\"));\n}\n\nfunction fromBase64(b64: string): Uint8Array {\n let binary: string;\n try {\n binary = atob(b64);\n } catch {\n throw new Error(`Invalid base64 data (length: ${b64.length})`);\n }\n if (binary.length === 0) {\n throw new Error(\"Decoded artifact is empty\");\n }\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) {\n bytes[i] = binary.charCodeAt(i);\n }\n return bytes;\n}\n\nfunction pubkeyStorageKey(chainId: number): string {\n return `fhe:pubkey:${chainId}`;\n}\n\nfunction paramsStorageKey(chainId: number, bits: number): string {\n return `fhe:params:${chainId}:${bits}`;\n}\n\nfunction paramsIndexKey(chainId: number): string {\n return `fhe:params-index:${chainId}`;\n}\n\nfunction assertCachedPk(v: unknown): asserts v is CachedPublicKey {\n assertObject(v, \"CachedPublicKey\");\n assertStringProp(v, \"publicKeyId\", \"CachedPublicKey.publicKeyId\");\n assertStringProp(v, \"publicKey\", \"CachedPublicKey.publicKey\");\n}\n\nfunction assertCachedParams(v: unknown): asserts v is CachedPublicParams {\n assertObject(v, \"CachedPublicParams\");\n assertStringProp(v, \"publicParamsId\", \"CachedPublicParams.publicParamsId\");\n assertStringProp(v, \"publicParams\", \"CachedPublicParams.publicParams\");\n}\n\n/** Manifest shape returned by the relayer `/keyurl` endpoint. */\ninterface ManifestShape {\n status: string;\n response: {\n fheKeyInfo: Array<{\n fhePublicKey: { dataId: string; urls: string[] };\n }>;\n crs: Record<string, { dataId: string; urls: string[] }>;\n };\n}\n\n// ── ArtifactCache ──────────────────────────────────────────\n\n/**\n * Persistent cache for FHE network public key and public params.\n * Uses a {@link GenericStorage} backend (e.g. MemoryStorage, or any\n * user-provided async key-value adapter) to avoid re-downloading large\n * binary data on every app instantiation.\n *\n * Cache keys are scoped by chain ID.\n */\nexport class FheArtifactCache {\n readonly #storage: GenericStorage;\n readonly #chainId: number;\n readonly #relayerUrl: string;\n readonly #ttlMs: number;\n readonly #logger: GenericLogger;\n #publicKeyMem: PublicKeyResult | undefined;\n #publicParamsMem = new Map<number, PublicParamsResult>();\n #publicKeyInflight: Promise<PublicKeyResult> | null = null;\n #publicParamsInflight = new Map<number, Promise<PublicParamsResult>>();\n #revalidationInflight: Promise<boolean> | null = null;\n /** In-memory guard to skip storage reads when revalidation isn't due. */\n #lastRevalidatedAt: number | null = null;\n\n constructor(opts: {\n storage: GenericStorage;\n chainId: number;\n relayerUrl: string;\n /** Cache TTL in seconds. Default: 86 400 (24 h). Set to 0 to revalidate on every operation. */\n ttl?: number;\n logger?: GenericLogger;\n }) {\n this.#storage = opts.storage;\n this.#chainId = opts.chainId;\n this.#relayerUrl = opts.relayerUrl;\n this.#ttlMs = (opts.ttl ?? 86_400) * 1000;\n this.#logger = opts.logger ?? console;\n }\n\n // ── getPublicKey ────────────────────────────────────────\n\n async getPublicKey(fetcher: () => Promise<PublicKeyResult>): Promise<PublicKeyResult> {\n if (this.#publicKeyMem !== undefined) {\n return this.#publicKeyMem;\n }\n\n // Deduplicate concurrent calls\n if (this.#publicKeyInflight) {\n return this.#publicKeyInflight;\n }\n\n this.#publicKeyInflight = this.#loadPublicKey(fetcher);\n try {\n return await this.#publicKeyInflight;\n } finally {\n this.#publicKeyInflight = null;\n }\n }\n\n async #loadPublicKey(fetcher: () => Promise<PublicKeyResult>): Promise<PublicKeyResult> {\n const key = pubkeyStorageKey(this.#chainId);\n\n try {\n const raw = await this.#storage.get(key);\n if (raw) {\n assertCachedPk(raw);\n const result: PublicKeyResult = {\n publicKeyId: raw.publicKeyId,\n publicKey: fromBase64(raw.publicKey),\n };\n this.#publicKeyMem = result;\n return result;\n }\n } catch (err) {\n // Corrupt or unreadable entry — delete and fall through to fetcher\n await this.#deleteQuietly(key);\n this.#logger.warn(\n \"Failed to read public key from persistent storage, falling back to network fetch\",\n {\n chainId: this.#chainId,\n error: toError(err).message,\n },\n );\n }\n\n const result = await fetcher();\n if (result === null) {\n return null;\n }\n\n this.#publicKeyMem = result;\n\n try {\n const cached: CachedPublicKey = {\n publicKeyId: result.publicKeyId,\n publicKey: toBase64(result.publicKey),\n lastValidatedAt: Date.now(),\n };\n await this.#storage.set(key, cached);\n } catch (err) {\n this.#logger.warn(\"Failed to persist public key to storage\", {\n chainId: this.#chainId,\n error: toError(err).message,\n });\n }\n\n return result;\n }\n\n // ── getPublicParams ─────────────────────────────────────\n\n async getPublicParams(\n bits: number,\n fetcher: () => Promise<PublicParamsResult>,\n ): Promise<PublicParamsResult> {\n const mem = this.#publicParamsMem.get(bits);\n if (mem !== undefined) {\n return mem;\n }\n\n // Deduplicate concurrent calls\n const inflight = this.#publicParamsInflight.get(bits);\n if (inflight) {\n return inflight;\n }\n\n const promise = this.#loadPublicParams(bits, fetcher);\n this.#publicParamsInflight.set(bits, promise);\n try {\n return await promise;\n } finally {\n this.#publicParamsInflight.delete(bits);\n }\n }\n\n async #loadPublicParams(\n bits: number,\n fetcher: () => Promise<PublicParamsResult>,\n ): Promise<PublicParamsResult> {\n const key = paramsStorageKey(this.#chainId, bits);\n\n try {\n const raw = await this.#storage.get(key);\n if (raw) {\n assertCachedParams(raw);\n const result: PublicParamsResult = {\n publicParamsId: raw.publicParamsId,\n publicParams: fromBase64(raw.publicParams),\n };\n this.#publicParamsMem.set(bits, result);\n return result;\n }\n } catch (err) {\n // Corrupt or unreadable entry — delete and fall through to fetcher\n await this.#deleteQuietly(key);\n this.#logger.warn(\n \"Failed to read public params from persistent storage, falling back to network fetch\",\n {\n chainId: this.#chainId,\n bits,\n error: toError(err).message,\n },\n );\n }\n\n const result = await fetcher();\n if (result === null) {\n return null;\n }\n\n this.#publicParamsMem.set(bits, result);\n\n try {\n const cached: CachedPublicParams = {\n publicParamsId: result.publicParamsId,\n publicParams: toBase64(result.publicParams),\n lastValidatedAt: Date.now(),\n };\n await this.#storage.set(key, cached);\n\n // Update params index for cold-start CRS detection\n const idxKey = paramsIndexKey(this.#chainId);\n const existing =\n (await this.#storage.get<number[]>(idxKey).catch((err) => {\n this.#logger.warn(\"Failed to read params index from storage\", {\n chainId: this.#chainId,\n error: toError(err).message,\n });\n return null;\n })) ?? [];\n if (!existing.includes(bits)) {\n await this.#storage.set(idxKey, [...existing, bits]);\n }\n } catch (err) {\n this.#logger.warn(\"Failed to persist public params to storage\", {\n chainId: this.#chainId,\n bits,\n error: toError(err).message,\n });\n }\n\n return result;\n }\n\n // ── Artifact-level revalidation ─────────────────────────\n\n /**\n * Check whether cached FHE artifacts are still fresh by issuing\n * HTTP conditional requests (ETag / If-None-Match, Last-Modified /\n * If-Modified-Since) against the actual artifact CDN URLs.\n *\n * @returns `true` if the cache was invalidated and the caller should\n * re-fetch artifacts, `false` otherwise.\n */\n async revalidateIfDue(): Promise<boolean> {\n // Concurrency guard — coalesce overlapping calls\n if (this.#revalidationInflight) {\n return this.#revalidationInflight;\n }\n this.#revalidationInflight = this.#revalidateIfDueInner();\n try {\n return await this.#revalidationInflight;\n } finally {\n this.#revalidationInflight = null;\n }\n }\n\n async #revalidateIfDueInner(): Promise<boolean> {\n // Fast path: in-memory timestamp check avoids storage I/O on every call\n const now = Date.now();\n if (this.#lastRevalidatedAt !== null && now - this.#lastRevalidatedAt < this.#ttlMs) {\n return false;\n }\n\n // Skip revalidation when relayerUrl is not configured (e.g. Hardhat)\n if (!this.#relayerUrl) {\n return false;\n }\n\n const pkKey = pubkeyStorageKey(this.#chainId);\n\n // Track partial progress so the catch block can reuse already-read data\n let storedPk: CachedPublicKey | null = null;\n let paramEntries: Array<{\n bits: number;\n key: string;\n data: CachedPublicParams;\n }> = [];\n\n try {\n // 1. Read PK cache entry and collect params entries in parallel\n const [pkRaw, entries] = await Promise.all([\n this.#storage.get(pkKey),\n this.#collectParamEntries(),\n ]);\n\n // Validate PK shape\n if (pkRaw) {\n try {\n assertCachedPk(pkRaw);\n storedPk = { ...pkRaw, lastValidatedAt: pkRaw.lastValidatedAt ?? 0 };\n } catch (err) {\n this.#logger.warn(\"Corrupt public key cache entry detected, deleting\", {\n chainId: this.#chainId,\n error: toError(err).message,\n });\n await this.#deleteQuietly(pkKey);\n }\n }\n\n paramEntries = entries;\n\n if (!storedPk) {\n return false;\n }\n\n // 2. Check if all entries are within TTL\n const allEntries: Array<{ lastValidatedAt: number }> = [\n storedPk,\n ...paramEntries.map((e) => e.data),\n ];\n const allFresh = allEntries.every((e) => now - e.lastValidatedAt < this.#ttlMs);\n if (allFresh) {\n this.#lastRevalidatedAt = now;\n return false;\n }\n\n // 3. Fetch manifest to discover current artifact URLs\n const manifestRes = await globalThis.fetch(`${this.#relayerUrl}/keyurl`);\n if (!manifestRes.ok) {\n // Treat as transient failure — use short retry instead of full TTL\n const retryTimestamp = now - this.#ttlMs + SHORT_RETRY_MS;\n this.#logger.warn(\"Manifest fetch failed during revalidation, retrying in 5 min\", {\n status: manifestRes.status,\n relayerUrl: this.#relayerUrl,\n });\n await this.#writeEntries(\n pkKey,\n { ...storedPk, lastValidatedAt: retryTimestamp },\n paramEntries.map((e) => ({\n ...e,\n data: { ...e.data, lastValidatedAt: retryTimestamp },\n })),\n );\n this.#lastRevalidatedAt = retryTimestamp;\n return false;\n }\n\n const manifest: ManifestShape = await manifestRes.json();\n\n // Validate manifest shape — a malformed response indicates a permanent\n // config error (wrong relayer URL, API version mismatch), not a transient\n // network issue. Log at error level so it's actionable.\n const fheKeyEntry = manifest?.response?.fheKeyInfo?.[0];\n if (\n !manifest ||\n typeof manifest !== \"object\" ||\n manifest.status !== \"succeeded\" ||\n !fheKeyEntry?.fhePublicKey?.urls?.length ||\n typeof manifest.response?.crs !== \"object\"\n ) {\n this.#logger.error(\n \"Relayer manifest has unexpected shape — check relayer URL and API version\",\n {\n relayerUrl: this.#relayerUrl,\n manifestKeys: manifest && typeof manifest === \"object\" ? Object.keys(manifest) : [],\n },\n );\n // Fail-open with short retry — but the error-level log distinguishes this from transient failures\n const retryTimestamp = now - this.#ttlMs + SHORT_RETRY_MS;\n await this.#writeEntries(\n pkKey,\n { ...storedPk, lastValidatedAt: retryTimestamp },\n paramEntries.map((e) => ({\n ...e,\n data: { ...e.data, lastValidatedAt: retryTimestamp },\n })),\n );\n this.#lastRevalidatedAt = retryTimestamp;\n return false;\n }\n const validManifest = manifest.response;\n\n // ── 4. Check PK artifact ──────────────────────────\n const pkArtifactUrl = fheKeyEntry.fhePublicKey.urls[0];\n // URL change → stale\n if (storedPk.artifactUrl && pkArtifactUrl && pkArtifactUrl !== storedPk.artifactUrl) {\n await this.#clearAll(pkKey, paramEntries);\n this.#lastRevalidatedAt = null;\n return true;\n }\n\n let updatedPk: CachedPublicKey = { ...storedPk, lastValidatedAt: now };\n if (pkArtifactUrl) {\n const freshness = await this.#checkArtifactFreshness(pkArtifactUrl, storedPk);\n if (!freshness.fresh) {\n await this.#clearAll(pkKey, paramEntries);\n this.#lastRevalidatedAt = null;\n return true;\n }\n updatedPk = {\n ...updatedPk,\n artifactUrl: pkArtifactUrl,\n etag: freshness.etag,\n lastModified: freshness.lastModified,\n };\n }\n\n // ── 5. Check each CRS artifact ────────────────────\n const updatedParamEntries: typeof paramEntries = [];\n for (const entry of paramEntries) {\n const manifestCrs = validManifest.crs[String(entry.bits)];\n const crsUrl = manifestCrs?.urls[0];\n\n // URL change → stale\n if (entry.data.artifactUrl && crsUrl && crsUrl !== entry.data.artifactUrl) {\n await this.#clearAll(pkKey, paramEntries);\n this.#lastRevalidatedAt = null;\n return true;\n }\n\n let updatedData: CachedPublicParams = {\n ...entry.data,\n lastValidatedAt: now,\n };\n if (crsUrl) {\n const freshness = await this.#checkArtifactFreshness(crsUrl, entry.data);\n if (!freshness.fresh) {\n await this.#clearAll(pkKey, paramEntries);\n this.#lastRevalidatedAt = null;\n return true;\n }\n updatedData = {\n ...updatedData,\n artifactUrl: crsUrl,\n etag: freshness.etag,\n lastModified: freshness.lastModified,\n };\n }\n updatedParamEntries.push({ ...entry, data: updatedData });\n }\n\n // 6. All fresh — update timestamps and HTTP validators\n await this.#writeEntries(pkKey, updatedPk, updatedParamEntries);\n this.#lastRevalidatedAt = now;\n return false;\n } catch (err) {\n const error = toError(err);\n const isProgrammingError =\n err instanceof TypeError ||\n err instanceof ReferenceError ||\n err instanceof RangeError ||\n err instanceof SyntaxError;\n const level = isProgrammingError ? \"error\" : \"warn\";\n this.#logger[level](\n isProgrammingError\n ? \"Unexpected error during revalidation (possible bug)\"\n : \"Revalidation failed, using cached artifacts (fail-open)\",\n {\n chainId: this.#chainId,\n relayerUrl: this.#relayerUrl,\n error: error.message,\n },\n );\n\n // Fail-open: use short retry interval (5 min) instead of full TTL\n const retryTimestamp = now - this.#ttlMs + SHORT_RETRY_MS;\n try {\n if (storedPk) {\n await this.#writeEntries(\n pkKey,\n { ...storedPk, lastValidatedAt: retryTimestamp },\n paramEntries.map((e) => ({\n ...e,\n data: { ...e.data, lastValidatedAt: retryTimestamp },\n })),\n );\n }\n } catch (innerErr) {\n this.#logger.warn(\"Failed to update validation timestamps after revalidation error\", {\n chainId: this.#chainId,\n error: toError(innerErr).message,\n });\n }\n this.#lastRevalidatedAt = retryTimestamp;\n return false;\n }\n }\n\n // ── Artifact freshness via HTTP conditional requests ───\n\n async #checkArtifactFreshness(\n url: string,\n cached: { etag?: string; lastModified?: string },\n ): Promise<{ fresh: boolean; etag?: string; lastModified?: string }> {\n const hasValidators = Boolean(cached.etag || cached.lastModified);\n const headers: Record<string, string> = {};\n if (cached.etag) {\n headers[\"If-None-Match\"] = cached.etag;\n }\n if (cached.lastModified) {\n headers[\"If-Modified-Since\"] = cached.lastModified;\n }\n\n // HEAD avoids downloading the (potentially multi-MB) artifact body.\n // With conditional headers, the server returns 304 if unchanged or 200 (no body) if stale.\n let res = await globalThis.fetch(url, { method: \"HEAD\", headers });\n\n // Fallback to GET if HEAD is not supported (e.g. some CDN/WAF configs)\n if (res.status === 405) {\n res = await globalThis.fetch(url, { headers });\n }\n\n // Treat server errors as transient — throw so the outer catch applies fail-open with short retry.\n // Without this, a CDN 5xx would be misinterpreted as \"artifact changed\" and wipe the cache.\n if (!res.ok && res.status !== 304) {\n throw new Error(`Artifact freshness check failed: HEAD ${url} returned ${res.status}`);\n }\n\n const etag = res.headers.get(\"etag\") ?? undefined;\n const lastModified = res.headers.get(\"last-modified\") ?? undefined;\n\n if (res.status === 304) {\n return {\n fresh: true,\n etag: etag ?? cached.etag,\n lastModified: lastModified ?? cached.lastModified,\n };\n }\n\n if (!hasValidators) {\n // First revalidation — capture validators, treat as fresh\n return { fresh: true, etag, lastModified };\n }\n\n // 200 = artifact changed\n return { fresh: false, etag, lastModified };\n }\n\n // ── Internal helpers ────────────────────────────────────\n\n async #collectParamEntries(): Promise<\n Array<{ bits: number; key: string; data: CachedPublicParams }>\n > {\n // Merge in-memory keys with persisted index for cold-start CRS detection\n const idxKey = paramsIndexKey(this.#chainId);\n const persistedBits =\n (await this.#storage.get<number[]>(idxKey).catch((err) => {\n this.#logger.warn(\"Failed to read params index, CRS revalidation may be incomplete\", {\n chainId: this.#chainId,\n error: toError(err).message,\n });\n return null;\n })) ?? [];\n const allBits = new Set([...this.#publicParamsMem.keys(), ...persistedBits]);\n\n const bitsArray = Array.from(allBits);\n const results = await Promise.all(\n bitsArray.map(async (bits) => {\n const pKey = paramsStorageKey(this.#chainId, bits);\n // Separate storage read from validation so we only delete on corruption\n let raw: unknown;\n try {\n raw = await this.#storage.get(pKey);\n } catch (err) {\n this.#logger.warn(\"Failed to read cached params entry during revalidation\", {\n chainId: this.#chainId,\n bits,\n error: toError(err).message,\n });\n return null;\n }\n if (!raw) {\n return null;\n }\n try {\n assertCachedParams(raw);\n return {\n bits,\n key: pKey,\n data: {\n ...raw,\n lastValidatedAt: raw.lastValidatedAt ?? 0,\n } as CachedPublicParams,\n };\n } catch (err) {\n this.#logger.warn(\"Corrupt params cache entry detected, deleting\", {\n chainId: this.#chainId,\n bits,\n error: toError(err).message,\n });\n await this.#deleteQuietly(pKey);\n return null;\n }\n }),\n );\n return results.filter(\n (e): e is { bits: number; key: string; data: CachedPublicParams } => e !== null,\n );\n }\n\n async #deleteQuietly(key: string): Promise<void> {\n await this.#storage.delete(key).catch((err) => {\n this.#logger.warn(\"Failed to delete cache entry\", {\n chainId: this.#chainId,\n key,\n error: toError(err).message,\n });\n });\n }\n\n async #clearAll(pkKey: string, paramEntries: Array<{ key: string }>): Promise<void> {\n const idxKey = paramsIndexKey(this.#chainId);\n // Delete from persistent storage first — if this fails, in-memory cache\n // still serves stale data, but the next revalidation cycle will retry.\n try {\n await Promise.all([\n this.#storage.delete(pkKey),\n this.#storage.delete(idxKey),\n ...paramEntries.map((entry) => this.#storage.delete(entry.key)),\n ]);\n } catch (err) {\n this.#logger.warn(\"Failed to clear stale artifacts from persistent storage\", {\n chainId: this.#chainId,\n error: toError(err).message,\n });\n }\n // Clear in-memory after storage to avoid re-loading stale entries on failure\n this.#publicKeyMem = undefined;\n this.#publicParamsMem.clear();\n }\n\n async #writeEntries(\n pkKey: string,\n pk: CachedPublicKey,\n paramEntries: Array<{ key: string; data: CachedPublicParams }>,\n ): Promise<void> {\n const writes = [\n this.#storage.set(pkKey, pk).catch((err) => {\n this.#logger.warn(\"Failed to update public key validation timestamp\", {\n chainId: this.#chainId,\n error: toError(err).message,\n });\n }),\n ...paramEntries.map((entry) =>\n this.#storage.set(entry.key, entry.data).catch((err) => {\n this.#logger.warn(\"Failed to update params validation timestamp\", {\n chainId: this.#chainId,\n error: toError(err).message,\n });\n }),\n ),\n ];\n await Promise.all(writes);\n }\n}\n","const MAX_RETRIES = 2;\nconst RETRY_BASE_MS = 500;\n\n/**\n * Retry an async operation with exponential backoff.\n * Only retries on transient errors (timeout, network). Does not retry user-facing errors.\n */\nexport async function withRetry<T>(fn: () => Promise<T>, retries = MAX_RETRIES): Promise<T> {\n let lastError: unknown;\n for (let attempt = 0; attempt <= retries; attempt++) {\n try {\n return await fn();\n } catch (error) {\n lastError = error;\n if (attempt < retries && isTransientError(error)) {\n await sleep(RETRY_BASE_MS * 2 ** attempt);\n continue;\n }\n throw error;\n }\n }\n throw lastError;\n}\n\nfunction isTransientError(error: unknown): boolean {\n if (!(error instanceof Error)) {\n return false;\n }\n const msg = error.message.toLowerCase();\n return (\n msg.includes(\"timed out\") ||\n msg.includes(\"timeout\") ||\n msg.includes(\"econnreset\") ||\n msg.includes(\"econnrefused\") ||\n msg.includes(\"network\") ||\n msg.includes(\"fetch failed\") ||\n msg.includes(\"socket hang up\") ||\n msg.includes(\"502\") ||\n msg.includes(\"503\") ||\n msg.includes(\"504\")\n );\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\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 { IndexedDBStorage } from \"../storage/indexeddb-storage\";\nimport type { GenericStorage } from \"../types\";\nimport type { RelayerWorkerClient } from \"../worker/worker.client\";\nimport type { FheChain } from \"../chains/types\";\nimport { BaseRelayer } from \"./base-relayer\";\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 PublicKeyData,\n PublicParamsData,\n RelayerWebConfig,\n UserDecryptParams,\n} from \"./relayer-sdk.types\";\nimport { 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 */\nexport const RELAYER_SDK_VERSION = \"0.4.2\";\nexport const 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. */\nexport const CDN_INTEGRITY =\n \"114438b01d518b53a447fa3e8bfbe6e71031cb42ac43219bb9f53488456fdfa4bbc8989628366d436e68f6526c7647eb\";\n\n/**\n * RelayerWeb — single-chain browser encryption/decryption layer.\n * The worker is injected at construction time; the relayer does not own its lifecycle.\n */\nexport class RelayerWeb extends BaseRelayer implements RelayerSDK, Disposable {\n #artifactCache: FheArtifactCache | null = null;\n #artifactStorage: GenericStorage | null = null;\n readonly #config: RelayerWebConfig;\n\n constructor(config: RelayerWebConfig) {\n super();\n this.#config = config;\n }\n\n protected get chain(): FheChain {\n return this.#config.chain;\n }\n\n protected async init(): Promise<void> {\n await this.#worker.initWorker();\n }\n\n get #worker(): RelayerWorkerClient {\n return this.#config.worker;\n }\n\n #getArtifactCache(): FheArtifactCache {\n if (!this.#artifactCache) {\n if (!this.#artifactStorage) {\n this.#artifactStorage =\n this.#config.fheArtifactStorage ??\n new IndexedDBStorage(\"FheArtifactCache\", 1, \"artifacts\");\n }\n this.#artifactCache = new FheArtifactCache({\n storage: this.#artifactStorage,\n chainId: this.chain.id,\n relayerUrl: this.chain.relayerUrl,\n ttl: this.#config.fheArtifactCacheTTL,\n logger: this.#config.logger,\n });\n }\n return this.#artifactCache;\n }\n\n /**\n * Terminate clears the artifact cache only.\n * The worker is externally owned — the relayer does not terminate it.\n */\n terminate(): void {\n this.#artifactCache = null;\n this.resetInit();\n }\n\n /** Calls {@link terminate}. */\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 const token = this.#config.security?.getCsrfToken?.() ?? \"\";\n if (token) {\n await this.#worker.updateCsrf(token);\n }\n }\n\n /**\n * Generate a keypair for FHE operations.\n */\n async generateKeypair(): Promise<KeypairType<Hex>> {\n await this.ensureInit();\n const chainId = this.chain.id;\n const result = await this.#worker.generateKeypair({ chainId });\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 await this.ensureInit();\n const chainId = this.chain.id;\n return this.#worker.createEIP712({\n chainId,\n publicKey,\n contractAddresses,\n startTimestamp,\n durationDays,\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 await this.ensureInit();\n const chainId = this.chain.id;\n\n return withRetry(async () => {\n await this.#refreshCsrfToken();\n const result = await this.#worker.encrypt({\n chainId,\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 await this.ensureInit();\n const chainId = this.chain.id;\n return withRetry(async () => {\n await this.#refreshCsrfToken();\n const result = await this.#worker.userDecrypt({ chainId, ...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 await this.ensureInit();\n const chainId = this.chain.id;\n return withRetry(async () => {\n await this.#refreshCsrfToken();\n const result = await this.#worker.publicDecrypt({ chainId, 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 await this.ensureInit();\n const chainId = this.chain.id;\n return this.#worker.createDelegatedUserDecryptEIP712({\n chainId,\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 await this.ensureInit();\n const chainId = this.chain.id;\n return withRetry(async () => {\n await this.#refreshCsrfToken();\n const result = await this.#worker.delegatedUserDecrypt({\n chainId,\n ...params,\n });\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 await this.ensureInit();\n const chainId = this.chain.id;\n return withRetry(async () => {\n await this.#refreshCsrfToken();\n return this.#worker.requestZKProofVerification({ chainId, 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<PublicKeyData | null> {\n await this.ensureInit();\n const chainId = this.chain.id;\n const artifactCache = this.#getArtifactCache();\n return artifactCache.getPublicKey(\n async () => (await this.#worker.getPublicKey({ chainId })).result,\n );\n }\n\n /**\n * Get public parameters for encryption capacity.\n * When storage is configured, the result is cached persistently.\n */\n async getPublicParams(bits: number): Promise<PublicParamsData | null> {\n await this.ensureInit();\n const chainId = this.chain.id;\n const artifactCache = this.#getArtifactCache();\n return artifactCache.getPublicParams(\n bits,\n async () => (await this.#worker.getPublicParams({ chainId, bits })).result,\n );\n }\n}\n","import type {\n CreateDelegatedEIP712Payload,\n CreateDelegatedEIP712ResponseData,\n CreateEIP712Payload,\n CreateEIP712ResponseData,\n DelegatedUserDecryptPayload,\n DelegatedUserDecryptResponseData,\n EncryptPayload,\n EncryptResponseData,\n GenerateKeypairRequest,\n GenerateKeypairResponseData,\n GetPublicKeyRequest,\n GetPublicKeyResponseData,\n GetPublicParamsRequest,\n GetPublicParamsResponseData,\n InitResponseData,\n PublicDecryptPayload,\n PublicDecryptResponseData,\n RequestZKProofVerificationRequest,\n RequestZKProofVerificationResponseData,\n UserDecryptPayload,\n UserDecryptResponseData,\n GenericLogger,\n WorkerEnv,\n WorkerRequest,\n WorkerRequestType,\n WorkerResponse,\n} from \"./worker.types\";\n\n/** Pending request tracker */\ninterface PendingRequest<T> {\n resolve: (value: T) => void;\n reject: (error: Error) => void;\n timeoutId: ReturnType<typeof setTimeout>;\n startTime: number;\n type: WorkerRequestType;\n}\n\n/** Default timeout for operations (30 seconds) */\nexport const DEFAULT_TIMEOUT_MS = 30_000;\n\n/** Extended timeout for WASM initialization (60 seconds) */\nexport const INIT_TIMEOUT_MS = 60_000;\n\n/**\n * Abstract base class for worker clients (browser Web Worker and Node.js worker_threads).\n * Encapsulates all shared logic: pending request tracking, timeouts, init dedup, domain methods.\n * Subclasses implement the abstract hooks for platform-specific worker creation and messaging.\n */\nexport abstract class BaseWorkerClient<TWorker, TConfig> {\n #worker: TWorker | null = null;\n #pendingRequests = new Map<string, PendingRequest<unknown>>();\n #initPromise: Promise<TWorker> | null = null;\n protected readonly config: TConfig;\n protected readonly logger: GenericLogger | undefined;\n\n constructor(config: TConfig, logger: GenericLogger | undefined) {\n this.config = config;\n this.logger = logger;\n }\n\n // ===========================================================================\n // Abstract hooks — subclasses must implement\n // ===========================================================================\n\n /** Create the platform-specific worker instance. */\n protected abstract createWorker(): TWorker;\n\n /** Wire message/error/messageerror events on the worker. */\n protected abstract wireEvents(worker: TWorker): void;\n\n /** Post a message to the worker. */\n protected abstract postMessage(worker: TWorker, request: WorkerRequest): void;\n\n /** Terminate the platform-specific worker. */\n protected abstract terminateWorker(worker: TWorker): void;\n\n /** Generate a unique request ID. */\n protected abstract generateRequestId(): string;\n\n /** Return the init request type and payload. */\n protected abstract getInitPayload(): {\n type: WorkerRequestType;\n payload: WorkerRequest[\"payload\"];\n };\n\n /** Subclasses set \"web\" or \"node\" — stamps the env discriminant on INIT payloads. */\n protected abstract readonly env: WorkerEnv;\n\n /** Optional hook called after worker init succeeds (e.g. for node worker.unref()). */\n protected onWorkerReady?(_worker: TWorker): void;\n\n // ===========================================================================\n // Shared init / terminate\n // ===========================================================================\n\n async initWorker(): Promise<TWorker> {\n if (this.#worker) {\n return this.#worker;\n }\n\n if (!this.#initPromise) {\n this.#initPromise = this.#doInitWorker().catch((error) => {\n this.#initPromise = null;\n throw error;\n });\n }\n return this.#initPromise;\n }\n\n async #doInitWorker(): Promise<TWorker> {\n const worker = this.createWorker();\n this.wireEvents(worker);\n\n try {\n const { type, payload } = this.getInitPayload();\n await this.sendRequestTo<InitResponseData>(worker, type, payload, INIT_TIMEOUT_MS);\n this.onWorkerReady?.(worker);\n this.#worker = worker;\n } catch (error) {\n this.terminateWorker(worker);\n throw error;\n }\n\n return this.#worker;\n }\n\n terminate(): void {\n if (this.#worker) {\n for (const [id, pending] of this.#pendingRequests) {\n clearTimeout(pending.timeoutId);\n pending.reject(new Error(\"Worker terminated\"));\n this.#pendingRequests.delete(id);\n }\n\n this.terminateWorker(this.#worker);\n this.#worker = null;\n }\n this.#initPromise = null;\n }\n\n // ===========================================================================\n // Message handling (called by subclass event wiring)\n // ===========================================================================\n\n protected handleResponse(response: WorkerResponse<unknown>): void {\n const pending = this.#pendingRequests.get(response.id);\n\n if (!pending) {\n this.logger?.warn(\"[WorkerClient] Received response for unknown request\", {\n id: response.id,\n });\n return;\n }\n\n const elapsed = Math.round(performance.now() - pending.startTime);\n\n clearTimeout(pending.timeoutId);\n this.#pendingRequests.delete(response.id);\n\n if (response.success) {\n this.logger?.debug(`[WorkerClient] ← ${pending.type} OK`, {\n id: response.id,\n elapsed,\n });\n pending.resolve(response.data);\n } else {\n this.logger?.error(`[WorkerClient] ← ${pending.type} FAILED`, {\n id: response.id,\n elapsed,\n error: response.error,\n });\n const err = new Error(response.error);\n if (\"statusCode\" in response && typeof response.statusCode === \"number\") {\n (err as Error & { statusCode?: number }).statusCode = response.statusCode;\n }\n pending.reject(err);\n }\n }\n\n protected handleWorkerError(message: string): void {\n this.logger?.error(\"[WorkerClient] Worker error\", { error: message });\n const worker = this.#worker;\n this.#worker = null;\n this.#rejectAllPending(`Worker error: ${message}`);\n if (worker) {\n this.terminateWorker(worker);\n }\n }\n\n protected handleWorkerMessageError(): void {\n this.logger?.error(\"[WorkerClient] Message deserialization failed\");\n const worker = this.#worker;\n this.#worker = null;\n this.#rejectAllPending(\"Worker message deserialization failed\");\n if (worker) {\n this.terminateWorker(worker);\n }\n }\n\n // ===========================================================================\n // Request sending\n // ===========================================================================\n\n protected sendRequestTo<T>(\n worker: TWorker,\n type: WorkerRequestType,\n payload: WorkerRequest[\"payload\"],\n timeoutMs: number = DEFAULT_TIMEOUT_MS,\n ): Promise<T> {\n return new Promise<T>((resolve, reject) => {\n const id = this.generateRequestId();\n const startTime = performance.now();\n this.logger?.debug(`[WorkerClient] → ${type}`, { id });\n\n const timeoutId = setTimeout(() => {\n this.#pendingRequests.delete(id);\n const elapsed = Math.round(performance.now() - startTime);\n this.logger?.error(`[WorkerClient] ${type} timed out after ${timeoutMs}ms`, {\n id,\n elapsed,\n });\n reject(new Error(`Request ${type} timed out after ${timeoutMs}ms`));\n }, timeoutMs);\n\n this.#pendingRequests.set(id, {\n resolve: resolve as (value: unknown) => void,\n reject,\n timeoutId,\n startTime,\n type,\n });\n\n const request = { id, type, payload } as WorkerRequest;\n this.postMessage(worker, request);\n });\n }\n\n protected async sendRequest<T>(\n type: WorkerRequestType,\n payload: WorkerRequest[\"payload\"],\n timeoutMs: number = DEFAULT_TIMEOUT_MS,\n ): Promise<T> {\n const worker = await this.initWorker();\n return this.sendRequestTo<T>(worker, type, payload, timeoutMs);\n }\n\n // ===========================================================================\n // Domain methods\n // ===========================================================================\n\n async generateKeypair(\n params: GenerateKeypairRequest[\"payload\"],\n ): Promise<GenerateKeypairResponseData> {\n return this.sendRequest<GenerateKeypairResponseData>(\"GENERATE_KEYPAIR\", params);\n }\n\n async createEIP712(params: CreateEIP712Payload): Promise<CreateEIP712ResponseData> {\n return this.sendRequest<CreateEIP712ResponseData>(\"CREATE_EIP712\", params);\n }\n\n async encrypt(params: EncryptPayload): Promise<EncryptResponseData> {\n return this.sendRequest<EncryptResponseData>(\"ENCRYPT\", params);\n }\n\n async userDecrypt(params: UserDecryptPayload): Promise<UserDecryptResponseData> {\n return this.sendRequest<UserDecryptResponseData>(\"USER_DECRYPT\", params);\n }\n\n async publicDecrypt(params: PublicDecryptPayload): Promise<PublicDecryptResponseData> {\n return this.sendRequest<PublicDecryptResponseData>(\"PUBLIC_DECRYPT\", params);\n }\n\n async createDelegatedUserDecryptEIP712(\n params: CreateDelegatedEIP712Payload,\n ): Promise<CreateDelegatedEIP712ResponseData> {\n return this.sendRequest<CreateDelegatedEIP712ResponseData>(\"CREATE_DELEGATED_EIP712\", params);\n }\n\n async delegatedUserDecrypt(\n params: DelegatedUserDecryptPayload,\n ): Promise<DelegatedUserDecryptResponseData> {\n return this.sendRequest<DelegatedUserDecryptResponseData>(\"DELEGATED_USER_DECRYPT\", params);\n }\n\n async requestZKProofVerification(\n params: RequestZKProofVerificationRequest[\"payload\"],\n ): Promise<RequestZKProofVerificationResponseData> {\n return this.sendRequest<RequestZKProofVerificationResponseData>(\n \"REQUEST_ZK_PROOF_VERIFICATION\",\n params,\n );\n }\n\n async getPublicKey(params: GetPublicKeyRequest[\"payload\"]): Promise<GetPublicKeyResponseData> {\n return this.sendRequest<GetPublicKeyResponseData>(\"GET_PUBLIC_KEY\", params);\n }\n\n async getPublicParams(\n params: GetPublicParamsRequest[\"payload\"],\n ): Promise<GetPublicParamsResponseData> {\n return this.sendRequest<GetPublicParamsResponseData>(\"GET_PUBLIC_PARAMS\", params);\n }\n\n // ===========================================================================\n // Internal helpers\n // ===========================================================================\n\n #rejectAllPending(message: string): void {\n for (const [id, pending] of this.#pendingRequests) {\n clearTimeout(pending.timeoutId);\n pending.reject(new Error(message));\n this.#pendingRequests.delete(id);\n }\n }\n}\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 { FheChain } from \"../chains/types\";\nimport type {\n GenericLogger,\n UpdateCsrfResponseData,\n WorkerEnv,\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 chains: FheChain[];\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 protected readonly env: WorkerEnv = \"web\";\n\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, chains, csrfToken, integrity, thread } = this.config;\n return {\n type: \"INIT\",\n payload: { env: \"web\" as const, cdnUrl, chains, csrfToken, integrity, thread },\n };\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 { CDN_INTEGRITY, CDN_URL, RelayerWeb } from \"../relayer/relayer-web\";\nimport { RelayerWorkerClient } from \"../worker/worker.client\";\nimport type { WebRelayerConfig, WebRelayerOptions } from \"./types\";\n\n/**\n * Browser relayer — routes to RelayerWeb (Web Worker + WASM).\n *\n * @param options - Worker options (threads, security, logger, storage).\n *\n * @example\n * ```ts\n * relayers: {\n * [sepolia.id]: web(),\n * [mainnet.id]: web({ threads: 4 }),\n * }\n * ```\n */\nexport function web(options?: WebRelayerOptions): WebRelayerConfig {\n return {\n type: \"web\",\n createWorker: (chains) =>\n new RelayerWorkerClient({\n cdnUrl: CDN_URL,\n chains,\n csrfToken: options?.security?.getCsrfToken?.() ?? \"\",\n integrity: options?.security?.integrityCheck === false ? undefined : CDN_INTEGRITY,\n logger: options?.logger,\n thread: options?.threads,\n }),\n createRelayer: (chain, worker) => new RelayerWeb({ chain, worker, ...options }),\n };\n}\n","import { ConfigurationError } from \"../errors\";\nimport { RelayerCleartext } from \"../relayer/cleartext/relayer-cleartext\";\nimport type { CleartextRelayerConfig } from \"./types\";\n\n/**\n * Cleartext relayer — routes to RelayerCleartext (no FHE infrastructure).\n *\n * When `executorAddress` is set on the chain definition (e.g. `hardhat`, `hoodi`),\n * it is picked up automatically.\n *\n * @example\n * ```ts\n * // executorAddress comes from the chain preset:\n * relayers: { [hardhat.id]: cleartext() }\n * ```\n */\nexport function cleartext(): CleartextRelayerConfig {\n return {\n type: \"cleartext\",\n createRelayer: (chain) => {\n if (!chain.executorAddress) {\n throw new ConfigurationError(\n `Cleartext relayer requires an executorAddress. ` +\n `Either use a chain preset that includes it (e.g. hardhat, hoodi) ` +\n `or set it on the chain definition.`,\n );\n }\n return new RelayerCleartext(chain);\n },\n };\n}\n","import type { FheChain } from \"../chains\";\nimport { buildZamaConfig } from \"./build\";\nimport type { ZamaConfig, ZamaConfigGeneric } from \"./types\";\n\n/**\n * Create a {@link ZamaConfig} from a custom {@link GenericSigner} and\n * {@link GenericProvider}. Use this when the built-in adapter paths\n * (`@zama-fhe/sdk/viem`, `@zama-fhe/sdk/ethers`, `@zama-fhe/react-sdk/wagmi`)\n * don't cover your setup — e.g. a server-side relayer that implements\n * `GenericSigner` directly.\n *\n * @example\n * ```ts\n * import { createConfig, web, memoryStorage } from \"@zama-fhe/sdk\";\n * import { sepolia } from \"@zama-fhe/sdk/chains\";\n *\n * const config = createConfig({\n * chains: [sepolia],\n * signer: myCustomSigner,\n * provider: myCustomProvider,\n * storage: memoryStorage,\n * relayers: { [sepolia.id]: web() },\n * });\n * const sdk = new ZamaSDK(config);\n * ```\n */\nexport function createConfig<const TChains extends readonly [FheChain, ...FheChain[]]>(\n params: ZamaConfigGeneric<TChains>,\n): ZamaConfig {\n return buildZamaConfig(params.signer, params.provider, params);\n}\n","import { getAddress, type Address } from \"viem\";\nimport type { ClearValueType, Handle } from \"./relayer/relayer-sdk.types\";\nimport type { GenericStorage } from \"./types\";\n\n/**\n * Storage-backed cache for decrypted FHE plaintext values.\n *\n * Each entry is keyed by `(requester, contractAddress, handle)` so that\n * different signers cannot read each other's cached decryptions — this\n * mirrors the on-chain ACL where only the handle owner (or delegate) is\n * authorized to decrypt.\n *\n * Addresses are checksummed and handles lowercased, making lookups\n * case-insensitive. A separate index (`zama:decrypt:keys`) tracks all\n * stored cache keys so {@link clearForRequester} and {@link clearAll} can\n * enumerate entries without a full storage scan. Index writes are\n * serialised through a micro-queue to prevent concurrent `set` calls\n * from losing entries.\n *\n * All public methods are **best-effort**: storage errors are caught and\n * swallowed — the cache never throws.\n *\n * Cache storage key format:\n * ```\n * zama:decrypt:{checksumAddress}:{checksumAddress}:{lowercaseHandle}\n * ```\n *\n * Lifecycle:\n * - Populated by {@link ZamaSDK.decrypt} after relayer calls.\n * - Cleared by {@link ZamaSDK.revoke} / {@link ZamaSDK.revokeSession} (per-requester).\n * - Cleared by signer lifecycle events (disconnect, account change, chain change).\n * - Survives page reloads when backed by persistent storage (e.g. IndexedDB).\n */\nexport class DecryptCache {\n readonly #storage: GenericStorage;\n readonly #decryptNamespace = \"zama:decrypt\";\n readonly #decryptKeysNamespace = `${this.#decryptNamespace}:keys`;\n /** Serialises concurrent writes to the keys index. */\n #indexWriteQueue: Promise<void> = Promise.resolve();\n\n constructor(storage: GenericStorage) {\n this.#storage = storage;\n }\n\n /** Returns the cached clear value or `null` on a miss / error. */\n async get(\n requester: Address,\n contractAddress: Address,\n handle: Handle,\n ): Promise<ClearValueType | null> {\n try {\n const key = this.#buildStorageKey(requester, contractAddress, handle);\n return await this.#storage.get<ClearValueType>(key);\n } catch (error) {\n console.warn(\"[zama-sdk] DecryptCache.get failed:\", error); // eslint-disable-line no-console\n return null;\n }\n }\n\n /** Stores `value` for the given `(requester, contractAddress, handle)` tuple. */\n async set(\n requester: Address,\n contractAddress: Address,\n handle: Handle,\n value: ClearValueType,\n ): Promise<void> {\n try {\n const key = this.#buildStorageKey(requester, contractAddress, handle);\n await this.#storage.set<ClearValueType>(key, value);\n // Track the key in the index (serialised to avoid concurrent overwrites)\n this.#indexWriteQueue = this.#indexWriteQueue.then(() =>\n this.#addToIndex(key).catch((error) => {\n console.warn(\"[zama-sdk] DecryptCache index write failed:\", error); // eslint-disable-line no-console\n }),\n );\n await this.#indexWriteQueue;\n } catch (error) {\n console.warn(\"[zama-sdk] DecryptCache.set failed:\", error); // eslint-disable-line no-console\n }\n }\n\n /** Removes all cached entries for the given `requester`. */\n async clearForRequester(requester: Address): Promise<void> {\n // Serialise with the index write queue to avoid racing with concurrent set() calls\n this.#indexWriteQueue = this.#indexWriteQueue.then(() =>\n this.#doClearForRequester(requester).catch((error) => {\n console.warn(\"[zama-sdk] DecryptCache.clearForRequester failed:\", error); // eslint-disable-line no-console\n }),\n );\n await this.#indexWriteQueue;\n }\n\n async #doClearForRequester(requester: Address): Promise<void> {\n const checksumRequester = getAddress(requester);\n const prefix = `${this.#decryptNamespace}:${checksumRequester}:`;\n const keys = await this.#readIndex();\n const toRemove: string[] = [];\n const remaining: string[] = [];\n for (const k of keys) {\n if (k.startsWith(prefix)) {\n toRemove.push(k);\n } else {\n remaining.push(k);\n }\n }\n await Promise.all(toRemove.map((k) => this.#storage.delete(k).catch(() => {})));\n await this.#storage.set(this.#decryptKeysNamespace, remaining);\n }\n\n /** Removes all cached entries. */\n async clearAll(): Promise<void> {\n // Serialise with the index write queue to avoid racing with concurrent set() calls\n this.#indexWriteQueue = this.#indexWriteQueue.then(() =>\n this.#doClearAll().catch((error) => {\n console.warn(\"[zama-sdk] DecryptCache.clearAll failed:\", error); // eslint-disable-line no-console\n }),\n );\n await this.#indexWriteQueue;\n }\n\n async #doClearAll(): Promise<void> {\n const keys = await this.#readIndex();\n await Promise.all(keys.map((k) => this.#storage.delete(k).catch(() => {})));\n await this.#storage.delete(this.#decryptKeysNamespace);\n }\n\n #buildStorageKey(requester: Address, contractAddress: Address, handle: Handle): string {\n return `${this.#decryptNamespace}:${getAddress(requester)}:${getAddress(contractAddress)}:${handle.toLowerCase()}`;\n }\n\n async #readIndex(): Promise<string[]> {\n return (await this.#storage.get<string[]>(this.#decryptKeysNamespace)) ?? [];\n }\n\n async #addToIndex(key: string): Promise<void> {\n const keys = await this.#readIndex();\n if (!keys.includes(key)) {\n keys.push(key);\n await this.#storage.set(this.#decryptKeysNamespace, keys);\n }\n }\n}\n","import type { Address, Hex } from \"viem\";\nimport { prefixHex } from \"../utils\";\n\n/** Encrypted data format with IV for AES-GCM decryption. */\nexport interface EncryptedData {\n /** Base64-encoded initialization vector. */\n iv: string;\n /** Base64-encoded ciphertext. */\n ciphertext: string;\n}\n\n/**\n * Manages AES-GCM encryption and decryption of FHE private keys.\n *\n * The encryption key is derived from a wallet signature via PBKDF2\n * (600 000 iterations, SHA-256). The signature is a secret known only\n * to the wallet holder, providing meaningful encryption protection\n * for the stored private key.\n *\n * The derived key is cached internally so that repeated encrypt/decrypt\n * calls with the same (signature, address) pair skip the expensive\n * PBKDF2 derivation.\n */\nexport class CredentialCrypto {\n #cachedDerivedKey: CryptoKey | null = null;\n #cachedDerivedKeyIdentity: string | null = null;\n\n /** Clear the cached derived key. Call when the session is revoked or the signer changes. */\n clearCache(): void {\n this.#cachedDerivedKey = null;\n this.#cachedDerivedKeyIdentity = null;\n }\n\n /** Encrypt an FHE private key using AES-GCM with a key derived from the wallet signature. */\n async encrypt(plaintext: Hex, signature: Hex, address: Address): Promise<EncryptedData> {\n const key = await this.#deriveKey(signature, address);\n const iv = crypto.getRandomValues(new Uint8Array(12));\n const encoder = new TextEncoder();\n\n const ciphertext = await crypto.subtle.encrypt(\n { name: \"AES-GCM\", iv },\n key,\n encoder.encode(plaintext),\n );\n\n return {\n iv: btoa(String.fromCharCode(...iv)),\n ciphertext: btoa(String.fromCharCode(...new Uint8Array(ciphertext))),\n };\n }\n\n /** Decrypt an AES-GCM encrypted FHE private key using a key derived from the wallet signature. */\n async decrypt(encrypted: EncryptedData, signature: Hex, address: Address): Promise<Hex> {\n const key = await this.#deriveKey(signature, address);\n const iv = Uint8Array.from(atob(encrypted.iv), (c) => c.charCodeAt(0));\n const ciphertext = Uint8Array.from(atob(encrypted.ciphertext), (c) => c.charCodeAt(0));\n\n const plaintext = await crypto.subtle.decrypt({ name: \"AES-GCM\", iv }, key, ciphertext);\n\n return prefixHex(new TextDecoder().decode(plaintext));\n }\n\n async #deriveKey(signature: Hex, address: Address): Promise<CryptoKey> {\n const identity = `${signature}:${address}`;\n if (this.#cachedDerivedKey && this.#cachedDerivedKeyIdentity === identity) {\n return this.#cachedDerivedKey;\n }\n\n const encoder = new TextEncoder();\n const keyMaterial = await crypto.subtle.importKey(\n \"raw\",\n encoder.encode(signature),\n \"PBKDF2\",\n false,\n [\"deriveKey\"],\n );\n\n const key = await crypto.subtle.deriveKey(\n {\n name: \"PBKDF2\",\n salt: encoder.encode(address),\n iterations: 600_000,\n hash: \"SHA-256\",\n },\n keyMaterial,\n { name: \"AES-GCM\", length: 256 },\n false,\n [\"encrypt\", \"decrypt\"],\n );\n\n this.#cachedDerivedKeyIdentity = identity;\n this.#cachedDerivedKey = key;\n return key;\n }\n}\n","import { getAddress, isAddress, type Address, type Hex } from \"viem\";\nimport { assertArray, assertCondition, assertObject, assertString } from \"../utils\";\nimport type { EncryptedData } from \"./credential-crypto\";\n\n/** Encrypted credential shape stored in persistent storage (shared base fields). */\nexport interface BaseEncryptedCredentials {\n publicKey: Hex;\n contractAddresses: Address[];\n encryptedPrivateKey: EncryptedData;\n startTimestamp: number;\n durationDays: number;\n}\n\n/**\n * Assert that `data` contains the base encrypted credential fields:\n * publicKey, contractAddresses (valid hex addresses), and encryptedPrivateKey (iv + ciphertext).\n */\nexport function assertBaseEncryptedCredentials(\n data: unknown,\n): asserts data is BaseEncryptedCredentials {\n assertObject(data, \"Stored credentials\");\n assertString(data.publicKey, \"credentials.publicKey\");\n assertArray(data.contractAddresses, \"credentials.contractAddresses\");\n for (const addr of data.contractAddresses) {\n assertCondition(\n typeof addr === \"string\" && isAddress(addr, { strict: false }),\n `Expected each contractAddress to be a valid hex address`,\n );\n }\n assertObject(data.encryptedPrivateKey, \"credentials.encryptedPrivateKey\");\n assertString(data.encryptedPrivateKey.iv, \"encryptedPrivateKey.iv\");\n assertString(data.encryptedPrivateKey.ciphertext, \"encryptedPrivateKey.ciphertext\");\n assertCondition(\n typeof data.startTimestamp === \"number\",\n \"Expected credentials.startTimestamp to be a number\",\n );\n assertCondition(\n typeof data.durationDays === \"number\",\n \"Expected credentials.durationDays to be a number\",\n );\n}\n\n/**\n * Assert that `data` contains the delegated-specific fields:\n * delegatorAddress, delegateAddress (valid addresses), startTimestamp and durationDays (numbers).\n */\nexport function assertDelegatedFields(data: unknown): asserts data is BaseEncryptedCredentials & {\n delegatorAddress: Address;\n delegateAddress: Address;\n} {\n assertBaseEncryptedCredentials(data);\n const obj = data as unknown as Record<string, unknown>;\n assertCondition(\n typeof obj.delegatorAddress === \"string\" && isAddress(obj.delegatorAddress, { strict: false }),\n \"Expected credentials.delegatorAddress to be a valid address\",\n );\n assertCondition(\n typeof obj.delegateAddress === \"string\" && isAddress(obj.delegateAddress, { strict: false }),\n \"Expected credentials.delegateAddress to be a valid address\",\n );\n assertCondition(typeof obj.startTimestamp === \"number\", \"Expected startTimestamp to be a number\");\n assertCondition(typeof obj.durationDays === \"number\", \"Expected durationDays to be a number\");\n}\n\n/** Check if credentials are still within their keypair TTL. */\nexport function isTimeValid(creds: { startTimestamp: number; durationDays: number }): boolean {\n const nowSeconds = Math.floor(Date.now() / 1000);\n const expiresAt = creds.startTimestamp + creds.durationDays * 86400;\n return nowSeconds < expiresAt;\n}\n\n/** Check if the signed address set covers all required addresses. */\nexport function coversContracts(signedAddresses: Address[], requiredContracts: Address[]): boolean {\n const required = new Set(requiredContracts.map((address) => getAddress(address)));\n const signed = new Set(signedAddresses.map((address) => getAddress(address)));\n return required.isSubsetOf(signed);\n}\n\n/**\n * Check if credentials are valid: not time-expired and covering all required contracts.\n */\nexport function isCredentialValid(\n creds: { startTimestamp: number; durationDays: number; contractAddresses: Address[] },\n requiredContracts: Address[],\n): boolean {\n if (!isTimeValid(creds)) {\n return false;\n }\n return coversContracts(creds.contractAddresses, requiredContracts);\n}\n\n/** Deduplicate and sort a list of addresses by their checksummed form. */\nexport function normalizeAddresses(addresses: Address[]): Address[] {\n return [...new Set(addresses.map((address) => getAddress(address)))].toSorted();\n}\n\n/** Compute a truncated SHA-256 store key from arbitrary identity segments. */\nexport async function computeStoreKey(...segments: (string | number)[]): Promise<string> {\n const hash = await crypto.subtle.digest(\n \"SHA-256\",\n new TextEncoder().encode(segments.map(String).join(\":\")),\n );\n return Array.from(new Uint8Array(hash))\n .map((b) => b.toString(16).padStart(2, \"0\"))\n .join(\"\")\n .slice(0, 32);\n}\n","import type { Hex } from \"viem\";\nimport { assertCondition, assertObject, assertString } from \"../utils\";\nimport type { GenericStorage } from \"../types\";\n\n/** Structured session entry stored in session storage. */\nexport interface SessionEntry {\n /** EIP-712 wallet signature authorizing decryption. */\n signature: Hex;\n /** Epoch seconds when the session was created. */\n createdAt: number;\n /** TTL at creation time (not current config). `0` = always expired, `\"infinite\"` = never expires. */\n ttl: number | \"infinite\";\n}\n\n/**\n * Manages session signature entries in a {@link GenericStorage} backend.\n *\n * A session entry caches a wallet signature so that subsequent decrypt\n * operations can reuse it without prompting the user again. The TTL\n * is recorded at creation time so that changing the config later does\n * not retroactively extend or shorten existing sessions.\n */\nexport class SessionSignatures {\n #storage: GenericStorage;\n\n constructor(storage: GenericStorage) {\n this.#storage = storage;\n }\n\n #assertSessionEntry(data: unknown): asserts data is SessionEntry {\n assertObject(data, \"Session entry\");\n assertString(data.signature, \"session.signature\");\n assertCondition(\n typeof data.createdAt === \"number\",\n `Expected session.createdAt to be a number`,\n );\n assertCondition(\n typeof data.ttl === \"number\" || data.ttl === \"infinite\",\n `Expected session.ttl to be a number or \"infinite\"`,\n );\n }\n\n /** Retrieve and validate a session entry, or `null` if none exists. */\n async get(key: string): Promise<SessionEntry | null> {\n const raw = await this.#storage.get<SessionEntry>(key);\n if (raw === null) {\n return null;\n }\n this.#assertSessionEntry(raw);\n return raw;\n }\n\n /** Create and store a session entry with the given TTL. */\n async set(params: { key: string; signature: Hex; ttl: number | \"infinite\" }): Promise<void> {\n const entry: SessionEntry = {\n signature: params.signature,\n createdAt: Math.floor(Date.now() / 1000),\n ttl: params.ttl,\n };\n await this.#storage.set(params.key, entry);\n }\n\n /** Delete a session entry. */\n async delete(key: string): Promise<void> {\n await this.#storage.delete(key);\n }\n\n /**\n * Check if a session entry has expired based on its recorded TTL.\n * - `0` = always expired (every operation triggers a signing prompt).\n * - `\"infinite\"` = never expires.\n * - Positive number = seconds until expiration.\n */\n isExpired(entry: SessionEntry): boolean {\n if (entry.ttl === \"infinite\") {\n return false;\n }\n if (entry.ttl === 0) {\n return true;\n }\n return Math.floor(Date.now() / 1000) - entry.createdAt >= entry.ttl;\n }\n}\n","import type { Address, Hex } from \"viem\";\nimport { ZamaError } from \"../errors/base\";\nimport { wrapSigningError } from \"../errors/signing\";\nimport type { ZamaSDKEventInput, ZamaSDKEventListener } from \"../events/sdk-events\";\nimport { ZamaSDKEvents } from \"../events/sdk-events\";\nimport type { GenericSigner, GenericStorage, StoredCredentials } from \"../types\";\nimport { toError } from \"../utils/error\";\nimport { CredentialCrypto } from \"./credential-crypto\";\nimport type { BaseEncryptedCredentials } from \"./credential-validation\";\nimport {\n coversContracts,\n isCredentialValid,\n isTimeValid,\n normalizeAddresses,\n} from \"./credential-validation\";\nimport { SessionSignatures } from \"./session-signatures\";\n\n/** Shared configuration accepted by both credential manager variants. */\nexport interface CredentialsConfig {\n /** Backend that generates FHE keypairs (public/private). */\n relayer: { generateKeypair(): Promise<{ publicKey: Hex; privateKey: Hex }> };\n /** Wallet signer used for EIP-712 authorization signatures. */\n signer: GenericSigner;\n /** Persistent storage for encrypted credentials. */\n storage: GenericStorage;\n /** Storage for session signatures (shorter-lived than credentials). */\n sessionStorage: GenericStorage;\n /** FHE keypair lifetime in seconds. Defaults to `2592000` (30 days). */\n keypairTTL?: number;\n /** Session signature lifetime. `0` = always re-sign, `\"infinite\"` = never expire. Defaults to `2592000` (30 days). */\n sessionTTL?: number | \"infinite\";\n /** Optional listener for credential lifecycle events. */\n onEvent?: ZamaSDKEventListener;\n}\n\n/** Minimal fields needed to produce an EIP-712 signing request. */\nexport interface SigningMeta {\n /** FHE public key being authorized. */\n publicKey: Hex;\n /** Epoch seconds when the keypair authorization begins. */\n startTimestamp: number;\n /** Number of days the keypair authorization is valid for. */\n durationDays: number;\n /** Delegator address, present only for delegated credentials. */\n delegatorAddress?: string;\n}\n\n/** Options for {@link BaseCredentialsManager.resolveCredentials}. */\ninterface ResolveCredentialsOptions<TCreds> {\n /** Storage key identifying the credential entry. */\n key: string;\n /** Contract addresses the caller needs access to. */\n contracts: Address[];\n /** Deduplication key — concurrent calls with the same key share a single creation promise. */\n createKey: string;\n /** Factory that creates fresh credentials when nothing usable is cached. */\n createFn: () => Promise<TCreds>;\n}\n\n/** Options for {@link BaseCredentialsManager.createCredentials}. */\ninterface CreateCredentialsOptions<TCreds> {\n /** Storage key identifying the credential entry. */\n key: string;\n /** Contract addresses being authorized. */\n contractAddresses: Address[];\n /** Factory that builds the credential payload (keypair + signature). */\n createFn: () => Promise<TCreds>;\n /** Human-readable context included in signing error messages. */\n errorContext: string;\n}\n\n/**\n * Abstract base for credential managers. Contains the entire allow/extend/expire\n * state machine. Subclasses provide the assertion, signing, and encrypt/decrypt\n * hooks that differ between regular and delegated flows.\n *\n * @typeParam TCreds - The in-memory credential shape (includes plaintext privateKey).\n * @typeParam TEncrypted - The on-disk shape (privateKey replaced by encryptedPrivateKey).\n */\nexport abstract class BaseCredentialsManager<\n TCreds extends StoredCredentials,\n TEncrypted extends BaseEncryptedCredentials,\n> {\n protected readonly signer: GenericSigner;\n protected readonly storage: GenericStorage;\n protected readonly sessionSignatures: SessionSignatures;\n protected readonly crypto: CredentialCrypto;\n readonly keypairTTL: number;\n readonly sessionTTL: number | \"infinite\";\n\n #onEvent: ZamaSDKEventListener;\n #createPromise: Promise<TCreds> | null = null;\n #createPromiseKey: string | null = null;\n #extendPromise: Promise<TCreds> | null = null;\n /** Last successfully resolved extension result, used to recover from the race where a\n * concurrent call enters #extendContracts after #extendPromise was already cleared. */\n #lastExtendResult: TCreds | null = null;\n\n constructor(config: CredentialsConfig) {\n this.signer = config.signer;\n this.storage = config.storage;\n this.sessionSignatures = new SessionSignatures(config.sessionStorage);\n this.crypto = new CredentialCrypto();\n this.keypairTTL = config.keypairTTL ?? 2592000;\n this.sessionTTL = config.sessionTTL ?? 2592000;\n this.#onEvent = config.onEvent ?? (() => {});\n\n if (typeof this.keypairTTL === \"number\" && this.keypairTTL < 0) {\n throw new Error(\"keypairTTL must be >= 0\");\n }\n if (typeof this.sessionTTL === \"number\" && this.sessionTTL < 0) {\n throw new Error(\"sessionTTL must be >= 0\");\n }\n if (typeof this.sessionTTL === \"number\" && this.sessionTTL > this.keypairTTL) {\n this.sessionTTL = this.keypairTTL;\n // oxlint-disable-next-line no-console\n console.warn(\n `[zama-sdk] sessionTTL was clamped to keypairTTL (${this.keypairTTL}s). ` +\n \"A session that outlives the keypair causes isAllowed() to return true \" +\n \"after the keypair expires, leading to unexpected wallet prompts.\",\n );\n }\n }\n\n /** Emit a credential lifecycle event, stamped with the current time. */\n protected emit(partial: ZamaSDKEventInput): void {\n this.#onEvent({ ...partial, timestamp: Date.now() } as never);\n }\n\n // ── Abstract hooks ────────────────────────────────────────────\n\n /** Validate that raw storage data matches the expected encrypted shape. */\n protected abstract assertEncrypted(data: unknown): asserts data is TEncrypted;\n\n /** Sign an EIP-712 authorization for the given contract addresses. */\n protected abstract signForContracts(\n meta: SigningMeta,\n contractAddresses: Address[],\n ): Promise<Hex>;\n\n /** Encrypt credentials for persistent storage. */\n protected abstract encryptCredentials(creds: TCreds): Promise<TEncrypted>;\n\n /** Decrypt credentials from persistent storage. */\n protected abstract decryptCredentials(encrypted: TEncrypted, signature: Hex): Promise<TCreds>;\n\n // ── Core credential resolution ────────────────────────────────\n\n /**\n * The allow() state machine: load → validate → extend/re-sign → or create fresh.\n * Subclasses call this from their public `allow()` after computing the key.\n */\n protected async resolveCredentials({\n key,\n contracts,\n createKey,\n createFn,\n }: ResolveCredentialsOptions<TCreds>): Promise<TCreds> {\n this.emit({\n type: ZamaSDKEvents.CredentialsLoading,\n contractAddresses: contracts,\n });\n\n try {\n const encrypted = await this.storage.get<TEncrypted>(key);\n if (encrypted) {\n this.assertEncrypted(encrypted);\n\n const sessionEntry = await this.sessionSignatures.get(key);\n if (sessionEntry) {\n if (this.sessionSignatures.isExpired(sessionEntry)) {\n await this.sessionSignatures.delete(key);\n this.emit({ type: ZamaSDKEvents.SessionExpired, reason: \"ttl\" });\n } else {\n const creds = await this.decryptCredentials(encrypted, sessionEntry.signature);\n if (isCredentialValid(creds, contracts)) {\n this.emit({\n type: ZamaSDKEvents.CredentialsCached,\n contractAddresses: contracts,\n });\n this.emit({\n type: ZamaSDKEvents.CredentialsAllowed,\n contractAddresses: contracts,\n });\n return creds;\n }\n if (isTimeValid(creds)) {\n return this.#extendContracts({\n key,\n credentials: creds,\n requiredContracts: contracts,\n });\n }\n this.emit({\n type: ZamaSDKEvents.CredentialsExpired,\n contractAddresses: contracts,\n });\n }\n }\n\n // No session or expired — need to re-sign\n if (isTimeValid(encrypted)) {\n if (coversContracts(encrypted.contractAddresses, contracts)) {\n const signature = await this.signForContracts(encrypted, encrypted.contractAddresses);\n await this.sessionSignatures.set({\n key,\n signature,\n ttl: this.sessionTTL,\n });\n const creds = await this.decryptCredentials(encrypted, signature);\n this.emit({\n type: ZamaSDKEvents.CredentialsCached,\n contractAddresses: contracts,\n });\n this.emit({\n type: ZamaSDKEvents.CredentialsAllowed,\n contractAddresses: contracts,\n });\n return creds;\n }\n // Time-valid but missing contracts — sign with old set to decrypt, then extend\n const oldSignature = await this.signForContracts(encrypted, encrypted.contractAddresses);\n const creds = await this.decryptCredentials(encrypted, oldSignature);\n return this.#extendContracts({\n key,\n credentials: creds,\n requiredContracts: contracts,\n });\n }\n\n this.emit({\n type: ZamaSDKEvents.CredentialsExpired,\n contractAddresses: contracts,\n });\n }\n } catch (error) {\n if (error instanceof ZamaError) {\n throw error;\n }\n // oxlint-disable-next-line no-console\n console.warn(\"[zama-sdk] Credential resolution failed, recreating:\", error);\n this.emit({\n type: ZamaSDKEvents.CredentialsCorrupted,\n error: toError(error),\n });\n await this.#deleteCredentials(key);\n }\n\n // Nothing cached — create fresh (deduplicated)\n if (!this.#createPromise || this.#createPromiseKey !== createKey) {\n this.#createPromiseKey = createKey;\n this.#createPromise = createFn()\n .then((creds) => {\n this.emit({\n type: ZamaSDKEvents.CredentialsAllowed,\n contractAddresses: contracts,\n });\n return creds;\n })\n .finally(() => {\n this.#createPromise = null;\n this.#createPromiseKey = null;\n });\n }\n return this.#createPromise;\n }\n\n // ── Shared public method implementations ──────────────────────\n\n /**\n * Check whether stored credentials are expired or don't cover the given contract.\n * Returns `true` if stored credentials are expired or corrupted.\n * Returns `false` if no credentials exist yet.\n */\n protected async checkExpired(key: string, contractAddress?: Address): Promise<boolean> {\n try {\n const stored = await this.storage.get<TEncrypted>(key);\n if (!stored) {\n return false;\n }\n this.assertEncrypted(stored);\n const requiredContracts = contractAddress ? [contractAddress] : [];\n return !isCredentialValid(stored, requiredContracts);\n } catch (error) {\n // oxlint-disable-next-line no-console\n console.warn(\"[zama-sdk] isExpired check failed, treating as expired:\", error);\n return true;\n }\n }\n\n /** Delete the session signature and clear caches, forcing a fresh wallet signature on next use. */\n protected async revokeSession(key: string, contractAddresses?: Address[]): Promise<void> {\n await this.sessionSignatures.delete(key);\n this.clearCaches();\n this.emit({\n type: ZamaSDKEvents.CredentialsRevoked,\n ...(contractAddresses ? { contractAddresses } : {}),\n } as ZamaSDKEventInput);\n }\n\n protected async checkAllowed(\n key: string,\n contractAddresses: [Address, ...Address[]],\n ): Promise<boolean> {\n // Runtime guard: credentials are always contract-scoped,\n // so an empty contract list must never resolve to \"allowed\"\n // (the compile-time tuple type can be bypassed via casts).\n if (contractAddresses.length === 0) {\n return false;\n }\n const entry = await this.sessionSignatures.get(key);\n if (entry === null) {\n return false;\n }\n if (this.sessionSignatures.isExpired(entry)) {\n return false;\n }\n try {\n const stored = await this.storage.get<TEncrypted>(key);\n if (!stored) {\n return false;\n }\n this.assertEncrypted(stored);\n return isCredentialValid(stored, contractAddresses);\n } catch {\n return false;\n }\n }\n\n protected async clearAll(key: string): Promise<void> {\n await this.sessionSignatures.delete(key);\n this.clearCaches();\n await this.#deleteCredentials(key);\n }\n\n /** Override to also clear subclass-specific caches (e.g. key cache). */\n protected clearCaches(): void {\n this.crypto.clearCache();\n this.#lastExtendResult = null;\n }\n\n // ── Credential creation helper ────────────────────────────────\n\n /**\n * Shared wrapper for fresh credential creation:\n * emits events, persists, saves session, and wraps signing errors.\n */\n protected async createCredentials({\n key,\n contractAddresses,\n createFn,\n errorContext,\n }: CreateCredentialsOptions<TCreds>): Promise<TCreds> {\n this.emit({ type: ZamaSDKEvents.CredentialsCreating, contractAddresses });\n try {\n const creds = await createFn();\n await this.persistCredentials(key, creds);\n await this.sessionSignatures.set({\n key,\n signature: creds.signature,\n ttl: this.sessionTTL,\n });\n this.emit({ type: ZamaSDKEvents.CredentialsCreated, contractAddresses });\n return creds;\n } catch (error) {\n if (error instanceof ZamaError) {\n throw error;\n }\n return wrapSigningError(error, errorContext);\n }\n }\n\n // ── Contract extension ────────────────────────────────────────\n\n async #extendContracts({\n key,\n credentials,\n requiredContracts,\n }: {\n key: string;\n credentials: TCreds;\n requiredContracts: Address[];\n }): Promise<TCreds> {\n if (this.#extendPromise) {\n const previous = await this.#extendPromise;\n if (coversContracts(previous.contractAddresses, requiredContracts)) {\n this.emit({\n type: ZamaSDKEvents.CredentialsAllowed,\n contractAddresses: requiredContracts,\n });\n return previous;\n }\n credentials = previous;\n } else if (this.#lastExtendResult) {\n // A concurrent extension may have resolved and cleared #extendPromise before\n // this call entered. Use the last known result as the base to avoid dropping\n // contract addresses merged by the just-completed extension.\n const last = this.#lastExtendResult;\n if (coversContracts(last.contractAddresses, requiredContracts)) {\n this.emit({\n type: ZamaSDKEvents.CredentialsAllowed,\n contractAddresses: requiredContracts,\n });\n return last;\n }\n credentials = last;\n }\n\n const promise = this.#extendCredentials({\n key,\n credentials,\n requiredContracts,\n });\n this.#extendPromise = promise;\n try {\n const result = await promise;\n this.#lastExtendResult = result;\n return result;\n } finally {\n if (this.#extendPromise === promise) {\n this.#extendPromise = null;\n }\n }\n }\n\n async #extendCredentials({\n key,\n credentials,\n requiredContracts,\n }: {\n key: string;\n credentials: TCreds;\n requiredContracts: Address[];\n }): Promise<TCreds> {\n const merged = normalizeAddresses([...credentials.contractAddresses, ...requiredContracts]);\n const signature = await this.signForContracts(credentials, merged);\n\n const extended: TCreds = {\n ...credentials,\n contractAddresses: merged,\n signature,\n };\n // Persist ciphertext before session signature to prevent a window where a\n // concurrent reader sees the new signature but finds old ciphertext.\n await this.persistCredentials(key, extended);\n await this.sessionSignatures.set({\n key,\n signature,\n ttl: this.sessionTTL,\n });\n this.emit({\n type: ZamaSDKEvents.CredentialsAllowed,\n contractAddresses: requiredContracts,\n });\n return extended;\n }\n\n protected async persistCredentials(key: string, credentials: TCreds): Promise<void> {\n try {\n const encrypted = await this.encryptCredentials(credentials);\n await this.storage.set(key, encrypted);\n } catch (error) {\n // oxlint-disable-next-line no-console\n console.warn(\"[zama-sdk] Failed to encrypt credentials for persistence:\", error);\n this.emit({\n type: ZamaSDKEvents.CredentialsPersistFailed,\n error: toError(error),\n });\n }\n }\n\n async #deleteCredentials(key: string): Promise<void> {\n try {\n await this.storage.delete(key);\n } catch (error) {\n // oxlint-disable-next-line no-console\n console.warn(\"[zama-sdk] Failed to delete credentials:\", error);\n this.emit({\n type: ZamaSDKEvents.CredentialsPersistFailed,\n error: toError(error),\n });\n }\n }\n}\n","import { getAddress, type Address, type Hex } from \"viem\";\nimport type { RelayerSDK } from \"../relayer/relayer-sdk\";\nimport type { SignerIdentity, StoredCredentials } from \"../types\";\nimport { MemoryStorage } from \"../storage/memory-storage\";\nimport {\n BaseCredentialsManager,\n type CredentialsConfig,\n type SigningMeta,\n} from \"./credentials-manager-base\";\nimport {\n type BaseEncryptedCredentials,\n assertBaseEncryptedCredentials,\n normalizeAddresses,\n computeStoreKey,\n} from \"./credential-validation\";\n\n/** Internal storage shape — same as BaseEncryptedCredentials. */\ntype EncryptedCredentials = BaseEncryptedCredentials;\n\n/** Configuration for constructing a {@link CredentialsManager}. */\nexport interface CredentialsManagerConfig extends CredentialsConfig {\n /** FHE relayer backend for keypair generation and EIP-712 creation. */\n relayer: RelayerSDK;\n}\n\nfunction hasExtensionRuntimeId(value: unknown): value is { runtime: { id: string } } {\n if (typeof value !== \"object\" || value === null) {\n return false;\n }\n const runtime = Reflect.get(value, \"runtime\");\n if (typeof runtime !== \"object\" || runtime === null) {\n return false;\n }\n return typeof Reflect.get(runtime, \"id\") === \"string\";\n}\n\n/**\n * Manages FHE decrypt credentials for a single wallet.\n * Handles keypair generation, EIP-712 authorization signing, and\n * encrypted persistence scoped to a (wallet address, chain ID) pair.\n */\nexport class CredentialsManager extends BaseCredentialsManager<\n StoredCredentials,\n EncryptedCredentials\n> {\n #relayer: RelayerSDK;\n #cachedStoreKey: string | null = null;\n #cachedStoreKeyIdentity: string | null = null;\n\n /** Derive the deterministic storage key for a given wallet address and chain. */\n static async computeStoreKey(address: Address, chainId: number): Promise<string> {\n return computeStoreKey(getAddress(address), chainId);\n }\n\n constructor(config: CredentialsManagerConfig) {\n super(config);\n this.#relayer = config.relayer;\n\n // Warn when using in-memory session storage inside a Chrome extension context\n const chromeNamespace =\n typeof globalThis !== \"undefined\" ? Reflect.get(globalThis, \"chrome\") : undefined;\n if (hasExtensionRuntimeId(chromeNamespace) && config.sessionStorage instanceof MemoryStorage) {\n // oxlint-disable-next-line no-console\n console.warn(\n \"[zama-sdk] Detected Chrome extension context with in-memory session storage. \" +\n \"Session signatures will be lost on service worker restart and won't be shared across contexts. \" +\n \"Consider using chromeSessionStorage instead. \",\n );\n }\n }\n\n // ── Public API ────────────────────────────────────────────────\n\n /**\n * Authorize FHE credentials for one or more contract addresses.\n *\n * @throws {@link SigningRejectedError} if the user rejects the wallet signature prompt.\n * @throws {@link SigningFailedError} if the signing operation fails for any other reason.\n */\n async allow(...contractAddresses: Address[]): Promise<StoredCredentials> {\n const normalized = normalizeAddresses(contractAddresses);\n const key = await this.#storeKey();\n return this.resolveCredentials({\n key,\n contracts: normalized,\n createKey: normalized.join(\",\"),\n createFn: () => this.create(normalized),\n });\n }\n\n /** Check if stored credentials are expired or unusable. */\n async isExpired(contractAddress?: Address): Promise<boolean> {\n return this.checkExpired(await this.#storeKey(), contractAddress);\n }\n\n /** Revoke the session signature. Next decrypt requires a fresh wallet signature. */\n async revoke(...contractAddresses: Address[]): Promise<void> {\n await this.revokeSession(\n await this.#storeKey(),\n contractAddresses.length > 0 ? contractAddresses : undefined,\n );\n }\n\n /** Revoke the session signature for a specific wallet identity (address, chainId). */\n async revokeFor(identity: SignerIdentity): Promise<void> {\n await this.revokeSession(\n await CredentialsManager.computeStoreKey(identity.address, identity.chainId),\n );\n }\n\n /** Whether a session signature is currently cached and covers the given contracts. */\n async isAllowed(contractAddresses: [Address, ...Address[]]): Promise<boolean> {\n return this.checkAllowed(await this.#storeKey(), contractAddresses);\n }\n\n /** Delete stored credentials (best-effort). */\n async clear(): Promise<void> {\n await this.clearAll(await this.#storeKey());\n }\n\n /**\n * Generate a fresh FHE keypair, create an EIP-712 authorization, and\n * prompt the user to sign it.\n */\n async create(contractAddresses: Address[]): Promise<StoredCredentials> {\n const normalized = normalizeAddresses(contractAddresses);\n const key = await this.#storeKey();\n return this.createCredentials({\n key,\n contractAddresses: normalized,\n createFn: async () => {\n const keypair = await this.#relayer.generateKeypair();\n const startTimestamp = Math.floor(Date.now() / 1000);\n const durationDays = Math.ceil(this.keypairTTL / 86400);\n\n const eip712 = await this.#relayer.createEIP712(\n keypair.publicKey,\n normalized,\n startTimestamp,\n durationDays,\n );\n const signature = await this.signer.signTypedData(eip712);\n\n return {\n publicKey: keypair.publicKey,\n privateKey: keypair.privateKey,\n signature,\n contractAddresses: normalized,\n startTimestamp,\n durationDays,\n };\n },\n errorContext: \"Failed to create decrypt credentials\",\n });\n }\n\n // ── Abstract implementations ──────────────────────────────────\n\n protected assertEncrypted(data: unknown): asserts data is EncryptedCredentials {\n assertBaseEncryptedCredentials(data);\n }\n\n protected async signForContracts(meta: SigningMeta, contractAddresses: Address[]): Promise<Hex> {\n const eip712 = await this.#relayer.createEIP712(\n meta.publicKey,\n contractAddresses,\n meta.startTimestamp,\n meta.durationDays,\n );\n return this.signer.signTypedData(eip712);\n }\n\n protected async encryptCredentials(creds: StoredCredentials): Promise<EncryptedCredentials> {\n const address = await this.signer.getAddress();\n const encryptedPrivateKey = await this.crypto.encrypt(\n creds.privateKey,\n creds.signature,\n address,\n );\n const { privateKey: _, signature: _sig, ...rest } = creds;\n return { ...rest, encryptedPrivateKey };\n }\n\n protected async decryptCredentials(\n encrypted: EncryptedCredentials,\n signature: Hex,\n ): Promise<StoredCredentials> {\n const address = await this.signer.getAddress();\n const privateKey = await this.crypto.decrypt(encrypted.encryptedPrivateKey, signature, address);\n const { encryptedPrivateKey: _, ...rest } = encrypted;\n return { ...rest, privateKey, signature };\n }\n\n protected override clearCaches(): void {\n this.#cachedStoreKey = null;\n this.#cachedStoreKeyIdentity = null;\n super.clearCaches();\n }\n\n // ── Store key ─────────────────────────────────────────────────\n\n async #storeKey(): Promise<string> {\n const address = await this.signer.getAddress();\n const chainId = await this.signer.getChainId();\n const identity = `${getAddress(address)}:${chainId}`;\n if (this.#cachedStoreKey && this.#cachedStoreKeyIdentity === identity) {\n return this.#cachedStoreKey;\n }\n const key = await CredentialsManager.computeStoreKey(address, chainId);\n this.#cachedStoreKeyIdentity = identity;\n this.#cachedStoreKey = key;\n return key;\n }\n}\n","import { getAddress, type Address, type Hex } from \"viem\";\nimport type { RelayerSDK } from \"../relayer/relayer-sdk\";\nimport type { DelegatedStoredCredentials } from \"../types\";\nimport {\n BaseCredentialsManager,\n type CredentialsConfig,\n type SigningMeta,\n} from \"./credentials-manager-base\";\nimport {\n type BaseEncryptedCredentials,\n assertDelegatedFields,\n normalizeAddresses,\n computeStoreKey,\n} from \"./credential-validation\";\n\n/** Internal storage shape — base fields plus delegator/delegate addresses. */\ninterface EncryptedCredentials extends BaseEncryptedCredentials {\n delegatorAddress: Address;\n delegateAddress: Address;\n}\n\n/** Configuration for constructing a {@link DelegatedCredentialsManager}. */\nexport interface DelegatedCredentialsManagerConfig extends CredentialsConfig {\n /** FHE relayer backend for keypair generation and delegated EIP-712 creation. */\n relayer: RelayerSDK;\n}\n\n/** Signing metadata for delegated credentials, adding the delegator's address. */\nexport interface DelegatedSigningMeta extends SigningMeta {\n /** On-chain address of the account that delegated decryption rights. */\n delegatorAddress: Address;\n}\n\n/**\n * Manages FHE decrypt credentials for delegated decryption.\n * Scoped to a (delegate, delegator) pair.\n */\nexport class DelegatedCredentialsManager extends BaseCredentialsManager<\n DelegatedStoredCredentials,\n EncryptedCredentials\n> {\n #relayer: RelayerSDK;\n #cachedStoreKey: string | null = null;\n #cachedStoreKeyIdentity: string | null = null;\n\n /** Derive the deterministic storage key for a (delegate, delegator, chain) triple. */\n static async computeStoreKey(\n delegateAddress: Address,\n delegatorAddress: Address,\n chainId: number,\n ): Promise<string> {\n return computeStoreKey(getAddress(delegateAddress), getAddress(delegatorAddress), chainId);\n }\n\n constructor(config: DelegatedCredentialsManagerConfig) {\n super(config);\n this.#relayer = config.relayer;\n }\n\n // ── Public API ────────────────────────────────────────────────\n\n /**\n * Authorize FHE delegated credentials for one or more contract addresses.\n *\n * @throws {@link SigningRejectedError} if the user rejects the wallet signature prompt.\n * @throws {@link SigningFailedError} if the signing operation fails for any other reason.\n */\n async allow(\n delegatorAddress: Address,\n ...contractAddresses: Address[]\n ): Promise<DelegatedStoredCredentials> {\n const normalizedDelegator = getAddress(delegatorAddress);\n const normalized = normalizeAddresses(contractAddresses);\n const key = await this.#storeKey(normalizedDelegator);\n return this.resolveCredentials({\n key,\n contracts: normalized,\n createKey: `${normalizedDelegator}:${normalized.join(\",\")}`,\n createFn: () => this.#create(normalizedDelegator, normalized),\n });\n }\n\n /** Check if stored delegated credentials are expired or unusable. */\n async isExpired(delegatorAddress: Address, contractAddress?: Address): Promise<boolean> {\n return this.checkExpired(await this.#storeKey(getAddress(delegatorAddress)), contractAddress);\n }\n\n /** Revoke the session signature for a delegator. */\n async revoke(delegatorAddress: Address): Promise<void> {\n await this.revokeSession(await this.#storeKey(getAddress(delegatorAddress)));\n }\n\n /** Whether a session signature is currently cached and covers the given contracts. */\n async isAllowed(\n delegatorAddress: Address,\n contractAddresses: [Address, ...Address[]],\n ): Promise<boolean> {\n return this.checkAllowed(await this.#storeKey(getAddress(delegatorAddress)), contractAddresses);\n }\n\n /** Delete stored credentials for a delegator (best-effort). */\n async clear(delegatorAddress: Address): Promise<void> {\n await this.clearAll(await this.#storeKey(getAddress(delegatorAddress)));\n }\n\n // ── Credential creation ───────────────────────────────────────\n\n async #create(\n delegatorAddress: Address,\n contractAddresses: Address[],\n ): Promise<DelegatedStoredCredentials> {\n const key = await this.#storeKey(delegatorAddress);\n return this.createCredentials({\n key,\n contractAddresses,\n createFn: async () => {\n const keypair = await this.#relayer.generateKeypair();\n const delegateAddress = await this.signer.getAddress();\n const startTimestamp = Math.floor(Date.now() / 1000);\n const durationDays = Math.ceil(this.keypairTTL / 86400);\n\n const meta = {\n publicKey: keypair.publicKey,\n startTimestamp,\n durationDays,\n delegatorAddress,\n };\n const signature = await this.#signDelegated(meta, contractAddresses);\n\n return {\n publicKey: keypair.publicKey,\n privateKey: keypair.privateKey,\n signature,\n contractAddresses,\n startTimestamp,\n durationDays,\n delegatorAddress,\n delegateAddress,\n };\n },\n errorContext: \"Failed to create delegated decrypt credentials\",\n });\n }\n\n // ── Abstract implementations ──────────────────────────────────\n\n protected assertEncrypted(data: unknown): asserts data is EncryptedCredentials {\n assertDelegatedFields(data);\n }\n\n protected async signForContracts(\n meta: DelegatedSigningMeta,\n contractAddresses: Address[],\n ): Promise<Hex> {\n return this.#signDelegated(meta, contractAddresses);\n }\n\n protected async encryptCredentials(\n creds: DelegatedStoredCredentials,\n ): Promise<EncryptedCredentials> {\n const address = await this.signer.getAddress();\n const encryptedPrivateKey = await this.crypto.encrypt(\n creds.privateKey,\n creds.signature,\n address,\n );\n const { privateKey: _, signature: _sig, ...rest } = creds;\n return { ...rest, encryptedPrivateKey };\n }\n\n protected async decryptCredentials(\n encrypted: EncryptedCredentials,\n signature: Hex,\n ): Promise<DelegatedStoredCredentials> {\n const address = await this.signer.getAddress();\n const privateKey = await this.crypto.decrypt(encrypted.encryptedPrivateKey, signature, address);\n const { encryptedPrivateKey: _, ...rest } = encrypted;\n return { ...rest, privateKey, signature };\n }\n\n protected override clearCaches(): void {\n this.#cachedStoreKey = null;\n this.#cachedStoreKeyIdentity = null;\n super.clearCaches();\n }\n\n // ── Private helpers ───────────────────────────────────────────\n\n async #storeKey(delegatorAddress: Address): Promise<string> {\n const delegateAddress = await this.signer.getAddress();\n const chainId = await this.signer.getChainId();\n const identity = `${getAddress(delegateAddress)}:${getAddress(delegatorAddress)}:${chainId}`;\n if (this.#cachedStoreKey && this.#cachedStoreKeyIdentity === identity) {\n return this.#cachedStoreKey;\n }\n const key = await DelegatedCredentialsManager.computeStoreKey(\n delegateAddress,\n delegatorAddress,\n chainId,\n );\n this.#cachedStoreKeyIdentity = identity;\n this.#cachedStoreKey = key;\n return key;\n }\n\n async #signDelegated(meta: DelegatedSigningMeta, contractAddresses: Address[]): Promise<Hex> {\n const delegatedEIP712 = await this.#relayer.createDelegatedUserDecryptEIP712(\n meta.publicKey,\n contractAddresses,\n meta.delegatorAddress,\n meta.startTimestamp,\n meta.durationDays,\n );\n return this.signer.signTypedData(delegatedEIP712);\n }\n}\n","/**\n * Framework-agnostic event decoders for confidential token contracts.\n * Works with raw log data from any provider.\n */\n\nimport type { Handle } from \"../relayer/relayer-sdk.types\";\nimport { getAddress, keccak256, toBytes, type Address, type Hex } from \"viem\";\nimport { prefixHex } from \"../utils\";\nimport type { RawLog } from \"../types/transaction\";\nexport type { RawLog } from \"../types/transaction\";\n\nfunction eventTopic(signature: string): Hex {\n return keccak256(toBytes(signature));\n}\n\n// ---------------------------------------------------------------------------\n// Event topic0 constants (keccak256 of canonical signature)\n// ---------------------------------------------------------------------------\n\n/**\n * Event topic0 constants (keccak256 of the canonical Solidity signature).\n * Pass to `getLogs({ topics: [Object.values(Topics)] })` to fetch all events.\n */\nexport const Topics = {\n /** `ConfidentialTransfer(address indexed from, address indexed to, bytes32 indexed amount)` */\n ConfidentialTransfer: eventTopic(\"ConfidentialTransfer(address,address,bytes32)\"),\n // NOTE: New wrapper contracts no longer emit Wrapped — shields now emit\n // ConfidentialTransfer(from=zeroAddress, ...) instead. Retained for backward\n // compatibility with older deployments.\n /** `Wrapped(address indexed to, uint256 amountIn)` */\n Wrapped: eventTopic(\"Wrapped(address,uint256)\"),\n /** `UnwrapRequested(address indexed receiver, bytes32 indexed unwrapRequestId, bytes32 amount)` */\n UnwrapRequested: eventTopic(\"UnwrapRequested(address,bytes32,bytes32)\"),\n /** `UnwrapRequested(address indexed receiver, bytes32 amount)` */\n UnwrapRequestedLegacy: eventTopic(\"UnwrapRequested(address,bytes32)\"),\n /** `UnwrapFinalized(address indexed receiver, bytes32 indexed unwrapRequestId, bytes32 encryptedAmount, uint64 cleartextAmount)` */\n UnwrapFinalized: eventTopic(\"UnwrapFinalized(address,bytes32,bytes32,uint64)\"),\n /** `UnwrapFinalized(address indexed receiver, bytes32 encryptedAmount, uint64 cleartextAmount)` */\n UnwrapFinalizedLegacy: eventTopic(\"UnwrapFinalized(address,bytes32,uint64)\"),\n /** @deprecated Use `Topics.UnwrapFinalized`. */\n UnwrappedFinalized: eventTopic(\"UnwrapFinalized(address,bytes32,bytes32,uint64)\"),\n /** `UnwrappedStarted(bool returnVal, uint256 indexed requestId, ...)` */\n UnwrappedStarted: eventTopic(\n \"UnwrappedStarted(bool,uint256,uint256,address,address,bytes32,bytes32)\",\n ),\n} as const;\n\n// ---------------------------------------------------------------------------\n// Typed event interfaces\n// ---------------------------------------------------------------------------\n\n/** Decoded `ConfidentialTransfer` event — an encrypted token transfer. */\nexport interface ConfidentialTransferEvent {\n readonly eventName: \"ConfidentialTransfer\";\n /** Sender address. */\n readonly from: Address;\n /** Receiver address. */\n readonly to: Address;\n /** FHE ciphertext handle for the transferred amount. */\n readonly encryptedAmountHandle: Handle;\n}\n\n// NOTE: New wrapper contracts no longer emit this event — shields now emit\n// ConfidentialTransfer(from=zeroAddress, ...) instead. Retained for backward\n// compatibility with older deployments.\n/** Decoded `Wrapped` event — an ERC-20 shield (wrap) operation. */\nexport interface WrappedEvent {\n readonly eventName: \"Wrapped\";\n /** Receiver of the minted confidential tokens. */\n readonly to: Address;\n /** Underlying ERC-20 tokens deposited. */\n readonly amountIn: bigint;\n}\n\n/** Decoded `UnwrapRequested` event — an unshield request submitted. */\nexport interface UnwrapRequestedEvent {\n readonly eventName: \"UnwrapRequested\";\n /** Address that will receive the unwrapped ERC-20 tokens. */\n readonly receiver: Address;\n /** FHE ciphertext handle for the requested unshield amount. */\n readonly encryptedAmount: Handle;\n /** Request identifier emitted by upgraded wrapper contracts. */\n readonly unwrapRequestId?: Handle;\n}\n\n/** Decoded `UnwrapFinalized` event — an unshield completed on-chain. */\nexport interface UnwrapFinalizedEvent {\n readonly eventName: \"UnwrapFinalized\";\n /** Address receiving the unwrapped ERC-20 tokens. */\n readonly receiver: Address;\n /** FHE ciphertext handle of the burnt confidential balance. */\n readonly encryptedAmount: Handle;\n /** Cleartext amount of underlying ERC-20 tokens returned. */\n readonly cleartextAmount: bigint;\n /** Request identifier emitted by upgraded wrapper contracts. */\n readonly unwrapRequestId?: Handle;\n}\n\n/** @deprecated Use `UnwrapFinalizedEvent`. */\nexport interface UnwrappedFinalizedEvent {\n readonly eventName: \"UnwrappedFinalized\";\n readonly receiver: Address;\n readonly encryptedAmount: Handle;\n readonly cleartextAmount: bigint;\n readonly unwrapRequestId?: Handle;\n}\n\n/** Decoded `UnwrappedStarted` event — the relayer began processing an unshield. */\nexport interface UnwrappedStartedEvent {\n readonly eventName: \"UnwrappedStarted\";\n /** Whether the unwrap start succeeded. */\n readonly returnVal: boolean;\n /** On-chain request ID. */\n readonly requestId: bigint;\n /** On-chain transaction ID. */\n readonly txId: bigint;\n /** Receiver address. */\n readonly to: Address;\n /** Refund address (if applicable). */\n readonly refund: Address;\n /** FHE handle of the requested amount. */\n readonly requestedAmount: Handle;\n /** FHE handle of the burn amount. */\n readonly burnAmount: Handle;\n}\n\n/** Union of all decoded confidential token event types. */\nexport type OnChainEvent =\n | ConfidentialTransferEvent\n | WrappedEvent\n | UnwrapRequestedEvent\n | UnwrapFinalizedEvent\n | UnwrappedFinalizedEvent\n | UnwrappedStartedEvent;\n\n// ---------------------------------------------------------------------------\n// ABI decoding helpers (no external deps)\n// ---------------------------------------------------------------------------\n\nfunction topicToAddress(topic: Hex): Address {\n return getAddress(prefixHex(topic.slice(-40)));\n}\n\nfunction topicToBigInt(topic: Hex): bigint {\n return BigInt(topic);\n}\n\nfunction topicToBytes32(topic: Hex): Handle {\n // EVM topics are already 32-byte 0x-prefixed hex — cast directly\n return topic as Handle;\n}\n\nfunction wordAt(data: Hex, index: number): string {\n // data starts with \"0x\", each word is 64 hex chars (32 bytes)\n const start = 2 + index * 64;\n const word = data.slice(start, start + 64);\n return word.length === 64 ? word : word.padEnd(64, \"0\");\n}\n\nfunction wordToAddress(data: Hex, index: number): Address {\n return getAddress(prefixHex(wordAt(data, index).slice(-40)));\n}\n\nfunction wordToBigInt(data: Hex, index: number): bigint {\n return BigInt(\"0x\" + wordAt(data, index));\n}\n\nfunction wordToBool(data: Hex, index: number): boolean {\n return BigInt(\"0x\" + wordAt(data, index)) !== 0n;\n}\n\nfunction wordToBytes32(data: Hex, index: number): Handle {\n // wordAt returns exactly 64 hex chars — prefix and cast directly\n return prefixHex(wordAt(data, index)) as Handle;\n}\n\n// ---------------------------------------------------------------------------\n// Individual decoders\n// ---------------------------------------------------------------------------\n\n/**\n * ConfidentialTransfer(address indexed from, address indexed to, bytes32 indexed amount)\n * All 3 params indexed → topics[1..3], no data.\n */\nexport function decodeConfidentialTransfer(log: RawLog): ConfidentialTransferEvent | null {\n if (log.topics[0] !== Topics.ConfidentialTransfer) {\n return null;\n }\n if (log.topics.length < 4) {\n return null;\n }\n\n return {\n eventName: \"ConfidentialTransfer\",\n from: topicToAddress(log.topics[1]!),\n to: topicToAddress(log.topics[2]!),\n encryptedAmountHandle: topicToBytes32(log.topics[3]!),\n };\n}\n\n// NOTE: New wrapper contracts no longer emit this event. Retained for backward\n// compatibility with older deployments.\n/**\n * Wrapped(address indexed to, uint256 amountIn)\n * Indexed: to (topics[1])\n * Data: amountIn (uint256)\n */\nexport function decodeWrapped(log: RawLog): WrappedEvent | null {\n if (log.topics[0] !== Topics.Wrapped) {\n return null;\n }\n if (log.topics.length < 2) {\n return null;\n }\n\n return {\n eventName: \"Wrapped\",\n to: topicToAddress(log.topics[1]!),\n amountIn: wordToBigInt(log.data, 0),\n };\n}\n\n/**\n * UnwrapRequested(address indexed receiver, bytes32 amount)\n * UnwrapRequested(address indexed receiver, bytes32 indexed unwrapRequestId, bytes32 amount)\n */\nexport function decodeUnwrapRequested(log: RawLog): UnwrapRequestedEvent | null {\n if (log.topics[0] === Topics.UnwrapRequested) {\n if (log.topics.length < 3) {\n return null;\n }\n\n return {\n eventName: \"UnwrapRequested\",\n receiver: topicToAddress(log.topics[1]!),\n unwrapRequestId: topicToBytes32(log.topics[2]!),\n encryptedAmount: wordToBytes32(log.data, 0),\n };\n }\n\n if (log.topics[0] === Topics.UnwrapRequestedLegacy) {\n if (log.topics.length < 2) {\n return null;\n }\n\n return {\n eventName: \"UnwrapRequested\",\n receiver: topicToAddress(log.topics[1]!),\n encryptedAmount: wordToBytes32(log.data, 0),\n };\n }\n\n return null;\n}\n\n/**\n * UnwrapFinalized(address indexed receiver, bytes32 encryptedAmount, uint64 cleartextAmount)\n * UnwrapFinalized(address indexed receiver, bytes32 indexed unwrapRequestId, bytes32 encryptedAmount, uint64 cleartextAmount)\n */\nexport function decodeUnwrapFinalized(log: RawLog): UnwrapFinalizedEvent | null {\n if (log.topics[0] === Topics.UnwrapFinalized) {\n if (log.topics.length < 3) {\n return null;\n }\n\n return {\n eventName: \"UnwrapFinalized\",\n receiver: topicToAddress(log.topics[1]!),\n unwrapRequestId: topicToBytes32(log.topics[2]!),\n encryptedAmount: wordToBytes32(log.data, 0),\n cleartextAmount: wordToBigInt(log.data, 1),\n };\n }\n\n if (log.topics[0] === Topics.UnwrapFinalizedLegacy) {\n if (log.topics.length < 2) {\n return null;\n }\n\n return {\n eventName: \"UnwrapFinalized\",\n receiver: topicToAddress(log.topics[1]!),\n encryptedAmount: wordToBytes32(log.data, 0),\n cleartextAmount: wordToBigInt(log.data, 1),\n };\n }\n\n return null;\n}\n\n/** @deprecated Use `decodeUnwrapFinalized`. */\nexport function decodeUnwrappedFinalized(log: RawLog): UnwrappedFinalizedEvent | null {\n const event = decodeUnwrapFinalized(log);\n if (!event) {\n return null;\n }\n\n return {\n ...event,\n eventName: \"UnwrappedFinalized\",\n };\n}\n\nfunction decodeLegacyUnwrappedFinalized(log: RawLog): UnwrappedFinalizedEvent | null {\n if (log.topics[0] !== Topics.UnwrapFinalizedLegacy) {\n return null;\n }\n const event = decodeUnwrapFinalized(log);\n if (!event) {\n return null;\n }\n\n return {\n ...event,\n eventName: \"UnwrappedFinalized\",\n };\n}\n\n/**\n * UnwrappedStarted(bool returnVal, uint256 indexed requestId, uint256 indexed txId, address indexed to,\n * address refund, bytes32 requestedAmount, bytes32 burnAmount)\n * Indexed: requestId (topics[1]), txId (topics[2]), to (topics[3])\n * Data: returnVal, refund, requestedAmount, burnAmount\n */\nexport function decodeUnwrappedStarted(log: RawLog): UnwrappedStartedEvent | null {\n if (log.topics[0] !== Topics.UnwrappedStarted) {\n return null;\n }\n if (log.topics.length < 4) {\n return null;\n }\n\n return {\n eventName: \"UnwrappedStarted\",\n requestId: topicToBigInt(log.topics[1]!),\n txId: topicToBigInt(log.topics[2]!),\n to: topicToAddress(log.topics[3]!),\n returnVal: wordToBool(log.data, 0),\n refund: wordToAddress(log.data, 1),\n requestedAmount: wordToBytes32(log.data, 2),\n burnAmount: wordToBytes32(log.data, 3),\n };\n}\n\n// ---------------------------------------------------------------------------\n// Convenience helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Try all decoders on a single log and return the first match, or `null`.\n *\n * @example\n * ```ts\n * const event = decodeOnChainEvent(log);\n * if (event?.eventName === \"ConfidentialTransfer\") {\n * console.log(event.from, event.to);\n * }\n * ```\n */\nexport function decodeOnChainEvent(log: RawLog): OnChainEvent | null {\n return (\n decodeConfidentialTransfer(log) ??\n decodeWrapped(log) ??\n decodeUnwrapRequested(log) ??\n decodeLegacyUnwrappedFinalized(log) ??\n decodeUnwrapFinalized(log) ??\n decodeUnwrappedStarted(log)\n );\n}\n\n/**\n * Batch-decode an array of logs, skipping unrecognized entries.\n *\n * @example\n * ```ts\n * const events = decodeOnChainEvents(receipt.logs);\n * ```\n */\nexport function decodeOnChainEvents(logs: readonly RawLog[]): OnChainEvent[] {\n const events: OnChainEvent[] = [];\n for (const log of logs) {\n const event = decodeOnChainEvent(log);\n if (event) {\n events.push(event);\n }\n }\n return events;\n}\n\n/**\n * Find the first {@link UnwrapRequestedEvent} in a logs array.\n *\n * @example\n * ```ts\n * const event = findUnwrapRequested(receipt.logs);\n * if (event) console.log(event.receiver, event.encryptedAmount);\n * ```\n */\nexport function findUnwrapRequested(logs: readonly RawLog[]): UnwrapRequestedEvent | null {\n for (const log of logs) {\n const event = decodeUnwrapRequested(log);\n if (event) {\n return event;\n }\n }\n return null;\n}\n\n// NOTE: New wrapper contracts no longer emit this event. Retained for backward\n// compatibility with older deployments.\n/**\n * Find the first {@link WrappedEvent} in a logs array.\n *\n * @example\n * ```ts\n * const event = findWrapped(receipt.logs);\n * if (event) console.log(event.to, event.amountIn);\n * ```\n */\nexport function findWrapped(logs: readonly RawLog[]): WrappedEvent | null {\n for (const log of logs) {\n const event = decodeWrapped(log);\n if (event) {\n return event;\n }\n }\n return null;\n}\n\n/**\n * All confidential token event topic0 hashes.\n * Pass to `getLogs({ topics: [TOKEN_TOPICS] })` to fetch\n * all confidential token events in a single RPC call.\n */\nexport const TOKEN_TOPICS = [\n Topics.ConfidentialTransfer,\n Topics.Wrapped,\n Topics.UnwrapRequested,\n Topics.UnwrapRequestedLegacy,\n Topics.UnwrapFinalized,\n Topics.UnwrapFinalizedLegacy,\n Topics.UnwrappedStarted,\n] as const;\n\n// ---------------------------------------------------------------------------\n// ACL delegation event topic0 constants\n// ---------------------------------------------------------------------------\n\n/**\n * ACL delegation event topic0 constants (keccak256 of the canonical Solidity signature).\n * These are ACL events, NOT token events — they are emitted by the ACL contract.\n */\nexport const AclTopics = {\n /** `DelegatedForUserDecryption(address indexed delegator, address indexed delegate, address contractAddress, uint64 delegationCounter, uint64 oldExpirationDate, uint64 newExpirationDate)` */\n DelegatedForUserDecryption: eventTopic(\n \"DelegatedForUserDecryption(address,address,address,uint64,uint64,uint64)\",\n ),\n /** `RevokedDelegationForUserDecryption(address indexed delegator, address indexed delegate, address contractAddress, uint64 delegationCounter, uint64 oldExpirationDate)` */\n RevokedDelegationForUserDecryption: eventTopic(\n \"RevokedDelegationForUserDecryption(address,address,address,uint64,uint64)\",\n ),\n} as const;\n\n// ---------------------------------------------------------------------------\n// ACL delegation event interfaces\n// ---------------------------------------------------------------------------\n\n/** Decoded `DelegatedForUserDecryption` event — a delegation was created or renewed. */\nexport interface DelegatedForUserDecryptionEvent {\n readonly eventName: \"DelegatedForUserDecryption\";\n /** Address of the delegator (the account granting access). */\n readonly delegator: Address;\n /** Address of the delegate (the account receiving access). */\n readonly delegate: Address;\n /** Contract address the delegation applies to. */\n readonly contractAddress: Address;\n /** Monotonic delegation counter. */\n readonly delegationCounter: bigint;\n /** Previous expiration timestamp (0 if first delegation). */\n readonly oldExpirationDate: bigint;\n /** New expiration timestamp. */\n readonly newExpirationDate: bigint;\n}\n\n/** Decoded `RevokedDelegationForUserDecryption` event — a delegation was revoked. */\nexport interface RevokedDelegationForUserDecryptionEvent {\n readonly eventName: \"RevokedDelegationForUserDecryption\";\n /** Address of the delegator. */\n readonly delegator: Address;\n /** Address of the delegate. */\n readonly delegate: Address;\n /** Contract address the revocation applies to. */\n readonly contractAddress: Address;\n /** Monotonic delegation counter. */\n readonly delegationCounter: bigint;\n /** Expiration date that was active before revocation. */\n readonly oldExpirationDate: bigint;\n}\n\n/** Union of all decoded ACL delegation event types. */\nexport type AclEvent = DelegatedForUserDecryptionEvent | RevokedDelegationForUserDecryptionEvent;\n\n// ---------------------------------------------------------------------------\n// ACL delegation event decoders\n// ---------------------------------------------------------------------------\n\n/**\n * DelegatedForUserDecryption(address indexed delegator, address indexed delegate,\n * address contractAddress, uint64 delegationCounter, uint64 oldExpirationDate, uint64 newExpirationDate)\n * Indexed: delegator (topics[1]), delegate (topics[2])\n * Data: contractAddress, delegationCounter, oldExpirationDate, newExpirationDate\n */\nexport function decodeDelegatedForUserDecryption(\n log: RawLog,\n): DelegatedForUserDecryptionEvent | null {\n if (log.topics[0] !== AclTopics.DelegatedForUserDecryption) {\n return null;\n }\n if (log.topics.length < 3) {\n return null;\n }\n\n return {\n eventName: \"DelegatedForUserDecryption\",\n delegator: topicToAddress(log.topics[1]!),\n delegate: topicToAddress(log.topics[2]!),\n contractAddress: wordToAddress(log.data, 0),\n delegationCounter: wordToBigInt(log.data, 1),\n oldExpirationDate: wordToBigInt(log.data, 2),\n newExpirationDate: wordToBigInt(log.data, 3),\n };\n}\n\n/**\n * RevokedDelegationForUserDecryption(address indexed delegator, address indexed delegate,\n * address contractAddress, uint64 delegationCounter, uint64 oldExpirationDate)\n * Indexed: delegator (topics[1]), delegate (topics[2])\n * Data: contractAddress, delegationCounter, oldExpirationDate\n */\nexport function decodeRevokedDelegationForUserDecryption(\n log: RawLog,\n): RevokedDelegationForUserDecryptionEvent | null {\n if (log.topics[0] !== AclTopics.RevokedDelegationForUserDecryption) {\n return null;\n }\n if (log.topics.length < 3) {\n return null;\n }\n\n return {\n eventName: \"RevokedDelegationForUserDecryption\",\n delegator: topicToAddress(log.topics[1]!),\n delegate: topicToAddress(log.topics[2]!),\n contractAddress: wordToAddress(log.data, 0),\n delegationCounter: wordToBigInt(log.data, 1),\n oldExpirationDate: wordToBigInt(log.data, 2),\n };\n}\n\n/**\n * Try all ACL delegation decoders on a single log and return the first match, or `null`.\n */\nexport function decodeAclEvent(log: RawLog): AclEvent | null {\n return decodeDelegatedForUserDecryption(log) ?? decodeRevokedDelegationForUserDecryption(log);\n}\n\n/**\n * Batch-decode an array of logs for ACL delegation events, skipping unrecognized entries.\n */\nexport function decodeAclEvents(logs: readonly RawLog[]): AclEvent[] {\n const events: AclEvent[] = [];\n for (const log of logs) {\n const event = decodeAclEvent(log);\n if (event) {\n events.push(event);\n }\n }\n return events;\n}\n\n/**\n * Find the first {@link DelegatedForUserDecryptionEvent} in a logs array.\n */\nexport function findDelegatedForUserDecryption(\n logs: readonly RawLog[],\n): DelegatedForUserDecryptionEvent | null {\n for (const log of logs) {\n const event = decodeDelegatedForUserDecryption(log);\n if (event) {\n return event;\n }\n }\n return null;\n}\n\n/**\n * Find the first {@link RevokedDelegationForUserDecryptionEvent} in a logs array.\n */\nexport function findRevokedDelegationForUserDecryption(\n logs: readonly RawLog[],\n): RevokedDelegationForUserDecryptionEvent | null {\n for (const log of logs) {\n const event = decodeRevokedDelegationForUserDecryption(log);\n if (event) {\n return event;\n }\n }\n return null;\n}\n\n/**\n * Both ACL delegation event topic0 hashes.\n * Pass to `getLogs({ topics: [ACL_TOPICS] })` to fetch\n * all delegation events in a single RPC call.\n */\nexport const ACL_TOPICS = [\n AclTopics.DelegatedForUserDecryption,\n AclTopics.RevokedDelegationForUserDecryption,\n] as const;\n","import { type Address, getAddress, type Hex } 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} 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 {\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 { isZeroHandle } from \"../utils/handles\";\nimport { ReadonlyToken } from \"./readonly-token\";\nimport type {\n ShieldCallbacks,\n ShieldOptions,\n TransactionResult,\n TransferCallbacks,\n TransferOptions,\n UnshieldCallbacks,\n UnshieldOptions,\n} from \"../types\";\nimport type { ZamaSDK } from \"../zama-sdk\";\nimport { assertBigint } from \"../utils/assertions\";\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 {@link ReadonlyToken} with write operations\n * (transfer, shield, unshield).\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(sdk: ZamaSDK, address: Address, wrapper?: Address) {\n super(sdk, address);\n this.wrapper = wrapper ? getAddress(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.sdk.provider\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 ChainMismatchError} if signer and provider are on different chains.\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 await this.sdk.requireChainAlignment(\"confidentialTransfer\");\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.sdk.relayer.encrypt({\n values: [{ value: amount, type: \"euint64\" }],\n contractAddress: this.address,\n userAddress: await this.sdk.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.sdk.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.sdk.provider.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 ChainMismatchError} if signer and provider are on different chains.\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 await this.sdk.requireChainAlignment(\"confidentialTransferFrom\");\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.sdk.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.sdk.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.sdk.provider.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 ChainMismatchError} if signer and provider are on different chains.\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 await this.sdk.requireChainAlignment(\"approve\");\n const normalizedSpender = getAddress(spender);\n try {\n const txHash = await this.sdk.signer.writeContract(\n setOperatorContract(this.address, normalizedSpender, until),\n );\n this.emit({ type: ZamaSDKEvents.ApproveSubmitted, txHash });\n const receipt = await this.sdk.provider.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.\n * @returns `true` if the spender is an approved operator for the holder.\n *\n * @example\n * ```ts\n * if (await token.isApproved(\"0xSpender\", \"0xHolder\")) {\n * // spender can call transferFrom on behalf of holder\n * }\n * ```\n */\n async isApproved(spender: Address, holder: Address): Promise<boolean> {\n return this.sdk.provider.readContract(\n isOperatorContract(this.address, getAddress(holder), getAddress(spender)),\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).\n *\n * @param amount - The plaintext amount to shield.\n * @param options - Optional configuration: `approvalStrategy` (`\"exact\"` | `\"max\"` | `\"skip\"`, default `\"exact\"`).\n * @returns The transaction hash and mined receipt.\n * @throws {@link ChainMismatchError} if signer and provider are on different chains.\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 await this.sdk.requireChainAlignment(\"shield\");\n const underlying = await this.#getUnderlying();\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.sdk.signer.getAddress();\n erc20Balance = await this.sdk.provider.readContract(\n balanceOfContract(underlying, userAddress),\n );\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.sdk.signer.getAddress();\n const txHash = await this.sdk.signer.writeContract(\n wrapContract(this.wrapper, recipient, amount),\n );\n this.emit({ type: ZamaSDKEvents.ShieldSubmitted, txHash });\n safeCallback(() => options?.onShieldSubmitted?.(txHash));\n const receipt = await this.sdk.provider.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 * 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 ChainMismatchError} if signer and provider are on different chains.\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 await this.sdk.requireChainAlignment(\"unwrap\");\n const userAddress = await this.sdk.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.sdk.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.sdk.signer.writeContract(\n unwrapContract(this.address, userAddress, userAddress, handles[0]!, inputProof),\n );\n this.emit({ type: ZamaSDKEvents.UnwrapSubmitted, txHash });\n const receipt = await this.sdk.provider.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 ChainMismatchError} if signer and provider are on different chains.\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 await this.sdk.requireChainAlignment(\"unwrapAll\");\n const userAddress = await this.sdk.signer.getAddress();\n const handle = await this.readConfidentialBalanceOf(userAddress);\n\n if (isZeroHandle(handle)) {\n throw new DecryptionFailedError(\"Cannot unshield: balance is zero\");\n }\n\n try {\n const txHash = await this.sdk.signer.writeContract(\n unwrapFromBalanceContract(this.address, userAddress, userAddress, handle),\n );\n this.emit({ type: ZamaSDKEvents.UnwrapSubmitted, txHash });\n const receipt = await this.sdk.provider.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 unwrapRequestIdOrAmount - `unwrapRequestId` from upgraded wrappers, or the encrypted amount handle from legacy wrappers.\n * @returns The transaction hash and mined receipt.\n * @throws {@link ChainMismatchError} if signer and provider are on different chains.\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.unwrapRequestId ?? event.encryptedAmount);\n * ```\n */\n async finalizeUnwrap(unwrapRequestIdOrAmount: Handle): Promise<TransactionResult> {\n await this.sdk.requireChainAlignment(\"finalizeUnwrap\");\n const result = await this.sdk.publicDecrypt([unwrapRequestIdOrAmount]);\n const clearValue = result.clearValues[unwrapRequestIdOrAmount];\n assertBigint(clearValue, \"finalizeUnwrap: clearValue\");\n try {\n const txHash = await this.sdk.signer.writeContract(\n finalizeUnwrapContract(\n this.wrapper,\n unwrapRequestIdOrAmount,\n clearValue,\n result.decryptionProof,\n ),\n );\n this.emit({ type: ZamaSDKEvents.FinalizeUnwrapSubmitted, txHash });\n const receipt = await this.sdk.provider.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 ChainMismatchError} if signer and provider are on different chains.\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 await this.sdk.requireChainAlignment(\"approveUnderlying\");\n const underlying = await this.#getUnderlying();\n\n const approvalAmount = amount ?? 2n ** 256n - 1n;\n\n try {\n const signer = this.sdk.signer;\n if (approvalAmount > 0n) {\n const userAddress = await signer.getAddress();\n const currentAllowance = await this.sdk.provider.readContract(\n allowanceContract(underlying, userAddress, this.wrapper),\n );\n\n if (currentAllowance > 0n) {\n await signer.writeContract(approveContract(underlying, this.wrapper, 0n));\n }\n }\n\n const txHash = await signer.writeContract(\n approveContract(underlying, this.wrapper, approvalAmount),\n );\n this.emit({ type: ZamaSDKEvents.ApproveUnderlyingSubmitted, txHash });\n const receipt = await this.sdk.provider.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 ChainMismatchError} if signer and provider are on different chains.\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 await this.sdk.requireChainAlignment(\"delegateDecryption\");\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 signer = this.sdk.signer;\n const signerAddress = await 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 let currentExpiry: bigint;\n try {\n currentExpiry = await this.getDelegationExpiry({\n delegatorAddress: signerAddress,\n delegateAddress: normalizedDelegate,\n });\n } catch {\n currentExpiry = -1n; // RPC failure — skip client-side check, let the contract enforce\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 signer.writeContract(\n delegateForUserDecryptionContract(acl, normalizedDelegate, this.address, expDate),\n );\n this.emit({ type: ZamaSDKEvents.DelegationSubmitted, txHash });\n const receipt = await this.sdk.provider.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 ChainMismatchError} if signer and provider are on different chains.\n * @throws {@link TransactionRevertedError} if the revocation transaction reverts.\n */\n async revokeDelegation({\n delegateAddress,\n }: {\n delegateAddress: Address;\n }): Promise<TransactionResult> {\n await this.sdk.requireChainAlignment(\"revokeDelegation\");\n const normalizedDelegate = getAddress(delegateAddress);\n const signer = this.sdk.signer;\n const signerAddress = await 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 let currentExpiry: bigint;\n try {\n currentExpiry = await this.getDelegationExpiry({\n delegatorAddress: signerAddress,\n delegateAddress: normalizedDelegate,\n });\n } catch {\n currentExpiry = 1n; // RPC failure — skip client-side check, let the contract enforce\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 signer.writeContract(\n revokeDelegationContract(acl, normalizedDelegate, this.address),\n );\n this.emit({ type: ZamaSDKEvents.RevokeDelegationSubmitted, txHash });\n const receipt = await this.sdk.provider.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 if (amount === 0n) {\n return;\n }\n\n let balance: bigint;\n try {\n balance = await this.balanceOf(await this.sdk.signer.getAddress());\n } catch (error) {\n if (error instanceof ZamaError) {\n throw error;\n }\n throw new BalanceCheckUnavailableError(`Balance validation failed (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.sdk.provider.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(\n event.unwrapRequestId ?? event.encryptedAmount,\n );\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 signer = this.sdk.signer;\n const userAddress = await signer.getAddress();\n const allowance = await this.sdk.provider.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 const resetHash = await signer.writeContract(approveContract(underlying, this.wrapper, 0n));\n await this.sdk.provider.waitForTransactionReceipt(resetHash);\n }\n\n const approvalAmount = maxApproval ? 2n ** 256n - 1n : amount;\n\n const txHash = await signer.writeContract(\n approveContract(underlying, this.wrapper, approvalAmount),\n );\n this.emit({ type: ZamaSDKEvents.ApproveUnderlyingSubmitted, txHash });\n safeCallback(() => callbacks?.onApprovalSubmitted?.(txHash));\n await this.sdk.provider.waitForTransactionReceipt(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, zeroAddress } 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 { mainnet, sepolia, hoodi } from \"./chains\";\nimport type { GenericProvider } from \"./types/provider\";\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 [mainnet.id]: mainnet.registryAddress,\n [sepolia.id]: sepolia.registryAddress,\n [hoodi.id]: hoodi.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 /** Read-only chain provider used for every registry lookup. */\n provider: GenericProvider;\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 * provider,\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 configured {@link GenericProvider} to resolve the correct registry\n * contract address for the current chain and exposes typed read helpers for\n * every registry query. Results are cached in memory with a configurable TTL\n * (default 24 hours).\n *\n * @example\n * ```ts\n * const registry = new WrappersRegistry({ provider });\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 provider: GenericProvider;\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.provider = config.provider;\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.provider.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.provider.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.provider.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.provider.readContract(nameContract(pair.tokenAddress)),\n this.provider.readContract(symbolContract(pair.tokenAddress)),\n this.provider.readContract(decimalsContract(pair.tokenAddress)),\n this.provider.readContract(erc20TotalSupplyContract(pair.tokenAddress)),\n this.provider.readContract(nameContract(pair.confidentialTokenAddress)),\n this.provider.readContract(symbolContract(pair.confidentialTokenAddress)),\n this.provider.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 the token has never been registered.\n * **Note:** revoked tokens (registered then invalidated) return a non-null result\n * with `isValid: false`. Check `result.isValid` explicitly rather than using\n * `if (result)` to guard against processing revoked tokens.\n *\n * @example\n * ```ts\n * const result = await registry.getConfidentialToken(usdcAddress);\n * if (result?.isValid) {\n * console.log(result.confidentialTokenAddress);\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 [isValid, confidentialTokenAddress] = await this.provider.readContract(\n getConfidentialTokenAddressContract(registry, normalized),\n );\n\n // Zero address means the token is not registered at all (never seen by the registry).\n // A non-zero address with isValid=false means it was registered but later revoked.\n if (confidentialTokenAddress === zeroAddress) {\n return this.#setCached(cacheKey, null, NEGATIVE_CACHE_TTL_MS);\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 [isValid, tokenAddress] = await this.provider.readContract(\n getTokenAddressContract(registry, normalized),\n );\n\n // Zero address means the confidential token is not registered at all.\n // A non-zero address with isValid=false means it was registered but later revoked.\n if (tokenAddress === zeroAddress) {\n return this.#setCached(cacheKey, null, NEGATIVE_CACHE_TTL_MS);\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.provider.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.provider.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.provider.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.provider.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 `[isValid, confidentialTokenAddress]`. `isValid` is `true` only for a\n * registered, non-revoked wrapper. The address is the zero address when no pair is registered.\n * A non-zero address with `isValid=false` means the wrapper was registered but later revoked.\n */\n async getConfidentialTokenAddress(tokenAddress: Address): Promise<readonly [boolean, Address]> {\n const registry = await this.getRegistryAddress();\n return this.provider.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 `[isValid, tokenAddress]`. `isValid` is `true` only for a registered,\n * non-revoked wrapper. The address is the zero address when no pair is registered.\n * A non-zero address with `isValid=false` means the wrapper was registered but later revoked.\n */\n async getTokenAddress(confidentialTokenAddress: Address): Promise<readonly [boolean, Address]> {\n const registry = await this.getRegistryAddress();\n return this.provider.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.provider.readContract(\n isConfidentialTokenValidContract(registry, getAddress(confidentialTokenAddress)),\n );\n }\n}\n","import { getAddress, type Address } from \"viem\";\nimport type { FheChain } from \"./chains/types\";\nimport { CredentialsManager } from \"./credentials/credentials-manager\";\nimport { DelegatedCredentialsManager } from \"./credentials/delegated-credentials-manager\";\nimport { DecryptCache } from \"./decrypt-cache\";\nimport { ChainMismatchError, wrapDecryptError } from \"./errors\";\nimport type { ZamaSDKEvent, ZamaSDKEventInput, ZamaSDKEventListener } from \"./events/sdk-events\";\nimport { ZamaSDKEvents } from \"./events/sdk-events\";\nimport type { DecryptHandle } from \"./query/user-decrypt\";\nimport { isZeroHandle } from \"./utils/handles\";\nimport type { RelayerDispatcher } from \"./relayer/relayer-dispatcher\";\nimport type { ClearValueType, Handle, PublicDecryptResult } from \"./relayer/relayer-sdk.types\";\nimport { MemoryStorage } from \"./storage/memory-storage\";\nimport { ReadonlyToken } from \"./token/readonly-token\";\nimport { Token } from \"./token/token\";\nimport type {\n GenericProvider,\n GenericSigner,\n GenericStorage,\n SignerIdentityChange,\n SignerIdentityListener,\n} from \"./types\";\nimport { toError } from \"./utils\";\nimport { pLimit } from \"./utils/concurrency\";\nimport { WrappersRegistry } from \"./wrappers-registry\";\n\n/** Maximum keypairTTL accepted by the fhevm ACL contract (365 days, in seconds). */\nconst MAX_KEYPAIR_TTL = 365 * 86400; // 31_536_000 s\n\n/** Run a best-effort cleanup step. Errors are logged, never thrown. */\nasync function swallow(label: string, fn: () => Promise<void> | void): Promise<void> {\n try {\n await fn();\n } catch (error) {\n // oxlint-disable-next-line no-console\n console.warn(`[zama-sdk] ${label} failed:`, error);\n }\n}\n\n/** Configuration for {@link ZamaSDK}. */\nexport interface ZamaSDKConfig {\n /** FHE chain configurations. Registry addresses are extracted from each chain's `registryAddress`. */\n chains?: readonly FheChain[];\n /** FHE relayer backend (`RelayerWeb` for browser, `RelayerNode` for server). */\n relayer: RelayerDispatcher;\n /**\n * Read-only chain provider (`ViemProvider`, `EthersProvider`, `WagmiProvider`,\n * or custom {@link GenericProvider}). Used for every public chain read the\n * SDK issues.\n */\n provider: GenericProvider;\n /**\n * Wallet signer (`ViemSigner`, `EthersSigner`, `WagmiSigner`, or custom\n * {@link GenericSigner}). Required for writes, EIP-712 signatures, and\n * wallet-lifecycle subscriptions.\n */\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 contracts in 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 * Maximum: `31536000` (365 days) — the fhevm contract rejects `durationDays > 365`.\n * Values above this maximum are automatically capped with a console warning.\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 * How long cached registry results remain valid, in seconds.\n * Default: `86400` (24 hours).\n */\n registryTTL?: number;\n /**\n * Per-chain wrappers registry address overrides, merged on top of chain definitions.\n * Use for custom or local chains (e.g. Hardhat) where no default registry exists.\n */\n registryAddresses?: Record<number, Address>;\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: RelayerDispatcher;\n readonly provider: GenericProvider;\n readonly signer: GenericSigner;\n readonly storage: GenericStorage;\n readonly sessionStorage: GenericStorage;\n readonly credentials: CredentialsManager;\n readonly delegatedCredentials: DelegatedCredentialsManager;\n /** Persistent cache for decrypted FHE plaintext values, scoped by (requester, contract, handle). */\n readonly cache: DecryptCache;\n /**\n * A {@link WrappersRegistry} instance auto-configured for the current chain.\n * Uses built-in defaults from chain configs, 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 readonly #identityListeners = new Set<SignerIdentityListener>();\n #unsubscribeSigner?: () => void;\n\n constructor(config: ZamaSDKConfig) {\n this.relayer = config.relayer;\n this.provider = config.provider;\n this.signer = config.signer;\n this.storage = config.storage;\n this.sessionStorage = config.sessionStorage ?? new MemoryStorage();\n this.cache = new DecryptCache(config.storage);\n this.#onEvent = config.onEvent ?? function () {};\n // Chain definitions provide defaults; explicit registryAddresses override them.\n const registryAddresses: Record<number, Address> = {};\n for (const chain of config.chains ?? []) {\n if (chain.registryAddress) {\n registryAddresses[chain.id] = chain.registryAddress;\n }\n }\n Object.assign(registryAddresses, config.registryAddresses);\n this.registry = new WrappersRegistry({\n provider: this.provider,\n registryTTL: config.registryTTL,\n registryAddresses,\n });\n this.#registryTTL = config.registryTTL;\n const credentialsConfig = {\n relayer: this.relayer,\n signer: config.signer,\n storage: this.storage,\n sessionStorage: this.sessionStorage,\n keypairTTL: (() => {\n const ttl = config.keypairTTL ?? 2592000;\n if (ttl <= 0 || isNaN(ttl)) {\n throw new Error(\"keypairTTL must be a positive number (seconds)\");\n }\n if (ttl > MAX_KEYPAIR_TTL) {\n // oxlint-disable-next-line no-console\n console.warn(\n `[zama-sdk] keypairTTL (${ttl}s) exceeds the fhevm maximum of 365 days (${MAX_KEYPAIR_TTL}s); capping to ${MAX_KEYPAIR_TTL}s.`,\n );\n return MAX_KEYPAIR_TTL;\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\n this.#unsubscribeSigner = this.signer.subscribe?.((change) => {\n void this.#handleIdentityChange(change);\n });\n }\n\n /**\n * Subscribe to wallet identity transitions. The SDK maintains a single\n * internal subscription to `signer.subscribe` and fans out to listeners\n * after running core cleanup (credential revocation + cache clear).\n *\n * Returns a no-op unsubscribe if the signer cannot emit lifecycle events.\n */\n onIdentityChange(listener: SignerIdentityListener): () => void {\n this.#identityListeners.add(listener);\n return () => {\n this.#identityListeners.delete(listener);\n };\n }\n\n /**\n * Pre-flight chain coherence check for write operations.\n *\n * Calls `signer.getChainId()` and `provider.getChainId()` in parallel.\n * Throws {@link ChainMismatchError} if they differ.\n *\n * @param operation - The operation name, included in the error message.\n * @returns The chain ID shared by both signer and provider.\n * @throws {@link ChainMismatchError} if signer and provider report different chain IDs.\n */\n async requireChainAlignment(operation: string): Promise<number> {\n const [signerChainId, providerChainId] = await Promise.all([\n this.signer.getChainId(),\n this.provider.getChainId(),\n ]);\n if (signerChainId !== providerChainId) {\n throw new ChainMismatchError({\n operation,\n signerChainId,\n providerChainId,\n });\n }\n return signerChainId;\n }\n\n async #handleIdentityChange(change: SignerIdentityChange): Promise<void> {\n if (change.previous) {\n const previous = change.previous;\n await swallow(\"revoke previous identity\", () => this.credentials.revokeFor(previous));\n await swallow(\"clear decrypt cache\", () => this.cache.clearForRequester(previous.address));\n }\n const nextChainId = change.next?.chainId;\n if (nextChainId !== undefined) {\n await swallow(\"switch relayer chain\", () => {\n this.relayer.switchChain(nextChainId);\n });\n }\n for (const listener of this.#identityListeners) {\n await swallow(\"identity listener\", () => listener(change));\n }\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.\n */\n createReadonlyToken(address: Address): ReadonlyToken {\n return new ReadonlyToken(this, address);\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.\n */\n createToken(address: Address, wrapper?: Address): Token {\n return new Token(this, address, wrapper);\n }\n\n /**\n * Emit a structured SDK event. Used by {@link Token}/{@link ReadonlyToken}\n * to surface lifecycle events through the unified SDK event stream.\n *\n * Listener exceptions are caught and logged so that a misbehaving subscriber\n * can never corrupt SDK operations.\n *\n * Application code should subscribe via the `onEvent` config option, never\n * call this directly.\n *\n * @internal\n */\n emitEvent(input: ZamaSDKEventInput, tokenAddress?: Address): void {\n try {\n this.#onEvent({\n ...input,\n tokenAddress,\n timestamp: Date.now(),\n } as ZamaSDKEvent);\n } catch (error) {\n // oxlint-disable-next-line no-console\n console.error(\"[zama-sdk] onEvent listener threw:\", error);\n }\n }\n\n /**\n * Create a {@link WrappersRegistry} instance bound to this SDK's provider.\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 provider: this.provider,\n registryAddresses,\n registryTTL: this.#registryTTL,\n });\n }\n\n /**\n * Pre-authorize contract addresses for decryption, triggering a single\n * wallet signature prompt. Subsequent {@link userDecrypt} calls whose\n * handles span the same set will reuse the cached credentials without\n * an additional prompt.\n *\n * @param contractAddresses - One or more contract addresses to authorize.\n *\n * @example\n * ```ts\n * // Sign once for three tokens, then decrypt individually\n * await sdk.allow([cUSDT, cDAI, cWETH]);\n * const a = await sdk.userDecrypt([{ handle: h1, contractAddress: cUSDT }]);\n * const b = await sdk.userDecrypt([{ handle: h2, contractAddress: cDAI }]);\n * ```\n */\n async allow(contractAddresses: Address[]): Promise<void> {\n if (contractAddresses.length === 0) {\n return;\n }\n await this.credentials.allow(...contractAddresses);\n }\n\n /**\n * Decrypt one or more FHE handles. Results are cached — repeated calls\n * for the same handle skip the relayer round-trip.\n *\n * Zero handles are mapped to `0n` without hitting the relayer.\n * Events (`DecryptStart/End/Error`) are emitted uniformly.\n * Relayer errors are wrapped into typed SDK errors.\n *\n * @param handles - Handles to decrypt, each paired with its contract address.\n * @returns A record mapping each handle to its decrypted clear-text value.\n * @throws {@link ChainMismatchError} if signer and provider are on different chains.\n *\n * @example\n * ```ts\n * const values = await sdk.userDecrypt([\n * { handle: balanceHandle, contractAddress: cUSDT },\n * ]);\n * console.log(values[balanceHandle]); // 1000n\n * ```\n */\n async userDecrypt(handles: DecryptHandle[]): Promise<Record<Handle, ClearValueType>> {\n await this.requireChainAlignment(\"userDecrypt\");\n if (handles.length === 0) {\n return {};\n }\n\n // Normalize addresses once at the top\n const normalized = handles.map((h) => ({\n handle: h.handle,\n contractAddress: getAddress(h.contractAddress),\n }));\n\n const result: Record<Handle, ClearValueType> = {};\n const nonZero: DecryptHandle[] = [];\n\n // Filter zero handles → 0n without relayer\n for (const h of normalized) {\n if (isZeroHandle(h.handle)) {\n result[h.handle] = 0n;\n } else {\n nonZero.push(h);\n }\n }\n\n if (nonZero.length === 0) {\n return result;\n }\n\n // Cache partition\n const signerAddress = await this.signer.getAddress();\n const uncached: DecryptHandle[] = [];\n\n for (const h of nonZero) {\n const cached = await this.cache.get(signerAddress, h.contractAddress, h.handle);\n if (cached !== null) {\n result[h.handle] = cached;\n } else {\n uncached.push(h);\n }\n }\n\n if (uncached.length === 0) {\n return result;\n }\n\n // Derive contract addresses from ALL handles for stable credential cache key\n const creds = await this.credentials.allow(\n ...new Set(normalized.map((h) => h.contractAddress)),\n );\n\n // Group uncached by contract\n const byContract = new Map<Address, Handle[]>();\n for (const h of uncached) {\n const existing = byContract.get(h.contractAddress);\n if (existing) {\n existing.push(h.handle);\n } else {\n byContract.set(h.contractAddress, [h.handle]);\n }\n }\n\n // Decrypt per contract group with bounded concurrency\n const t0 = Date.now();\n const uncachedHandles = uncached.map((h) => h.handle);\n\n try {\n this.emitEvent({\n type: ZamaSDKEvents.DecryptStart,\n handles: uncachedHandles,\n });\n\n await pLimit(\n [...byContract.entries()].map(([contractAddress, contractHandles]) => async () => {\n const decrypted = await this.relayer.userDecrypt({\n handles: contractHandles,\n contractAddress,\n signedContractAddresses: creds.contractAddresses,\n privateKey: creds.privateKey,\n publicKey: creds.publicKey,\n signature: creds.signature,\n signerAddress,\n startTimestamp: creds.startTimestamp,\n durationDays: creds.durationDays,\n });\n\n for (const [handle, value] of Object.entries(decrypted)) {\n result[handle as Handle] = value;\n await this.cache.set(signerAddress, contractAddress, handle as Handle, value);\n }\n }),\n 5,\n );\n\n // Emit only the freshly-decrypted subset in `result` so its keys match\n // `handles`. Cached and zero-handle entries are intentionally excluded.\n const uncachedResult: Record<Handle, ClearValueType> = {};\n for (const handle of uncachedHandles) {\n const value = result[handle];\n if (value !== undefined) {\n uncachedResult[handle] = value;\n }\n }\n this.emitEvent({\n type: ZamaSDKEvents.DecryptEnd,\n durationMs: Date.now() - t0,\n handles: uncachedHandles,\n result: uncachedResult,\n });\n return result;\n } catch (error) {\n this.emitEvent({\n type: ZamaSDKEvents.DecryptError,\n error: toError(error),\n durationMs: Date.now() - t0,\n handles: uncachedHandles,\n });\n throw wrapDecryptError(error, \"Failed to decrypt handles\");\n }\n }\n\n /**\n * Publicly decrypt one or more FHE handles.\n *\n * Returns the decryption proof alongside the clear-text values so callers\n * can submit on-chain finalization transactions (e.g. `finalizeUnwrap`).\n *\n * @param handles - FHE handles to decrypt publicly.\n * @returns Clear-text values, ABI-encoded values, and the decryption proof.\n *\n * @example\n * ```ts\n * const { clearValues, decryptionProof, abiEncodedClearValues } =\n * await sdk.publicDecrypt([handle]);\n * ```\n */\n async publicDecrypt(handles: Handle[]): Promise<PublicDecryptResult> {\n if (handles.length === 0) {\n return {\n clearValues: {},\n decryptionProof: \"0x\",\n abiEncodedClearValues: \"0x\",\n };\n }\n\n try {\n return await this.relayer.publicDecrypt(handles);\n } catch (error) {\n throw wrapDecryptError(error, \"Public decryption failed\");\n }\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 const address = await this.signer.getAddress();\n const chainId = await this.signer.getChainId();\n try {\n await this.credentials.revokeFor({ address, chainId });\n } finally {\n await this.cache.clearForRequester(address);\n }\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 this.#identityListeners.clear();\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, provider, 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\";\nimport type { Handle } from \"../relayer/relayer-sdk.types\";\n\nconst STORAGE_PREFIX = \"zama:pending-unshield:\";\nconst CURRENT_VERSION = 1;\n\n/**\n * Persisted state for an in-progress unshield request.\n * Used to resume an interrupted unshield after page reload.\n */\nexport interface PendingUnshieldRequest {\n /** Transaction hash of the original unwrap call. */\n readonly unwrapTxHash: Hex;\n /**\n * Request identifier emitted by upgraded wrapper contracts.\n * Present only for requests initiated after the protocol upgrade.\n * When defined, pass this as `unwrapRequestId` to `finalizeUnwrap`.\n * When absent (legacy request), pass the `encryptedAmount` from the `UnwrapRequested` event.\n */\n readonly unwrapRequestId?: Handle;\n}\n\ninterface StoredPendingUnshieldRequest extends PendingUnshieldRequest {\n readonly version: typeof CURRENT_VERSION;\n}\n\nfunction storageKey(wrapperAddress: Address): string {\n return `${STORAGE_PREFIX}${wrapperAddress}`;\n}\n\nfunction normalizePendingUnshield(\n value: Hex | StoredPendingUnshieldRequest | null,\n): PendingUnshieldRequest | null {\n if (value === null) {\n return null;\n }\n if (typeof value === \"string\") {\n return { unwrapTxHash: value };\n }\n if (typeof value === \"object\" && \"unwrapTxHash\" in value) {\n return {\n unwrapTxHash: value.unwrapTxHash,\n unwrapRequestId: value.unwrapRequestId,\n };\n }\n return null;\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 unwrapRequestId?: Handle,\n): Promise<void> {\n if (unwrapRequestId === undefined) {\n await storage.set(storageKey(wrapperAddress), unwrapTxHash);\n return;\n }\n\n await storage.set(storageKey(wrapperAddress), {\n version: CURRENT_VERSION,\n unwrapTxHash,\n unwrapRequestId,\n } satisfies StoredPendingUnshieldRequest);\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 const request = await loadPendingUnshieldRequest(storage, wrapperAddress);\n return request?.unwrapTxHash ?? null;\n}\n\n/**\n * Load a previously saved unwrap request, including `unwrapRequestId` when available.\n *\n * `resumeUnshield()` only needs `unwrapTxHash`: it reloads the transaction receipt and\n * rediscovers the right finalize handle from the emitted `UnwrapRequested` event.\n * Use `unwrapRequestId` directly only for custom flows that call `finalizeUnwrap()`\n * without reloading the original unwrap receipt.\n */\nexport async function loadPendingUnshieldRequest(\n storage: GenericStorage,\n wrapperAddress: Address,\n): Promise<PendingUnshieldRequest | null> {\n const value = await storage.get<Hex | StoredPendingUnshieldRequest>(storageKey(wrapperAddress));\n return normalizePendingUnshield(value);\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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"}
|