@veridex/sdk 1.0.1 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/auth/prepareAuth.js.map +1 -1
- package/dist/auth/prepareAuth.mjs.map +1 -1
- package/dist/chains/starknet/index.d.mts +1 -2
- package/dist/chains/starknet/index.js +1 -13
- package/dist/chains/starknet/index.js.map +1 -1
- package/dist/chains/starknet/index.mjs +1 -1
- package/dist/chains/sui/index.d.mts +2 -2
- package/dist/chains/sui/index.js +2 -2
- package/dist/chains/sui/index.js.map +1 -1
- package/dist/chains/sui/index.mjs +1 -1
- package/dist/{chunk-EFIURACP.mjs → chunk-MLXQHIH2.mjs} +2 -14
- package/dist/chunk-MLXQHIH2.mjs.map +1 -0
- package/dist/{chunk-PRHNGA4G.mjs → chunk-SXXGTQIR.mjs} +3 -3
- package/dist/{chunk-PRHNGA4G.mjs.map → chunk-SXXGTQIR.mjs.map} +1 -1
- package/dist/index.d.mts +3 -0
- package/dist/index.js +21 -15
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +20 -2
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-EFIURACP.mjs.map +0 -1
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/core/BalanceManager.ts","../src/core/TransactionTracker.ts","../src/core/CrossChainManager.ts","../src/core/RelayerClient.ts","../src/core/ChainDetector.ts","../src/core/TransactionParser.ts","../src/core/TransactionSummary.types.ts","../src/core/SpendingLimitsManager.ts","../src/core/SpendingLimits.types.ts","../src/core/AccountManager.ts","../src/core/RecoveryManager.ts","../src/core/MultisigManager.ts","../src/core/PolicyEnforcement.ts","../src/core/VeridexError.ts","../src/core/BalanceWatcher.ts","../src/core/VeridexSDK.ts","../src/core/GasSponsor.ts","../src/factory.ts","../src/core/BrowserCapabilities.ts","../src/core/CredentialManager.ts","../src/core/CrossOriginAuth.ts","../src/core/InjectedWalletAdapter.ts","../src/sessions/index.ts","../src/sessions/types.ts","../src/sessions/crypto.ts","../src/sessions/storage.ts","../src/constants/errors.ts","../src/core/EnterpriseManager.ts","../src/erc8004/contracts.ts"],"sourcesContent":["/**\n * Veridex Protocol SDK - Balance Manager\n * \n * Manages balance fetching for native tokens and ERC20s across chains\n */\n\nimport { ethers } from 'ethers';\nimport { \n TokenInfo, \n getTokenList, \n getAllTokens, \n isNativeToken, \n NATIVE_TOKEN_ADDRESS \n} from '../constants/tokens.js';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface TokenBalance {\n /** Token information */\n token: TokenInfo;\n /** Raw balance in smallest units */\n balance: bigint;\n /** Formatted balance with decimals */\n formatted: string;\n /** USD value (if price available) */\n usdValue?: number;\n}\n\nexport interface PortfolioBalance {\n /** Wormhole chain ID */\n wormholeChainId: number;\n /** Chain name */\n chainName: string;\n /** Address being queried */\n address: string;\n /** Individual token balances */\n tokens: TokenBalance[];\n /** Total USD value (if prices available) */\n totalUsdValue?: number;\n /** Timestamp of last update */\n lastUpdated: number;\n}\n\nexport interface BalanceManagerConfig {\n /** Whether to cache balances */\n cacheBalances?: boolean;\n /** Cache TTL in milliseconds */\n cacheTtl?: number;\n /** Custom RPC URLs by chain ID */\n customRpcUrls?: Record<number, string>;\n}\n\n// ============================================================================\n// Constants\n// ============================================================================\n\n/**\n * Default RPC URLs for testnet chains\n */\nconst DEFAULT_RPC_URLS: Record<number, string> = {\n 10002: 'https://ethereum-sepolia-rpc.publicnode.com',\n 10003: 'https://sepolia-rollup.arbitrum.io/rpc',\n 10004: 'https://sepolia.base.org',\n 10005: 'https://sepolia.optimism.io',\n};\n\n/**\n * Testnet token prices (USD) for development/testing\n * These are static estimates since testnet tokens have no real value\n */\nconst TESTNET_TOKEN_PRICES: Record<string, number> = {\n ETH: 2500,\n WETH: 2500,\n 'WETH.BASE': 2500, // Wormhole-wrapped Base WETH\n USDC: 1,\n USDT: 1,\n DAI: 1,\n WBTC: 60000,\n LINK: 15,\n UNI: 8,\n};\n\n/**\n * ERC20 ABI for balance checking\n */\nconst ERC20_ABI = [\n 'function balanceOf(address owner) view returns (uint256)',\n 'function decimals() view returns (uint8)',\n 'function symbol() view returns (string)',\n 'function name() view returns (string)',\n];\n\n/**\n * Default cache TTL: 30 seconds\n */\nconst DEFAULT_CACHE_TTL = 30_000;\n\n// ============================================================================\n// Balance Cache\n// ============================================================================\n\ninterface CachedBalance {\n balance: PortfolioBalance;\n expiresAt: number;\n}\n\n// ============================================================================\n// Balance Manager Class\n// ============================================================================\n\nexport class BalanceManager {\n private config: Required<BalanceManagerConfig>;\n private providers: Map<number, ethers.JsonRpcProvider> = new Map();\n private cache: Map<string, CachedBalance> = new Map();\n\n constructor(config: BalanceManagerConfig = {}) {\n this.config = {\n cacheBalances: config.cacheBalances ?? true,\n cacheTtl: config.cacheTtl ?? DEFAULT_CACHE_TTL,\n customRpcUrls: config.customRpcUrls ?? {},\n };\n }\n\n // ========================================================================\n // Public Methods\n // ========================================================================\n\n /**\n * Get balance for a specific token on a chain\n * \n * @param wormholeChainId - The Wormhole chain ID\n * @param address - The address to check balance for\n * @param tokenAddress - Token address or 'native' for native token\n * @returns TokenBalance with raw and formatted amounts\n */\n async getBalance(\n wormholeChainId: number,\n address: string,\n tokenAddress: string\n ): Promise<TokenBalance> {\n const provider = this.getProvider(wormholeChainId);\n const tokenList = getTokenList(wormholeChainId);\n \n if (!tokenList) {\n throw new Error(`Chain ${wormholeChainId} not supported`);\n }\n\n const tokens = getAllTokens(wormholeChainId);\n let tokenInfo = tokens.find(\n t => t.address.toLowerCase() === tokenAddress.toLowerCase()\n );\n\n // Handle native token variations\n if (!tokenInfo && isNativeToken(tokenAddress)) {\n tokenInfo = tokenList.nativeToken;\n }\n\n // If still no token info, create a generic one\n if (!tokenInfo) {\n tokenInfo = await this.fetchTokenInfo(provider, tokenAddress);\n }\n\n const balance = await this.fetchBalance(provider, address, tokenAddress, tokenInfo);\n const formatted = ethers.formatUnits(balance, tokenInfo.decimals);\n // Calculate USD value using testnet prices\n const price = TESTNET_TOKEN_PRICES[tokenInfo.symbol.toUpperCase()];\n const usdValue = price ? parseFloat(formatted) * price : undefined;\n\n return {\n token: tokenInfo,\n balance,\n formatted,\n usdValue,\n };\n }\n\n /**\n * Get all token balances for an address on a chain\n * \n * @param wormholeChainId - The Wormhole chain ID\n * @param address - The address to check balances for\n * @param includeZeroBalances - Whether to include tokens with 0 balance\n * @returns PortfolioBalance with all token balances\n */\n async getPortfolioBalance(\n wormholeChainId: number,\n address: string,\n includeZeroBalances: boolean = false\n ): Promise<PortfolioBalance> {\n // Check cache first\n const cacheKey = `${wormholeChainId}:${address.toLowerCase()}`;\n if (this.config.cacheBalances) {\n const cached = this.cache.get(cacheKey);\n if (cached && cached.expiresAt > Date.now()) {\n return cached.balance;\n }\n }\n\n const tokenList = getTokenList(wormholeChainId);\n if (!tokenList) {\n throw new Error(`Chain ${wormholeChainId} not supported`);\n }\n\n const provider = this.getProvider(wormholeChainId);\n const tokens = getAllTokens(wormholeChainId);\n const balances: TokenBalance[] = [];\n\n // Fetch all balances in parallel\n const balancePromises = tokens.map(async (token) => {\n try {\n const balance = await this.fetchBalance(\n provider,\n address,\n token.address,\n token\n );\n const formatted = ethers.formatUnits(balance, token.decimals);\n // Calculate USD value using testnet prices\n const price = TESTNET_TOKEN_PRICES[token.symbol.toUpperCase()];\n const usdValue = price ? parseFloat(formatted) * price : undefined;\n return { token, balance, formatted, usdValue };\n } catch (error) {\n console.warn(`Failed to fetch ${token.symbol} balance:`, error);\n return { token, balance: 0n, formatted: '0', usdValue: undefined };\n }\n });\n\n const results = await Promise.all(balancePromises);\n\n for (const result of results) {\n if (includeZeroBalances || result.balance > 0n) {\n balances.push(result);\n }\n }\n\n // Calculate total USD value\n const totalUsdValue = balances.reduce((sum, b) => sum + (b.usdValue ?? 0), 0);\n\n const portfolio: PortfolioBalance = {\n wormholeChainId,\n chainName: tokenList.chainName,\n address,\n tokens: balances,\n totalUsdValue: totalUsdValue > 0 ? totalUsdValue : undefined,\n lastUpdated: Date.now(),\n };\n\n // Cache the result\n if (this.config.cacheBalances) {\n this.cache.set(cacheKey, {\n balance: portfolio,\n expiresAt: Date.now() + this.config.cacheTtl,\n });\n }\n\n return portfolio;\n }\n\n /**\n * Get native token balance\n * \n * @param wormholeChainId - The Wormhole chain ID\n * @param address - The address to check\n * @returns TokenBalance for native token\n */\n async getNativeBalance(\n wormholeChainId: number,\n address: string\n ): Promise<TokenBalance> {\n return this.getBalance(wormholeChainId, address, NATIVE_TOKEN_ADDRESS);\n }\n\n /**\n * Get balances across multiple chains for an address\n * \n * @param address - The address to check\n * @param chainIds - Array of Wormhole chain IDs to check\n * @returns Array of PortfolioBalance for each chain\n */\n async getMultiChainBalances(\n address: string,\n chainIds: number[]\n ): Promise<PortfolioBalance[]> {\n const promises = chainIds.map(chainId =>\n this.getPortfolioBalance(chainId, address).catch(error => {\n console.warn(`Failed to fetch balances for chain ${chainId}:`, error);\n return null;\n })\n );\n\n const results = await Promise.all(promises);\n return results.filter((r): r is PortfolioBalance => r !== null);\n }\n\n /**\n * Clear the balance cache\n */\n clearCache(): void {\n this.cache.clear();\n }\n\n /**\n * Invalidate cache for a specific address\n */\n invalidateCache(wormholeChainId: number, address: string): void {\n const cacheKey = `${wormholeChainId}:${address.toLowerCase()}`;\n this.cache.delete(cacheKey);\n }\n\n /**\n * Add or update RPC URL for a chain\n */\n setRpcUrl(wormholeChainId: number, rpcUrl: string): void {\n this.config.customRpcUrls[wormholeChainId] = rpcUrl;\n // Clear existing provider to force recreation\n this.providers.delete(wormholeChainId);\n }\n\n // ========================================================================\n // Private Methods\n // ========================================================================\n\n /**\n * Get or create a provider for a chain\n */\n private getProvider(wormholeChainId: number): ethers.JsonRpcProvider {\n let provider = this.providers.get(wormholeChainId);\n if (provider) {\n return provider;\n }\n\n const rpcUrl = this.config.customRpcUrls[wormholeChainId] ?? \n DEFAULT_RPC_URLS[wormholeChainId];\n \n if (!rpcUrl) {\n throw new Error(`No RPC URL configured for chain ${wormholeChainId}`);\n }\n\n provider = new ethers.JsonRpcProvider(rpcUrl);\n this.providers.set(wormholeChainId, provider);\n return provider;\n }\n\n /**\n * Fetch balance for a token\n */\n private async fetchBalance(\n provider: ethers.JsonRpcProvider,\n address: string,\n tokenAddress: string,\n _tokenInfo: TokenInfo\n ): Promise<bigint> {\n if (isNativeToken(tokenAddress)) {\n return await provider.getBalance(address);\n }\n\n const contract = new ethers.Contract(tokenAddress, ERC20_ABI, provider);\n return await contract.balanceOf(address);\n }\n\n /**\n * Fetch token info from contract\n */\n private async fetchTokenInfo(\n provider: ethers.JsonRpcProvider,\n tokenAddress: string\n ): Promise<TokenInfo> {\n const contract = new ethers.Contract(tokenAddress, ERC20_ABI, provider);\n \n const [symbol, name, decimals] = await Promise.all([\n contract.symbol().catch(() => 'UNKNOWN'),\n contract.name().catch(() => 'Unknown Token'),\n contract.decimals().catch(() => 18),\n ]);\n\n return {\n symbol,\n name,\n address: tokenAddress,\n decimals: Number(decimals),\n isNative: false,\n };\n }\n}\n","/**\n * Veridex Protocol SDK - Transaction Tracker\n * \n * Tracks transaction status from pending to confirmed\n */\n\nimport { ethers } from 'ethers';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport type TransactionStatus = \n | 'pending'\n | 'submitted'\n | 'confirming'\n | 'confirmed'\n | 'failed'\n | 'dropped';\n\nexport interface TransactionState {\n /** Transaction hash */\n hash: string;\n /** Current status */\n status: TransactionStatus;\n /** Wormhole chain ID where transaction was sent */\n wormholeChainId: number;\n /** Block number when confirmed */\n blockNumber?: number;\n /** Number of confirmations */\n confirmations: number;\n /** Required confirmations for finality */\n requiredConfirmations: number;\n /** Gas used (after confirmation) */\n gasUsed?: bigint;\n /** Effective gas price */\n effectiveGasPrice?: bigint;\n /** Error message if failed */\n error?: string;\n /** Timestamp when transaction was submitted */\n submittedAt: number;\n /** Timestamp when transaction was confirmed */\n confirmedAt?: number;\n /** VAA sequence number (for cross-chain txs) */\n vaaSequence?: bigint;\n}\n\nexport interface TrackerConfig {\n /** Polling interval in ms (default: 2000) */\n pollingInterval?: number;\n /** Required confirmations for finality (default: 1) */\n requiredConfirmations?: number;\n /** Timeout in ms before marking as dropped (default: 300000 - 5 min) */\n timeout?: number;\n /** Custom RPC URLs by chain ID */\n customRpcUrls?: Record<number, string>;\n}\n\nexport type TransactionCallback = (state: TransactionState) => void;\n\n// ============================================================================\n// Constants\n// ============================================================================\n\nconst DEFAULT_POLLING_INTERVAL = 2000;\nconst DEFAULT_REQUIRED_CONFIRMATIONS = 1;\nconst DEFAULT_TIMEOUT = 300_000; // 5 minutes\n\nconst DEFAULT_RPC_URLS: Record<number, string> = {\n 10002: 'https://ethereum-sepolia-rpc.publicnode.com',\n 10003: 'https://sepolia-rollup.arbitrum.io/rpc',\n 10004: 'https://sepolia.base.org',\n 10005: 'https://sepolia.optimism.io',\n};\n\n// ============================================================================\n// Transaction Tracker Class\n// ============================================================================\n\nexport class TransactionTracker {\n private config: Required<TrackerConfig>;\n private providers: Map<number, ethers.JsonRpcProvider> = new Map();\n private trackedTransactions: Map<string, TransactionState> = new Map();\n private callbacks: Map<string, TransactionCallback[]> = new Map();\n private pollingIntervals: Map<string, NodeJS.Timeout> = new Map();\n\n constructor(config: TrackerConfig = {}) {\n this.config = {\n pollingInterval: config.pollingInterval ?? DEFAULT_POLLING_INTERVAL,\n requiredConfirmations: config.requiredConfirmations ?? DEFAULT_REQUIRED_CONFIRMATIONS,\n timeout: config.timeout ?? DEFAULT_TIMEOUT,\n customRpcUrls: config.customRpcUrls ?? {},\n };\n }\n\n // ========================================================================\n // Public Methods\n // ========================================================================\n\n /**\n * Track a transaction and receive status updates\n * \n * @param hash - Transaction hash\n * @param wormholeChainId - Chain where transaction was sent\n * @param callback - Optional callback for status updates\n * @param vaaSequence - Optional VAA sequence for cross-chain transactions\n * @returns Initial transaction state\n */\n track(\n hash: string,\n wormholeChainId: number,\n callback?: TransactionCallback,\n vaaSequence?: bigint\n ): TransactionState {\n // Create initial state\n const state: TransactionState = {\n hash,\n status: 'pending',\n wormholeChainId,\n confirmations: 0,\n requiredConfirmations: this.config.requiredConfirmations,\n submittedAt: Date.now(),\n vaaSequence,\n };\n\n this.trackedTransactions.set(hash, state);\n \n if (callback) {\n this.addCallback(hash, callback);\n }\n\n // Start polling\n this.startPolling(hash, wormholeChainId);\n\n return state;\n }\n\n /**\n * Add a callback for transaction updates\n */\n addCallback(hash: string, callback: TransactionCallback): void {\n const existing = this.callbacks.get(hash) ?? [];\n existing.push(callback);\n this.callbacks.set(hash, existing);\n }\n\n /**\n * Remove a callback\n */\n removeCallback(hash: string, callback: TransactionCallback): void {\n const existing = this.callbacks.get(hash) ?? [];\n const filtered = existing.filter(cb => cb !== callback);\n if (filtered.length > 0) {\n this.callbacks.set(hash, filtered);\n } else {\n this.callbacks.delete(hash);\n }\n }\n\n /**\n * Get current state of a tracked transaction\n */\n getState(hash: string): TransactionState | null {\n return this.trackedTransactions.get(hash) ?? null;\n }\n\n /**\n * Wait for a transaction to reach confirmed status\n * \n * @param hash - Transaction hash\n * @param wormholeChainId - Chain where transaction was sent\n * @returns Promise that resolves when confirmed or rejects on failure\n */\n async waitForConfirmation(\n hash: string,\n wormholeChainId: number\n ): Promise<TransactionState> {\n // Check if already tracked\n let state = this.trackedTransactions.get(hash);\n \n if (!state) {\n state = this.track(hash, wormholeChainId);\n }\n\n // If already confirmed or failed, return immediately\n if (state.status === 'confirmed' || state.status === 'failed' || state.status === 'dropped') {\n return state;\n }\n\n // Wait for confirmation\n return new Promise((resolve, reject) => {\n const callback: TransactionCallback = (newState) => {\n if (newState.status === 'confirmed') {\n this.removeCallback(hash, callback);\n resolve(newState);\n } else if (newState.status === 'failed' || newState.status === 'dropped') {\n this.removeCallback(hash, callback);\n reject(new Error(newState.error ?? `Transaction ${newState.status}`));\n }\n };\n\n this.addCallback(hash, callback);\n });\n }\n\n /**\n * Stop tracking a transaction\n */\n stopTracking(hash: string): void {\n const interval = this.pollingIntervals.get(hash);\n if (interval) {\n clearInterval(interval);\n this.pollingIntervals.delete(hash);\n }\n this.trackedTransactions.delete(hash);\n this.callbacks.delete(hash);\n }\n\n /**\n * Stop tracking all transactions\n */\n stopAll(): void {\n for (const hash of this.pollingIntervals.keys()) {\n this.stopTracking(hash);\n }\n }\n\n /**\n * Get all tracked transactions\n */\n getAllTracked(): TransactionState[] {\n return Array.from(this.trackedTransactions.values());\n }\n\n /**\n * Get pending transactions\n */\n getPending(): TransactionState[] {\n return this.getAllTracked().filter(\n tx => tx.status === 'pending' || tx.status === 'submitted' || tx.status === 'confirming'\n );\n }\n\n // ========================================================================\n // Private Methods\n // ========================================================================\n\n /**\n * Get or create provider for a chain\n */\n private getProvider(wormholeChainId: number): ethers.JsonRpcProvider {\n let provider = this.providers.get(wormholeChainId);\n if (provider) {\n return provider;\n }\n\n const rpcUrl = this.config.customRpcUrls[wormholeChainId] ?? \n DEFAULT_RPC_URLS[wormholeChainId];\n \n if (!rpcUrl) {\n throw new Error(`No RPC URL configured for chain ${wormholeChainId}`);\n }\n\n provider = new ethers.JsonRpcProvider(rpcUrl);\n this.providers.set(wormholeChainId, provider);\n return provider;\n }\n\n /**\n * Start polling for transaction status\n */\n private startPolling(hash: string, wormholeChainId: number): void {\n // Initial check\n this.checkTransaction(hash, wormholeChainId);\n\n // Set up interval\n const interval = setInterval(() => {\n this.checkTransaction(hash, wormholeChainId);\n }, this.config.pollingInterval);\n\n this.pollingIntervals.set(hash, interval);\n }\n\n /**\n * Check transaction status\n */\n private async checkTransaction(hash: string, wormholeChainId: number): Promise<void> {\n const state = this.trackedTransactions.get(hash);\n if (!state) {\n this.stopTracking(hash);\n return;\n }\n\n // Check timeout\n if (Date.now() - state.submittedAt > this.config.timeout) {\n this.updateState(hash, {\n status: 'dropped',\n error: 'Transaction timeout - possibly dropped from mempool',\n });\n this.stopTracking(hash);\n return;\n }\n\n try {\n const provider = this.getProvider(wormholeChainId);\n const receipt = await provider.getTransactionReceipt(hash);\n\n if (!receipt) {\n // Transaction not yet mined\n if (state.status === 'pending') {\n this.updateState(hash, { status: 'submitted' });\n }\n return;\n }\n\n // Transaction is mined\n const currentBlock = await provider.getBlockNumber();\n const confirmations = currentBlock - receipt.blockNumber + 1;\n\n if (receipt.status === 0) {\n // Transaction failed\n this.updateState(hash, {\n status: 'failed',\n blockNumber: receipt.blockNumber,\n confirmations,\n gasUsed: receipt.gasUsed,\n effectiveGasPrice: receipt.gasPrice,\n error: 'Transaction reverted',\n });\n this.stopTracking(hash);\n return;\n }\n\n if (confirmations >= this.config.requiredConfirmations) {\n // Fully confirmed\n this.updateState(hash, {\n status: 'confirmed',\n blockNumber: receipt.blockNumber,\n confirmations,\n gasUsed: receipt.gasUsed,\n effectiveGasPrice: receipt.gasPrice,\n confirmedAt: Date.now(),\n });\n this.stopTracking(hash);\n } else {\n // Still confirming\n this.updateState(hash, {\n status: 'confirming',\n blockNumber: receipt.blockNumber,\n confirmations,\n gasUsed: receipt.gasUsed,\n effectiveGasPrice: receipt.gasPrice,\n });\n }\n } catch (error) {\n console.warn(`Error checking transaction ${hash}:`, error);\n // Don't update state on transient errors\n }\n }\n\n /**\n * Update transaction state and notify callbacks\n */\n private updateState(hash: string, updates: Partial<TransactionState>): void {\n const current = this.trackedTransactions.get(hash);\n if (!current) return;\n\n const newState: TransactionState = { ...current, ...updates };\n this.trackedTransactions.set(hash, newState);\n\n // Notify callbacks\n const callbacks = this.callbacks.get(hash) ?? [];\n for (const callback of callbacks) {\n try {\n callback(newState);\n } catch (error) {\n console.error('Error in transaction callback:', error);\n }\n }\n }\n}\n\n// ============================================================================\n// Helper Functions\n// ============================================================================\n\n/**\n * Create a formatted transaction explorer URL\n */\nexport function getExplorerUrl(\n wormholeChainId: number,\n hash: string\n): string | null {\n const explorers: Record<number, string> = {\n 10004: 'https://sepolia.basescan.org/tx/',\n 10005: 'https://sepolia-optimism.etherscan.io/tx/',\n 10003: 'https://sepolia.arbiscan.io/tx/',\n };\n\n const baseUrl = explorers[wormholeChainId];\n return baseUrl ? `${baseUrl}${hash}` : null;\n}\n\n/**\n * Format transaction state for display\n */\nexport function formatTransactionState(state: TransactionState): string {\n switch (state.status) {\n case 'pending':\n return 'Transaction pending...';\n case 'submitted':\n return 'Transaction submitted, waiting for confirmation...';\n case 'confirming':\n return `Confirming (${state.confirmations}/${state.requiredConfirmations})...`;\n case 'confirmed':\n return 'Transaction confirmed!';\n case 'failed':\n return `Transaction failed: ${state.error ?? 'Unknown error'}`;\n case 'dropped':\n return 'Transaction dropped from mempool';\n default:\n return 'Unknown status';\n }\n}\n","/**\n * Veridex Protocol SDK - Cross-Chain Manager\n * \n * Orchestrates cross-chain transfers including:\n * - VAA fetching and parsing\n * - Fee estimation (message + relayer fees)\n * - Transaction status tracking across chains\n * - Lifecycle callbacks for UI updates\n */\n\nimport { ethers } from 'ethers';\nimport {\n fetchVAA,\n fetchVAAByTxHash,\n parseVAA,\n parseVeridexPayload,\n encodeVAAToBytes,\n getSequenceFromTxReceipt,\n waitForGuardianSignatures,\n normalizeEmitterAddress,\n GUARDIAN_CONFIG,\n} from '../wormhole.js';\nimport type {\n BridgeParams,\n VAA,\n VeridexPayload,\n ChainConfig,\n} from './types.js';\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Cross-chain transfer lifecycle states\n */\nexport type CrossChainStatus =\n | 'preparing'\n | 'signing'\n | 'dispatching'\n | 'waiting_confirmations'\n | 'waiting_guardians'\n | 'vaa_ready'\n | 'relaying'\n | 'executing'\n | 'completed'\n | 'failed';\n\n/**\n * Progress callback for cross-chain operations\n */\nexport interface CrossChainProgress {\n status: CrossChainStatus;\n step: number;\n totalSteps: number;\n message: string;\n details?: {\n txHash?: string;\n sequence?: bigint;\n guardianSignatures?: number;\n requiredSignatures?: number;\n vaaReady?: boolean;\n destinationTxHash?: string;\n };\n}\n\n/**\n * Cross-chain transfer result\n */\nexport interface CrossChainResult {\n /** Source chain transaction hash */\n sourceTxHash: string;\n /** Wormhole message sequence number */\n sequence: bigint;\n /** Emitter address (Hub contract) */\n emitterAddress: string;\n /** Source chain Wormhole ID */\n sourceChain: number;\n /** Destination chain Wormhole ID */\n destinationChain: number;\n /** VAA base64 (once ready) */\n vaa?: string;\n /** Parsed VAA */\n parsedVaa?: VAA;\n /** Destination chain transaction hash */\n destinationTxHash?: string;\n /** Total time taken in ms */\n duration: number;\n /** Final status */\n status: CrossChainStatus;\n /** Error message if failed */\n error?: string;\n}\n\n/**\n * Fee breakdown for cross-chain transfers\n */\nexport interface CrossChainFees {\n /** Gas cost on source chain */\n sourceGas: bigint;\n /** Wormhole message fee */\n messageFee: bigint;\n /** Relayer fee (if using automatic relay) */\n relayerFee: bigint;\n /** Total estimated cost in source chain native token */\n totalCost: bigint;\n /** Formatted total cost */\n formattedTotal: string;\n /** Currency symbol */\n currency: string;\n}\n\n/**\n * Configuration for CrossChainManager\n */\nexport interface CrossChainConfig {\n /** Use testnet APIs (default: true) */\n testnet?: boolean;\n /** Relayer service URL (optional) */\n relayerUrl?: string;\n /** Max time to wait for VAA (ms) */\n vaaTimeoutMs?: number;\n /** Interval to poll for VAA (ms) */\n vaaPollingIntervalMs?: number;\n /** Required block confirmations before fetching VAA */\n confirmationsRequired?: number;\n /** Auto-relay VAA to destination (requires relayer) */\n autoRelay?: boolean;\n}\n\n/**\n * Callback type for progress updates\n */\nexport type CrossChainProgressCallback = (progress: CrossChainProgress) => void;\n\n// ============================================================================\n// Default Configuration\n// ============================================================================\n\nconst DEFAULT_CONFIG: Required<CrossChainConfig> = {\n testnet: true,\n relayerUrl: '',\n vaaTimeoutMs: 120_000, // 2 minutes\n vaaPollingIntervalMs: 3_000, // 3 seconds\n confirmationsRequired: 1,\n autoRelay: false,\n};\n\n// ============================================================================\n// CrossChainManager Class\n// ============================================================================\n\n/**\n * Manages cross-chain transfer lifecycle\n */\nexport class CrossChainManager {\n private config: Required<CrossChainConfig>;\n private pendingTransfers: Map<string, CrossChainResult> = new Map();\n\n constructor(config: CrossChainConfig = {}) {\n this.config = { ...DEFAULT_CONFIG, ...config };\n }\n\n // ========================================================================\n // Configuration\n // ========================================================================\n\n /**\n * Update configuration\n */\n setConfig(config: Partial<CrossChainConfig>): void {\n this.config = { ...this.config, ...config };\n }\n\n /**\n * Get current configuration\n */\n getConfig(): CrossChainConfig {\n return { ...this.config };\n }\n\n // ========================================================================\n // Fee Estimation\n // ========================================================================\n\n /**\n * Estimate fees for a cross-chain transfer\n */\n async estimateFees(\n params: BridgeParams,\n sourceChainConfig: ChainConfig,\n provider: ethers.Provider\n ): Promise<CrossChainFees> {\n // Get current gas price\n const feeData = await provider.getFeeData();\n const gasPrice = feeData.gasPrice ?? 0n;\n \n // Estimate gas for dispatch (Hub chain)\n // This is an approximation - actual gas depends on payload size\n const estimatedGas = 300_000n;\n const sourceGas = estimatedGas * gasPrice;\n\n // Get Wormhole message fee\n let messageFee = 0n;\n try {\n const wormholeAbi = ['function messageFee() view returns (uint256)'];\n const wormhole = new ethers.Contract(\n sourceChainConfig.contracts.wormholeCoreBridge,\n wormholeAbi,\n provider\n );\n messageFee = await wormhole.messageFee();\n } catch {\n // Default to 0 if bridge doesn't have messageFee\n }\n\n // Get relayer fee if using automatic relay\n let relayerFee = 0n;\n if (this.config.autoRelay && this.config.relayerUrl) {\n try {\n relayerFee = await this.fetchRelayerFee(\n params.destinationChain,\n sourceChainConfig.wormholeChainId\n );\n } catch {\n // Relayer fee fetch failed, continue with 0\n }\n }\n\n const totalCost = sourceGas + messageFee + relayerFee;\n\n return {\n sourceGas,\n messageFee,\n relayerFee,\n totalCost,\n formattedTotal: this.formatWei(totalCost),\n currency: 'ETH',\n };\n }\n\n /**\n * Fetch relayer fee from relayer service\n */\n private async fetchRelayerFee(\n destinationChain: number,\n _sourceChain: number\n ): Promise<bigint> {\n if (!this.config.relayerUrl) {\n return 0n;\n }\n\n // The current Veridex relayer exposes a simplified fee endpoint.\n // Source chain is accepted here for future-proofing but not required by the API today.\n const response = await fetch(\n `${this.config.relayerUrl}/api/v1/fee?targetChain=${destinationChain}`\n );\n\n if (!response.ok) {\n throw new Error('Failed to fetch relayer fee');\n }\n\n const data = await response.json() as {\n fees?: {\n wormhole?: string;\n relayer?: string;\n total?: string;\n };\n };\n\n return BigInt(data.fees?.relayer ?? '0');\n }\n\n // ========================================================================\n // VAA Operations\n // ========================================================================\n\n /**\n * Fetch VAA by sequence number\n */\n async fetchVAA(\n emitterChain: number,\n emitterAddress: string,\n sequence: bigint,\n onProgress?: CrossChainProgressCallback\n ): Promise<string> {\n onProgress?.({\n status: 'waiting_guardians',\n step: 4,\n totalSteps: 6,\n message: 'Waiting for Wormhole guardians to sign...',\n details: { sequence },\n });\n\n const vaaBase64 = await fetchVAA(emitterChain, emitterAddress, sequence, {\n testnet: this.config.testnet,\n maxRetries: Math.ceil(this.config.vaaTimeoutMs / this.config.vaaPollingIntervalMs),\n retryDelayMs: this.config.vaaPollingIntervalMs,\n onRetry: (attempt, max) => {\n onProgress?.({\n status: 'waiting_guardians',\n step: 4,\n totalSteps: 6,\n message: `Waiting for guardians (attempt ${attempt}/${max})...`,\n details: { sequence },\n });\n },\n });\n\n onProgress?.({\n status: 'vaa_ready',\n step: 5,\n totalSteps: 6,\n message: 'VAA signed and ready!',\n details: { sequence, vaaReady: true },\n });\n\n return vaaBase64;\n }\n\n /**\n * Fetch VAA by transaction hash (more reliable)\n */\n async fetchVAAByTxHash(\n txHash: string,\n onProgress?: CrossChainProgressCallback\n ): Promise<string> {\n onProgress?.({\n status: 'waiting_guardians',\n step: 4,\n totalSteps: 6,\n message: 'Waiting for Wormhole guardians to sign...',\n details: { txHash },\n });\n\n const vaaBase64 = await fetchVAAByTxHash(txHash, {\n testnet: this.config.testnet,\n maxRetries: Math.ceil(this.config.vaaTimeoutMs / this.config.vaaPollingIntervalMs),\n retryDelayMs: this.config.vaaPollingIntervalMs,\n onRetry: (attempt, max) => {\n onProgress?.({\n status: 'waiting_guardians',\n step: 4,\n totalSteps: 6,\n message: `Waiting for guardians (attempt ${attempt}/${max})...`,\n details: { txHash },\n });\n },\n });\n\n onProgress?.({\n status: 'vaa_ready',\n step: 5,\n totalSteps: 6,\n message: 'VAA signed and ready!',\n details: { txHash, vaaReady: true },\n });\n\n return vaaBase64;\n }\n\n /**\n * Wait for guardians to sign a message with progress tracking\n */\n async waitForGuardians(\n emitterChain: number,\n emitterAddress: string,\n sequence: bigint,\n onProgress?: CrossChainProgressCallback\n ): Promise<VAA> {\n const requiredSignatures = this.config.testnet\n ? GUARDIAN_CONFIG.TESTNET_QUORUM\n : GUARDIAN_CONFIG.MAINNET_QUORUM;\n\n return await waitForGuardianSignatures(\n emitterChain,\n emitterAddress,\n sequence,\n {\n testnet: this.config.testnet,\n requiredSignatures,\n maxWaitMs: this.config.vaaTimeoutMs,\n checkIntervalMs: this.config.vaaPollingIntervalMs,\n onProgress: (current, required) => {\n onProgress?.({\n status: 'waiting_guardians',\n step: 4,\n totalSteps: 6,\n message: `Collecting signatures (${current}/${required})...`,\n details: {\n sequence,\n guardianSignatures: current,\n requiredSignatures: required,\n },\n });\n },\n }\n );\n }\n\n /**\n * Parse a VAA and extract Veridex payload\n */\n parseVAA(vaaBase64: string): { vaa: VAA; payload: VeridexPayload } {\n const vaa = parseVAA(vaaBase64);\n const payload = parseVeridexPayload(vaa.payload);\n return { vaa, payload };\n }\n\n /**\n * Encode VAA for on-chain submission\n */\n encodeVAAForSubmission(vaaBase64: string): string {\n return encodeVAAToBytes(vaaBase64);\n }\n\n // ========================================================================\n // Transfer Lifecycle\n // ========================================================================\n\n /**\n * Track a cross-chain transfer\n */\n trackTransfer(\n sourceTxHash: string,\n sourceChain: number,\n destinationChain: number,\n sequence: bigint,\n emitterAddress: string\n ): CrossChainResult {\n const result: CrossChainResult = {\n sourceTxHash,\n sequence,\n emitterAddress,\n sourceChain,\n destinationChain,\n duration: 0,\n status: 'waiting_guardians',\n };\n\n this.pendingTransfers.set(sourceTxHash, result);\n return result;\n }\n\n /**\n * Get pending transfer by source tx hash\n */\n getPendingTransfer(sourceTxHash: string): CrossChainResult | undefined {\n return this.pendingTransfers.get(sourceTxHash);\n }\n\n /**\n * Get all pending transfers\n */\n getAllPendingTransfers(): CrossChainResult[] {\n return Array.from(this.pendingTransfers.values()).filter(\n t => t.status !== 'completed' && t.status !== 'failed'\n );\n }\n\n /**\n * Update transfer status\n */\n updateTransfer(\n sourceTxHash: string,\n updates: Partial<CrossChainResult>\n ): CrossChainResult | undefined {\n const transfer = this.pendingTransfers.get(sourceTxHash);\n if (!transfer) return undefined;\n\n Object.assign(transfer, updates);\n return transfer;\n }\n\n /**\n * Complete transfer with VAA\n */\n completeTransfer(\n sourceTxHash: string,\n vaa: string,\n destinationTxHash?: string\n ): CrossChainResult | undefined {\n const transfer = this.pendingTransfers.get(sourceTxHash);\n if (!transfer) return undefined;\n\n transfer.vaa = vaa;\n transfer.parsedVaa = parseVAA(vaa);\n transfer.destinationTxHash = destinationTxHash;\n transfer.status = 'completed';\n\n return transfer;\n }\n\n /**\n * Mark transfer as failed\n */\n failTransfer(sourceTxHash: string, error: string): CrossChainResult | undefined {\n const transfer = this.pendingTransfers.get(sourceTxHash);\n if (!transfer) return undefined;\n\n transfer.status = 'failed';\n transfer.error = error;\n\n return transfer;\n }\n\n /**\n * Clear completed/failed transfers\n */\n clearFinishedTransfers(): void {\n for (const [hash, transfer] of this.pendingTransfers.entries()) {\n if (transfer.status === 'completed' || transfer.status === 'failed') {\n this.pendingTransfers.delete(hash);\n }\n }\n }\n\n // ========================================================================\n // Utilities\n // ========================================================================\n\n /**\n * Extract sequence from transaction receipt\n */\n async getSequenceFromTx(\n provider: ethers.Provider,\n txHash: string,\n wormholeCoreBridge: string\n ): Promise<bigint> {\n return await getSequenceFromTxReceipt(provider, txHash, wormholeCoreBridge);\n }\n\n /**\n * Normalize address to emitter format\n */\n normalizeAddress(address: string): string {\n return normalizeEmitterAddress(address);\n }\n\n /**\n * Get explorer URL for a cross-chain transfer\n */\n getExplorerUrl(\n txHash: string,\n _chain: 'source' | 'destination',\n explorerBaseUrl: string\n ): string {\n return `${explorerBaseUrl}/tx/${txHash}`;\n }\n\n /**\n * Get Wormholescan URL for VAA\n */\n getWormholeExplorerUrl(\n emitterChain: number,\n emitterAddress: string,\n sequence: bigint\n ): string {\n const base = this.config.testnet\n ? 'https://wormholescan.io/#/tx'\n : 'https://wormholescan.io/#/tx';\n \n const normalizedEmitter = normalizeEmitterAddress(emitterAddress);\n return `${base}/${emitterChain}/${normalizedEmitter}/${sequence.toString()}`;\n }\n\n /**\n * Format wei to human-readable string\n */\n private formatWei(wei: bigint): string {\n const eth = Number(wei) / 1e18;\n if (eth < 0.0001) {\n return `${(Number(wei) / 1e9).toFixed(4)} gwei`;\n }\n return `${eth.toFixed(6)} ETH`;\n }\n}\n\n// ============================================================================\n// Export singleton for convenience\n// ============================================================================\n\nexport const crossChainManager = new CrossChainManager();\n","/**\n * Veridex Protocol SDK - Relayer Client\n * \n * Client for interacting with the Veridex relayer service.\n * The relayer automatically submits VAAs to destination chains.\n * \n * Features:\n * - Submit VAA for relay\n * - Check relay status\n * - Get supported routes\n * - Fee estimation\n */\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Relay request status\n */\nexport type RelayStatus =\n | 'pending'\n | 'processing'\n | 'submitted'\n | 'confirmed'\n | 'failed';\n\n/**\n * Relay request result\n */\nexport interface RelayRequest {\n /** Unique relay request ID */\n id: string;\n /** VAA sequence number */\n sequence: bigint;\n /** Source chain Wormhole ID */\n sourceChain: number;\n /** Destination chain Wormhole ID */\n destinationChain: number;\n /** Relay status */\n status: RelayStatus;\n /** Source transaction hash */\n sourceTxHash: string;\n /** Destination transaction hash (when completed) */\n destinationTxHash?: string;\n /** Timestamp when request was created */\n createdAt: number;\n /** Timestamp when request was last updated */\n updatedAt: number;\n /** Error message if failed */\n error?: string;\n /** Gas used on destination chain */\n gasUsed?: bigint;\n /** Fee paid */\n feePaid?: bigint;\n}\n\n/**\n * Supported route information\n */\nexport interface RelayRoute {\n /** Source chain Wormhole ID */\n sourceChain: number;\n /** Destination chain Wormhole ID */\n destinationChain: number;\n /** Whether the route is active */\n active: boolean;\n /** Estimated relay time in seconds */\n estimatedTimeSeconds: number;\n /** Base fee in destination chain native token */\n baseFee: bigint;\n /** Fee per gas unit */\n gasPrice: bigint;\n /** Maximum gas limit */\n maxGas: bigint;\n}\n\n/**\n * Relayer service info\n */\nexport interface RelayerInfo {\n /** Relayer name/identifier */\n name: string;\n /** Relayer version */\n version: string;\n /** Supported chains */\n supportedChains: number[];\n /** Available routes */\n routes: RelayRoute[];\n /** Whether the relayer is online */\n online: boolean;\n /** Current queue depth */\n queueDepth: number;\n}\n\n/**\n * Request body for submitting a signed action to the relayer (gasless)\n * Uses full WebAuthn data for authenticateAndDispatch\n */\nexport interface SubmitSignedActionRequest {\n /** WebAuthn authenticatorData (hex) */\n authenticatorData: string;\n /** WebAuthn clientDataJSON (raw string) */\n clientDataJSON: string;\n /** Index of \"challenge\":\"...\" in clientDataJSON */\n challengeIndex: number;\n /** Index of \"type\":\"...\" in clientDataJSON */\n typeIndex: number;\n /** P-256 signature r component (hex) */\n r: string;\n /** P-256 signature s component (hex) */\n s: string;\n /** P-256 public key X coordinate (hex) */\n publicKeyX: string;\n /** P-256 public key Y coordinate (hex) */\n publicKeyY: string;\n /** Target chain Wormhole ID */\n targetChain: number;\n /** Action payload (hex) */\n actionPayload: string;\n /** User nonce */\n nonce: number;\n}\n\n/**\n * Response from submitting a signed action\n */\nexport interface SubmitActionResult {\n /** Whether the submission was successful */\n success: boolean;\n /** Transaction hash on Hub chain */\n txHash?: string;\n /** Wormhole sequence number */\n sequence?: string;\n /** Error message if failed */\n error?: string;\n /** Human-readable message */\n message?: string;\n}\n\n/**\n * Query submission request (Issue #11/#12)\n * For optimistic execution via Wormhole Query proofs (~5-7s vs ~120s)\n */\nexport interface SubmitQueryRequest {\n /** Target spoke chain Wormhole ID */\n targetChain: number;\n /** User's key hash */\n userKeyHash: string;\n /** Serialized transaction for spoke chain */\n serializedTx: string; // hex\n /** Query proof with Guardian signatures */\n queryProof: {\n /** Raw query response bytes */\n queryResponse: string; // hex\n /** Guardian signatures */\n signatures: string; // hex\n };\n /** Whether to fallback to VAA if Query fails */\n fallbackToVaa?: boolean;\n /** Optional metadata */\n metadata?: {\n /** User's preferred execution path */\n preferredPath?: 'query' | 'vaa';\n /** Transaction value in USD (for routing decisions) */\n estimatedValueUSD?: number;\n };\n}\n\n/**\n * Query submission result (Issue #11/#12)\n */\nexport interface SubmitQueryResult {\n /** Whether submission succeeded */\n success: boolean;\n /** Transaction hash on spoke chain */\n txHash?: string;\n /** Execution path used */\n path: 'query' | 'vaa';\n /** Latency in milliseconds */\n latencyMs?: number;\n /** Error message if failed */\n error?: string;\n /** Whether fallback to VAA occurred */\n fellBack?: boolean;\n}\n\n/**\n * Fee quote for a relay\n */\nexport interface RelayFeeQuote {\n /** Source chain Wormhole ID */\n sourceChain: number;\n /** Destination chain Wormhole ID */\n destinationChain: number;\n /** Estimated fee in source chain native token */\n feeInSourceToken: bigint;\n /** Estimated fee in destination chain native token */\n feeInDestinationToken: bigint;\n /** Estimated gas on destination */\n estimatedGas: bigint;\n /** Quote expiration timestamp */\n expiresAt: number;\n /** Quote ID for submission */\n quoteId: string;\n}\n\n/**\n * Configuration for RelayerClient\n */\nexport interface RelayerClientConfig {\n /** Base URL of the relayer service */\n baseUrl: string;\n /** API key for authentication (optional) */\n apiKey?: string;\n /** Timeout for requests in ms */\n timeoutMs?: number;\n /** Max retries for failed requests */\n maxRetries?: number;\n}\n\nexport type RegisteredAppStatus = 'active' | 'suspended' | 'revoked';\nexport type RegisteredAppTrustLevel = 'verified' | 'registered' | 'pending';\n\nexport interface RegisteredAppSummary {\n id: string;\n name: string;\n origin: string;\n trustLevel: RegisteredAppTrustLevel;\n status: RegisteredAppStatus;\n requestCount: number;\n createdAt: number;\n lastUsedAt?: number;\n}\n\nexport interface RegisteredAppDetail extends RegisteredAppSummary {\n description?: string;\n apiKey?: string;\n activeSessionCount?: number;\n}\n\nexport interface RelayerAppSession {\n id: string;\n keyHash: string;\n appOrigin: string;\n sessionPublicKey: string;\n permissions: string[];\n expiresAt: number;\n createdAt: number;\n revoked: boolean;\n active: boolean;\n}\n\nexport interface CredentialMetadataRecord {\n credentialId: string;\n keyHash: string;\n displayName: string;\n platformHint: string;\n backupEligible: boolean | null;\n backupState: boolean | null;\n isRoot: boolean;\n status: 'active' | 'revoked';\n lastUsedAt: number | null;\n useCount: number;\n createdAt: number;\n updatedAt: number;\n}\n\n// ============================================================================\n// Default Configuration\n// ============================================================================\n\nconst DEFAULT_CONFIG: Required<Omit<RelayerClientConfig, 'baseUrl'>> = {\n apiKey: '',\n timeoutMs: 30_000,\n maxRetries: 3,\n};\n\n// ============================================================================\n// RelayerClient Class\n// ============================================================================\n\n/**\n * Client for the Veridex relayer service\n */\nexport class RelayerClient {\n private baseUrl: string;\n private config: Required<Omit<RelayerClientConfig, 'baseUrl'>>;\n\n constructor(config: RelayerClientConfig) {\n this.baseUrl = config.baseUrl.replace(/\\/+$/, ''); // Remove trailing slashes\n this.config = { ...DEFAULT_CONFIG, ...config };\n }\n\n // ========================================================================\n // Relay Operations\n // ========================================================================\n\n /**\n * Submit a VAA for relay to destination chain\n */\n async submitRelay(\n vaaBase64: string,\n sourceChain: number,\n destinationChain: number,\n sourceTxHash: string,\n sequence: bigint,\n feeQuoteId?: string\n ): Promise<RelayRequest> {\n void vaaBase64;\n void sourceChain;\n void destinationChain;\n void sourceTxHash;\n void sequence;\n void feeQuoteId;\n throw new Error(\n 'submitRelay() is not supported by the current Veridex relayer API. ' +\n 'Use submitSignedAction() and let the relayer observe hub events to relay automatically.'\n );\n }\n\n /**\n * Submit a signed action to the relayer for gasless execution\n * \n * This allows users to execute transfers without paying gas themselves.\n * The relayer will submit the transaction to the Hub chain and pay the gas.\n * The relayer then automatically relays the VAA to the destination spoke chain.\n * \n * @param request - The signed action request with passkey signature\n * @returns Result including Hub tx hash and Wormhole sequence\n */\n async submitSignedAction(request: SubmitSignedActionRequest): Promise<SubmitActionResult> {\n try {\n const response = await this.fetch('/api/v1/submit', {\n method: 'POST',\n body: JSON.stringify(request),\n });\n\n return {\n success: response.success,\n txHash: response.transactionHash ?? response.txHash,\n sequence: response.sequence,\n error: response.error,\n message: response.message,\n };\n } catch (err: any) {\n // Handle 400 errors gracefully - the relayer returns error details in the body\n if (err.status === 400 && err.body) {\n return {\n success: false,\n error: err.body.error ?? 'Relayer returned 400 Bad Request',\n message: err.body.message,\n };\n }\n // Re-throw other errors\n throw err;\n }\n }\n\n /**\n * Submit a Query-based transaction for optimistic execution (Issue #11/#12)\n * \n * Uses Wormhole Cross-Chain Queries (CCQ) to achieve ~5-7 second latency\n * vs ~120+ seconds for traditional VAA flow.\n * \n * Flow:\n * 1. Client fetches Hub state via queryHubState() from SDK\n * 2. Client constructs and signs transaction\n * 3. Client submits Query proof + tx to this endpoint\n * 4. Relayer validates format and submits to spoke chain\n * 5. Spoke chain verifies Guardian signatures on-chain\n * \n * @param request - Query submission with Guardian-signed proof\n * @returns Result including spoke tx hash and execution path\n */\n async submitQuery(request: SubmitQueryRequest): Promise<SubmitQueryResult> {\n try {\n const response = await this.fetch('/api/v1/submit-query', {\n method: 'POST',\n body: JSON.stringify(request),\n });\n\n return {\n success: response.success ?? false,\n txHash: response.txHash,\n path: response.path ?? 'query',\n latencyMs: response.latencyMs,\n error: response.error,\n fellBack: response.fellBack ?? false,\n };\n } catch (err: any) {\n // Handle errors gracefully\n if (err.status === 400 && err.body) {\n return {\n success: false,\n path: 'query',\n error: err.body.error ?? 'Relayer returned 400 Bad Request',\n };\n }\n throw err;\n }\n }\n\n /**\n * Get relay request status\n */\n async getRelayStatus(requestId: string): Promise<RelayRequest> {\n void requestId;\n throw new Error('getRelayStatus() is not supported by the current Veridex relayer API.');\n }\n\n /**\n * Get relay status by source transaction hash\n */\n async getRelayBySourceTx(sourceTxHash: string): Promise<RelayRequest | null> {\n void sourceTxHash;\n return null;\n }\n\n /**\n * Get relay status by sequence number\n */\n async getRelayBySequence(\n sourceChain: number,\n sequence: bigint\n ): Promise<RelayRequest | null> {\n void sourceChain;\n void sequence;\n return null;\n }\n\n /**\n * Cancel a pending relay request\n */\n async cancelRelay(requestId: string): Promise<boolean> {\n void requestId;\n return false;\n }\n\n /**\n * Poll for relay completion\n */\n async waitForRelay(\n requestId: string,\n timeoutMs: number = 120_000,\n pollingIntervalMs: number = 3_000,\n onProgress?: (status: RelayStatus) => void\n ): Promise<RelayRequest> {\n void requestId;\n void timeoutMs;\n void pollingIntervalMs;\n void onProgress;\n throw new Error('waitForRelay() is not supported by the current Veridex relayer API.');\n }\n\n // ========================================================================\n // Fee Estimation\n // ========================================================================\n\n /**\n * Get fee quote for a relay\n */\n async getFeeQuote(\n sourceChain: number,\n destinationChain: number,\n estimatedGas?: bigint\n ): Promise<RelayFeeQuote> {\n void sourceChain;\n void estimatedGas;\n\n // The relayer currently returns a simple fee breakdown; we map it into the\n // existing RelayFeeQuote shape with best-effort defaults.\n const response = await this.fetch(`/api/v1/fee?targetChain=${destinationChain}`);\n const relayerFee = BigInt(response?.fees?.relayer ?? '0');\n const total = BigInt(response?.fees?.total ?? relayerFee.toString());\n\n return {\n sourceChain: sourceChain,\n destinationChain,\n feeInSourceToken: total,\n feeInDestinationToken: relayerFee,\n estimatedGas: 0n,\n expiresAt: Date.now() + 60_000,\n quoteId: '',\n };\n }\n\n // ========================================================================\n // Service Info\n // ========================================================================\n\n /**\n * Get relayer service info\n */\n async getInfo(): Promise<RelayerInfo> {\n const response = await this.fetch('/api/v1/info');\n\n return {\n name: 'veridex-relayer',\n version: response?.relayer?.version ?? response?.version ?? 'unknown',\n supportedChains: (response?.supportedChains || []).map((c: any) => c.wormholeChainId ?? c),\n routes: [],\n online: true,\n queueDepth: 0,\n };\n }\n\n /**\n * Get supported routes\n */\n async getRoutes(): Promise<RelayRoute[]> {\n throw new Error('getRoutes() is not supported by the current Veridex relayer API.');\n }\n\n /**\n * Check if a route is supported\n */\n async isRouteSupported(\n sourceChain: number,\n destinationChain: number\n ): Promise<boolean> {\n void sourceChain;\n void destinationChain;\n return false;\n }\n\n /**\n * Check relayer health\n */\n async healthCheck(): Promise<boolean> {\n try {\n const response = await this.fetch('/health');\n return response.status === 'healthy' || response.status === 'degraded' || response.healthy === true;\n } catch {\n return false;\n }\n }\n\n // ========================================================================\n // Account And Control Plane\n // ========================================================================\n\n async listApps(): Promise<RegisteredAppSummary[]> {\n const response = await this.fetch('/api/v1/apps');\n return (response.apps ?? []) as RegisteredAppSummary[];\n }\n\n async getApp(appId: string): Promise<RegisteredAppDetail> {\n const response = await this.fetch(`/api/v1/apps/${encodeURIComponent(appId)}`);\n return response.app as RegisteredAppDetail;\n }\n\n async updateAppStatus(appId: string, status: RegisteredAppStatus): Promise<void> {\n await this.fetch(`/api/v1/apps/${encodeURIComponent(appId)}/status`, {\n method: 'PUT',\n body: JSON.stringify({ status }),\n });\n }\n\n async updateAppTrustLevel(appId: string, trustLevel: RegisteredAppTrustLevel): Promise<void> {\n await this.fetch(`/api/v1/apps/${encodeURIComponent(appId)}/trust-level`, {\n method: 'PUT',\n body: JSON.stringify({ trustLevel }),\n });\n }\n\n async listAppSessions(appId: string, options?: { includeRevoked?: boolean }): Promise<RelayerAppSession[]> {\n const query = options?.includeRevoked ? '?includeRevoked=true' : '';\n const response = await this.fetch(`/api/v1/apps/${encodeURIComponent(appId)}/sessions${query}`);\n return (response.sessions ?? []) as RelayerAppSession[];\n }\n\n async revokeAppSessions(appId: string, sessionId?: string): Promise<number> {\n const response = await this.fetch(`/api/v1/apps/${encodeURIComponent(appId)}/sessions/revoke`, {\n method: 'POST',\n body: JSON.stringify(sessionId ? { sessionId } : {}),\n });\n return Number(response.revokedCount ?? 0);\n }\n\n async listCredentialMetadata(keyHash: string): Promise<CredentialMetadataRecord[]> {\n const response = await this.fetch(`/api/v1/credential/metadata?keyHash=${encodeURIComponent(keyHash)}`);\n return (response.credentials ?? []) as CredentialMetadataRecord[];\n }\n\n // ========================================================================\n // Pending Relays\n // ========================================================================\n\n /**\n * Get all pending relay requests for a user\n */\n async getPendingRelays(userKeyHash: string): Promise<RelayRequest[]> {\n void userKeyHash;\n return [];\n }\n\n /**\n * Get relay history for a user\n */\n async getRelayHistory(\n userKeyHash: string,\n limit: number = 50,\n offset: number = 0\n ): Promise<RelayRequest[]> {\n void userKeyHash;\n void limit;\n void offset;\n return [];\n }\n\n // ========================================================================\n // Internal Helpers\n // ========================================================================\n\n /**\n * SDK version for telemetry\n */\n private static readonly SDK_VERSION = '1.0.0-beta.1';\n\n /**\n * Make an HTTP request to the relayer\n */\n private async fetch(\n path: string,\n options: RequestInit = {}\n ): Promise<any> {\n const headers: HeadersInit = {\n 'Content-Type': 'application/json',\n 'User-Agent': `@veridex/sdk/${RelayerClient.SDK_VERSION}`,\n ...(options.headers || {}),\n };\n\n if (this.config.apiKey) {\n (headers as Record<string, string>)['X-API-Key'] = this.config.apiKey;\n }\n\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), this.config.timeoutMs);\n\n let lastError: Error | null = null;\n\n for (let attempt = 0; attempt <= this.config.maxRetries; attempt++) {\n try {\n const response = await fetch(`${this.baseUrl}${path}`, {\n ...options,\n headers,\n signal: controller.signal,\n });\n\n clearTimeout(timeout);\n\n if (!response.ok) {\n const error: any = new Error(\n `Relayer request failed: ${response.status} ${response.statusText}`\n );\n error.status = response.status;\n try {\n error.body = await response.json();\n } catch {\n // Ignore JSON parse errors\n }\n throw error;\n }\n\n return await response.json();\n } catch (error: any) {\n lastError = error;\n\n // Don't retry on client errors (4xx)\n if (error.status && error.status >= 400 && error.status < 500) {\n throw error;\n }\n\n // Don't retry on abort\n if (error.name === 'AbortError') {\n throw new Error('Request timeout');\n }\n\n // Wait before retry\n if (attempt < this.config.maxRetries) {\n await this.sleep(1000 * (attempt + 1));\n }\n }\n }\n\n throw lastError || new Error('Request failed after all retries');\n }\n\n /**\n * Sleep helper\n */\n private sleep(ms: number): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, ms));\n }\n}\n\n// ============================================================================\n// Factory function\n// ============================================================================\n\n/**\n * Create a RelayerClient instance\n */\nexport function createRelayerClient(config: RelayerClientConfig): RelayerClient {\n return new RelayerClient(config);\n}\n","/**\n * Veridex Protocol SDK - Chain Detector\n *\n * Phase 4: Multi-chain client support helper.\n *\n * Provides:\n * - Chain config lookup (testnet/mainnet)\n * - Auto-configuration for non-EVM ChainClient instances\n */\n\nimport type { ChainClient, ChainConfig, PasskeyCredential, ChainAddress } from './types.js';\nimport { TESTNET_CHAINS, MAINNET_CHAINS } from '../constants.js';\nimport { WalletManager } from './WalletManager.js';\nimport { SolanaClient } from '../chains/solana/SolanaClient.js';\nimport { AptosClient } from '../chains/aptos/AptosClient.js';\nimport { SuiClient } from '../chains/sui/SuiClient.js';\nimport { StarknetClient } from '../chains/starknet/StarknetClient.js';\n\nexport interface ChainDetectorConfig {\n testnet?: boolean;\n rpcUrls?: Record<number, string>;\n}\n\nexport interface NativeBalanceCapable {\n getNativeBalance(address: string): Promise<bigint>;\n}\n\nconst NON_EVM_NATIVE_META: Record<number, { symbol: string; name: string; decimals: number }> = {\n 1: { symbol: 'SOL', name: 'Solana', decimals: 9 },\n 21: { symbol: 'SUI', name: 'Sui', decimals: 9 },\n 22: { symbol: 'APT', name: 'Aptos', decimals: 8 },\n};\n\nexport class ChainDetector {\n private readonly testnet: boolean;\n private readonly rpcUrls: Record<number, string>;\n private readonly walletManager: WalletManager;\n\n constructor(config: ChainDetectorConfig = {}) {\n this.testnet = config.testnet ?? true;\n this.rpcUrls = config.rpcUrls ?? {};\n this.walletManager = new WalletManager({ cacheAddresses: true, persistToStorage: false });\n }\n\n getChainConfig(wormholeChainId: number): ChainConfig | undefined {\n const chains = this.testnet ? TESTNET_CHAINS : MAINNET_CHAINS;\n return Object.values(chains).find(c => c.wormholeChainId === wormholeChainId);\n }\n\n /**\n * Create a chain client for non-EVM chains using repo constants.\n * For EVM, callers should instantiate EVMClient directly (Hub-driven).\n */\n createClient(wormholeChainId: number): ChainClient {\n const chain = this.getChainConfig(wormholeChainId);\n if (!chain) {\n throw new Error(`Unknown chain (wormholeChainId=${wormholeChainId})`);\n }\n\n const rpcUrl = this.rpcUrls[wormholeChainId] ?? chain.rpcUrl;\n\n if (chain.isEvm) {\n throw new Error(\n `EVM chain auto-detection is not supported here (wormholeChainId=${wormholeChainId}). ` +\n 'Instantiate EVMClient with hubContractAddress/vaultFactory/vaultImplementation explicitly.'\n );\n }\n\n switch (wormholeChainId) {\n case 1: {\n const programId = chain.contracts.hub;\n if (!programId || !chain.contracts.tokenBridge) {\n throw new Error('Solana config missing programId/tokenBridge in constants');\n }\n return new SolanaClient({\n wormholeChainId,\n rpcUrl,\n programId,\n wormholeCoreBridge: chain.contracts.wormholeCoreBridge,\n tokenBridge: chain.contracts.tokenBridge,\n network: this.testnet ? 'devnet' : 'mainnet',\n });\n }\n case 22: {\n const moduleAddress = chain.contracts.hub;\n if (!moduleAddress || !chain.contracts.tokenBridge) {\n throw new Error('Aptos config missing moduleAddress/tokenBridge in constants');\n }\n return new AptosClient({\n wormholeChainId,\n rpcUrl,\n moduleAddress,\n wormholeCoreBridge: chain.contracts.wormholeCoreBridge,\n tokenBridge: chain.contracts.tokenBridge,\n network: this.testnet ? 'testnet' : 'mainnet',\n });\n }\n case 21: {\n const packageId = chain.contracts.hub;\n return new SuiClient({\n wormholeChainId,\n rpcUrl,\n packageId: packageId ?? '',\n wormholeCoreBridge: chain.contracts.wormholeCoreBridge,\n tokenBridge: chain.contracts.tokenBridge,\n network: this.testnet ? 'testnet' : 'mainnet',\n });\n }\n case 50001: {\n // Starknet Sepolia with custom bridge\n const spokeAddress = chain.contracts.hub;\n const bridgeAddress = chain.contracts.wormholeCoreBridge;\n if (!spokeAddress || !bridgeAddress) {\n throw new Error('Starknet config missing spoke/bridge addresses in constants');\n }\n return new StarknetClient({\n wormholeChainId,\n rpcUrl,\n spokeContractAddress: spokeAddress,\n bridgeContractAddress: bridgeAddress,\n network: this.testnet ? 'sepolia' : 'mainnet',\n });\n }\n default:\n throw new Error(\n `Unsupported non-EVM chain (wormholeChainId=${wormholeChainId}). ` +\n 'Add configuration in ChainDetector.createClient().'\n );\n }\n }\n\n /**\n * Derive a best-effort vault address for a chain from the passkey credential.\n *\n * - EVM chains: requires vaultFactory/vaultImplementation in constants.\n * - Non-EVM chains: uses WalletManager chain-specific derivation.\n */\n deriveVaultAddress(credential: PasskeyCredential, wormholeChainId: number): ChainAddress | null {\n const chain = this.getChainConfig(wormholeChainId);\n if (!chain) {\n return null;\n }\n\n if (chain.isEvm) {\n const factory = chain.contracts.vaultFactory;\n const implementation = chain.contracts.vaultImplementation;\n if (!factory || !implementation) {\n return null;\n }\n\n const address = this.walletManager.computeVaultAddress(credential.keyHash, factory, implementation);\n return {\n wormholeChainId,\n chainName: chain.name,\n address,\n isEvm: true,\n deployed: false,\n derivationType: 'create2',\n };\n }\n\n // Non-EVM: WalletManager derives using keyHash conventions.\n return {\n wormholeChainId,\n chainName: chain.name,\n address: wormholeChainId === 21 \n ? this.normalizeSuiAddress(credential.keyHash)\n : wormholeChainId === 50001\n ? credential.keyHash // Starknet uses keyHash directly (felt252)\n : credential.keyHash,\n isEvm: false,\n deployed: false,\n derivationType: wormholeChainId === 1 \n ? 'pda' \n : wormholeChainId === 22 \n ? 'resource_account' \n : wormholeChainId === 50001\n ? 'keyHash'\n : 'object',\n };\n }\n\n getNonEvmNativeTokenMeta(wormholeChainId: number): { symbol: string; name: string; decimals: number } | null {\n return NON_EVM_NATIVE_META[wormholeChainId] ?? null;\n }\n\n private normalizeSuiAddress(value: string): string {\n const clean = value.replace(/^0x/, '').padStart(64, '0');\n return '0x' + clean;\n }\n}\n\nexport function createChainDetector(config: ChainDetectorConfig = {}): ChainDetector {\n return new ChainDetector(config);\n}\n","/**\n * Veridex Protocol SDK - Transaction Parser\n * \n * Parses transaction payloads into human-readable summaries (Issue #26)\n * \n * Security-critical: This module MUST accurately represent what users are signing.\n * Any mismatch between displayed information and actual transaction is a security vulnerability.\n */\n\nimport { ethers } from 'ethers';\nimport {\n ACTION_TRANSFER,\n ACTION_EXECUTE,\n ACTION_CONFIG,\n ACTION_BRIDGE,\n} from '../constants.js';\nimport {\n decodeTransferAction,\n decodeBridgeAction,\n} from '../payload.js';\nimport type { PreparedTransfer, PreparedBridge } from './types.js';\nimport type { BridgeParams, TransferParams } from '../types.js';\nimport type {\n TransactionSummary,\n TransactionParserConfig,\n TokenDisplay,\n RecipientDisplay,\n ChainDisplay,\n RiskWarning,\n TransferDetails,\n BridgeDetails,\n ExecuteDetails,\n ConfigDetails,\n TokenInfo,\n} from './TransactionSummary.types.js';\nimport { getChainDisplay, getConfigTypeName } from './TransactionSummary.types.js';\n\n// ============================================================================\n// Default Token Registry\n// ============================================================================\n\nconst DEFAULT_TOKENS: Map<string, TokenInfo> = new Map([\n // Native token placeholder\n ['0x0000000000000000000000000000000000000000', {\n symbol: 'ETH',\n name: 'Ether',\n decimals: 18,\n verified: true,\n }],\n ['native', {\n symbol: 'ETH',\n name: 'Ether',\n decimals: 18,\n verified: true,\n }],\n // Common stablecoins (Base Sepolia)\n ['0x036cbd53842c5426634e7929541ec2318f3dcf7e', {\n symbol: 'USDC',\n name: 'USD Coin',\n decimals: 6,\n verified: true,\n }],\n]);\n\n// ============================================================================\n// Utility Functions\n// ============================================================================\n\n/**\n * Format a bigint amount to human-readable string\n */\nexport function formatAmount(amount: bigint, decimals: number): string {\n if (amount === 0n) return '0';\n \n const divisor = 10n ** BigInt(decimals);\n const whole = amount / divisor;\n const remainder = amount % divisor;\n \n if (remainder === 0n) {\n return whole.toString();\n }\n \n // Format with decimal places\n const remainderStr = remainder.toString().padStart(decimals, '0');\n // Trim trailing zeros\n const trimmed = remainderStr.replace(/0+$/, '');\n \n return `${whole}.${trimmed}`;\n}\n\n/**\n * Truncate an address for display\n */\nexport function truncateAddress(address: string, startChars = 6, endChars = 4): string {\n if (address.length <= startChars + endChars + 3) {\n return address;\n }\n return `${address.slice(0, startChars)}...${address.slice(-endChars)}`;\n}\n\n/**\n * Format time remaining until expiration\n */\nexport function formatTimeRemaining(expiresAt: number): string {\n const now = Date.now();\n const remaining = expiresAt - now;\n \n if (remaining <= 0) return 'Expired';\n \n const seconds = Math.floor(remaining / 1000);\n if (seconds < 60) return `${seconds} seconds`;\n \n const minutes = Math.floor(seconds / 60);\n if (minutes < 60) return `${minutes} minute${minutes === 1 ? '' : 's'}`;\n \n const hours = Math.floor(minutes / 60);\n return `${hours} hour${hours === 1 ? '' : 's'}`;\n}\n\n/**\n * Check if address is the zero address (native token)\n */\nexport function isNativeToken(address: string): boolean {\n return address === '0x0000000000000000000000000000000000000000' ||\n address === 'native' ||\n address === ethers.ZeroAddress;\n}\n\n// ============================================================================\n// Transaction Parser Class\n// ============================================================================\n\n/**\n * Parses prepared transactions into human-readable summaries\n */\nexport class TransactionParser {\n private config: TransactionParserConfig;\n private tokenRegistry: Map<string, TokenInfo>;\n\n constructor(config: TransactionParserConfig = {}) {\n this.config = config;\n this.tokenRegistry = config.knownTokens ?? new Map(DEFAULT_TOKENS);\n }\n\n /**\n * Main entry point: parse a prepared transfer into a human-readable summary\n * \n * This method determines the action type from the payload and delegates\n * to the appropriate specialized parser.\n * \n * @param prepared - PreparedTransfer or PreparedBridge object from SDK\n * @param vaultAddress - Optional vault address (uses default if not provided)\n * @param vaultChainId - Optional vault chain ID (uses config default if not provided)\n */\n async parse(\n prepared: PreparedTransfer | PreparedBridge,\n vaultAddress?: string,\n vaultChainId?: number\n ): Promise<TransactionSummary> {\n const effectiveVaultAddress = vaultAddress ?? '0x0000000000000000000000000000000000000000';\n \n // Determine chain ID based on type - PreparedBridge uses destinationChain, PreparedTransfer uses params.targetChain\n const isBridgePrepared = 'destinationChain' in prepared;\n const defaultChainId = isBridgePrepared \n ? (prepared as PreparedBridge).destinationChain \n : (prepared as PreparedTransfer).params.targetChain;\n const effectiveChainId = vaultChainId ?? this.config.defaultChainId ?? defaultChainId;\n \n // Normalize to PreparedTransfer with defaults for missing fields\n // For PreparedBridge, we construct params from the bridge-specific fields\n const normalizedParams: TransferParams = isBridgePrepared \n ? {\n targetChain: (prepared as PreparedBridge).destinationChain,\n token: (prepared as PreparedBridge).params.token,\n recipient: (prepared as PreparedBridge).params.recipient,\n amount: (prepared as PreparedBridge).params.amount,\n }\n : (prepared as PreparedTransfer).params;\n\n const normalized: PreparedTransfer = {\n params: normalizedParams,\n actionPayload: prepared.actionPayload,\n nonce: prepared.nonce,\n challenge: prepared.challenge,\n estimatedGas: (prepared as PreparedTransfer).estimatedGas ?? 0n,\n gasPrice: (prepared as PreparedTransfer).gasPrice ?? 0n,\n messageFee: (prepared as PreparedTransfer).messageFee ?? (isBridgePrepared ? (prepared as PreparedBridge).fees?.relayerFee ?? 0n : 0n),\n totalCost: (prepared as PreparedTransfer).totalCost ?? 0n,\n formattedCost: (prepared as PreparedTransfer).formattedCost ?? '0',\n preparedAt: prepared.preparedAt ?? Date.now(),\n expiresAt: prepared.expiresAt,\n };\n\n // Determine action type from payload\n const actionType = this.detectActionType(normalized.actionPayload);\n\n switch (actionType) {\n case ACTION_TRANSFER:\n return this.parseTransfer(normalized, effectiveVaultAddress, effectiveChainId);\n case ACTION_BRIDGE:\n return this.parseBridgeFromPrepared(normalized, effectiveVaultAddress, effectiveChainId);\n case ACTION_EXECUTE:\n return this.parseExecuteFromPayload(\n normalized.actionPayload,\n normalized.nonce,\n normalized.challenge,\n effectiveVaultAddress,\n effectiveChainId,\n normalized.expiresAt,\n normalized.formattedCost\n );\n case ACTION_CONFIG:\n return this.parseConfigFromPayload(\n normalized.actionPayload,\n normalized.nonce,\n normalized.challenge,\n effectiveVaultAddress,\n effectiveChainId,\n normalized.expiresAt,\n normalized.formattedCost\n );\n default:\n // Fallback for unknown action types\n return this.createUnknownActionSummary(normalized, effectiveVaultAddress, effectiveChainId);\n }\n }\n\n /**\n * Detect action type from payload\n */\n private detectActionType(payload: string): number {\n if (!payload || payload.length < 4) return 0;\n // Action type is typically first byte after 0x\n const typeHex = payload.slice(2, 4);\n return parseInt(typeHex, 16);\n }\n\n /**\n * Parse bridge action from PreparedTransfer\n */\n private async parseBridgeFromPrepared(\n prepared: PreparedTransfer,\n vaultAddress: string,\n vaultChainId: number\n ): Promise<TransactionSummary> {\n const { params, actionPayload, nonce, challenge, expiresAt, formattedCost } = prepared;\n const decoded = decodeBridgeAction(actionPayload);\n\n const token = await this.resolveToken(decoded.token, decoded.amount);\n const sourceChain = getChainDisplay(vaultChainId);\n const destinationChain = getChainDisplay(params.targetChain);\n const recipient = await this.resolveRecipient(decoded.recipient);\n\n const details: BridgeDetails = {\n token,\n sourceChain,\n destinationChain,\n recipient,\n estimatedTime: this.estimateBridgeTime(sourceChain.id, destinationChain.id),\n };\n\n const warnings = await this.assessBridgeRisks({\n sourceChain: vaultChainId,\n destinationChain: params.targetChain,\n token: decoded.token,\n recipient: decoded.recipient,\n amount: decoded.amount,\n }, token, sourceChain, destinationChain);\n\n return {\n action: 'bridge',\n title: `Bridge ${token.symbol}`,\n description: `Bridge ${token.amount} ${token.symbol} from ${sourceChain.name} to ${destinationChain.name}`,\n details,\n vault: {\n address: vaultAddress,\n truncated: truncateAddress(vaultAddress),\n chain: sourceChain,\n },\n fee: {\n gas: formattedCost,\n paidByRelayer: false,\n total: formattedCost,\n },\n warnings,\n raw: {\n actionType: ACTION_BRIDGE,\n actionPayload,\n nonce,\n challenge: ethers.hexlify(challenge),\n chainId: params.targetChain,\n expiresAt,\n expiresIn: formatTimeRemaining(expiresAt),\n },\n generatedAt: Date.now(),\n };\n }\n\n /**\n * Parse execute action from payload\n */\n private async parseExecuteFromPayload(\n actionPayload: string,\n nonce: bigint,\n challenge: Uint8Array,\n vaultAddress: string,\n chainId: number,\n expiresAt: number,\n formattedCost: string\n ): Promise<TransactionSummary> {\n // Decode execute action - basic structure\n const target = '0x' + actionPayload.slice(4, 44);\n const value = BigInt('0x' + actionPayload.slice(44, 108));\n const calldata = '0x' + actionPayload.slice(108);\n\n const targetDisplay = await this.resolveRecipient(target);\n const chain = getChainDisplay(chainId);\n const functionInfo = this.decodeFunctionCall(calldata);\n\n const details: ExecuteDetails = {\n target: targetDisplay,\n value: await this.resolveToken(ethers.ZeroAddress, value),\n chain,\n functionName: functionInfo?.name,\n decodedArgs: functionInfo?.args,\n calldata,\n };\n\n const warnings = await this.assessExecuteRisks(target, value, calldata, targetDisplay);\n\n return {\n action: 'execute',\n title: 'Contract Call',\n description: `Call ${functionInfo?.name ?? 'function'} on ${targetDisplay.ens ?? targetDisplay.truncated}`,\n details,\n vault: {\n address: vaultAddress,\n truncated: truncateAddress(vaultAddress),\n chain,\n },\n fee: {\n gas: formattedCost,\n paidByRelayer: false,\n total: formattedCost,\n },\n warnings,\n raw: {\n actionType: ACTION_EXECUTE,\n actionPayload,\n nonce,\n challenge: ethers.hexlify(challenge),\n chainId,\n expiresAt,\n expiresIn: formatTimeRemaining(expiresAt),\n },\n generatedAt: Date.now(),\n };\n }\n\n /**\n * Parse config action from payload\n */\n private async parseConfigFromPayload(\n actionPayload: string,\n nonce: bigint,\n challenge: Uint8Array,\n vaultAddress: string,\n chainId: number,\n expiresAt: number,\n formattedCost: string\n ): Promise<TransactionSummary> {\n // Decode config action - basic structure\n const configType = parseInt(actionPayload.slice(2, 4), 16);\n const configData = '0x' + actionPayload.slice(4);\n\n const chain = getChainDisplay(chainId);\n const configTypeName = getConfigTypeName(configType);\n\n const details: ConfigDetails = {\n configType,\n configTypeName,\n description: this.describeConfigChange(configType, configData),\n changes: this.parseConfigChanges(configType, configData),\n };\n\n const warnings: RiskWarning[] = [{\n level: 'high',\n type: 'config_change',\n message: 'This transaction will modify your vault settings',\n details: `Changing: ${configTypeName}`,\n }];\n\n return {\n action: 'config',\n title: 'Configuration Change',\n description: `Update vault configuration: ${configTypeName}`,\n details,\n vault: {\n address: vaultAddress,\n truncated: truncateAddress(vaultAddress),\n chain,\n },\n fee: {\n gas: formattedCost,\n paidByRelayer: false,\n total: formattedCost,\n },\n warnings,\n raw: {\n actionType: ACTION_CONFIG,\n actionPayload,\n nonce,\n challenge: ethers.hexlify(challenge),\n chainId,\n expiresAt,\n expiresIn: formatTimeRemaining(expiresAt),\n },\n generatedAt: Date.now(),\n };\n }\n\n /**\n * Create a fallback summary for unknown action types\n */\n private createUnknownActionSummary(\n prepared: PreparedTransfer,\n vaultAddress: string,\n chainId: number\n ): TransactionSummary {\n const chain = getChainDisplay(chainId);\n\n return {\n action: 'execute',\n title: 'Unknown Action',\n description: 'This transaction contains an unrecognized action type',\n details: null,\n vault: {\n address: vaultAddress,\n truncated: truncateAddress(vaultAddress),\n chain,\n },\n fee: {\n gas: prepared.formattedCost,\n paidByRelayer: false,\n total: prepared.formattedCost,\n },\n warnings: [{\n level: 'critical',\n type: 'unknown_token',\n message: 'Unknown action type - proceed with extreme caution',\n details: `Action type: ${this.detectActionType(prepared.actionPayload)}`,\n }],\n raw: {\n actionType: this.detectActionType(prepared.actionPayload),\n actionPayload: prepared.actionPayload,\n nonce: prepared.nonce,\n challenge: ethers.hexlify(prepared.challenge),\n chainId,\n expiresAt: prepared.expiresAt,\n expiresIn: formatTimeRemaining(prepared.expiresAt),\n },\n generatedAt: Date.now(),\n };\n }\n\n /**\n * Parse a prepared transfer into a human-readable summary\n */\n async parseTransfer(\n prepared: PreparedTransfer,\n vaultAddress: string,\n vaultChainId: number\n ): Promise<TransactionSummary> {\n const { params, actionPayload, nonce, challenge, expiresAt } = prepared;\n const decoded = decodeTransferAction(actionPayload);\n\n const token = await this.resolveToken(decoded.token, decoded.amount);\n const recipient = await this.resolveRecipient(decoded.recipient);\n const chain = getChainDisplay(params.targetChain);\n\n const details: TransferDetails = {\n token,\n recipient,\n chain,\n };\n\n const warnings = await this.assessTransferRisks(params, token, recipient);\n\n return {\n action: 'transfer',\n title: `Send ${token.symbol}`,\n description: `Send ${token.amount} ${token.symbol} to ${recipient.ens ?? recipient.truncated}`,\n details,\n vault: {\n address: vaultAddress,\n truncated: truncateAddress(vaultAddress),\n chain: getChainDisplay(vaultChainId),\n },\n fee: {\n gas: prepared.formattedCost,\n paidByRelayer: false, // Will be updated by caller if gasless\n total: prepared.formattedCost,\n },\n warnings,\n raw: {\n actionType: ACTION_TRANSFER,\n actionPayload,\n nonce,\n challenge: ethers.hexlify(challenge),\n chainId: params.targetChain,\n expiresAt,\n expiresIn: formatTimeRemaining(expiresAt),\n },\n generatedAt: Date.now(),\n };\n }\n\n /**\n * Parse a bridge operation into a human-readable summary\n */\n async parseBridge(\n params: BridgeParams,\n actionPayload: string,\n nonce: bigint,\n challenge: Uint8Array,\n vaultAddress: string,\n vaultChainId: number,\n expiresAt: number,\n formattedCost: string\n ): Promise<TransactionSummary> {\n const decoded = decodeBridgeAction(actionPayload);\n\n const token = await this.resolveToken(decoded.token, decoded.amount);\n const sourceChain = getChainDisplay(params.sourceChain);\n const destinationChain = getChainDisplay(params.destinationChain);\n const recipient = await this.resolveRecipient(decoded.recipient);\n\n const details: BridgeDetails = {\n token,\n sourceChain,\n destinationChain,\n recipient,\n estimatedTime: this.estimateBridgeTime(sourceChain.id, destinationChain.id),\n };\n\n const warnings = await this.assessBridgeRisks(params, token, sourceChain, destinationChain);\n\n return {\n action: 'bridge',\n title: `Bridge ${token.symbol}`,\n description: `Bridge ${token.amount} ${token.symbol} from ${sourceChain.name} to ${destinationChain.name}`,\n details,\n vault: {\n address: vaultAddress,\n truncated: truncateAddress(vaultAddress),\n chain: getChainDisplay(vaultChainId),\n },\n fee: {\n gas: formattedCost,\n paidByRelayer: false,\n total: formattedCost,\n },\n warnings,\n raw: {\n actionType: ACTION_BRIDGE,\n actionPayload,\n nonce,\n challenge: ethers.hexlify(challenge),\n chainId: params.sourceChain,\n expiresAt,\n expiresIn: formatTimeRemaining(expiresAt),\n },\n generatedAt: Date.now(),\n };\n }\n\n /**\n * Parse an execute (contract call) operation into a human-readable summary\n */\n async parseExecute(\n target: string,\n value: bigint,\n calldata: string,\n chainId: number,\n nonce: bigint,\n challenge: Uint8Array,\n vaultAddress: string,\n expiresAt: number,\n formattedCost: string\n ): Promise<TransactionSummary> {\n const targetRecipient = await this.resolveRecipient(target);\n const chain = getChainDisplay(chainId);\n const valueToken = await this.resolveToken(ethers.ZeroAddress, value);\n\n // Try to decode function signature\n const functionInfo = this.decodeFunctionCall(calldata);\n\n const details: ExecuteDetails = {\n target: targetRecipient,\n value: valueToken,\n chain,\n functionName: functionInfo?.name,\n decodedArgs: functionInfo?.args,\n calldata,\n };\n\n const warnings = await this.assessExecuteRisks(target, value, calldata, targetRecipient);\n\n const title = functionInfo?.name\n ? `Call ${functionInfo.name}`\n : 'Contract Interaction';\n\n return {\n action: 'execute',\n title,\n description: `Execute contract call on ${targetRecipient.ens ?? targetRecipient.truncated}`,\n details,\n vault: {\n address: vaultAddress,\n truncated: truncateAddress(vaultAddress),\n chain,\n },\n fee: {\n gas: formattedCost,\n paidByRelayer: false,\n total: formattedCost,\n },\n warnings,\n raw: {\n actionType: ACTION_EXECUTE,\n actionPayload: calldata,\n nonce,\n challenge: ethers.hexlify(challenge),\n chainId,\n expiresAt,\n expiresIn: formatTimeRemaining(expiresAt),\n },\n generatedAt: Date.now(),\n };\n }\n\n /**\n * Parse a config change operation\n */\n async parseConfig(\n configType: number,\n configData: string,\n chainId: number,\n nonce: bigint,\n challenge: Uint8Array,\n vaultAddress: string,\n expiresAt: number,\n formattedCost: string\n ): Promise<TransactionSummary> {\n const chain = getChainDisplay(chainId);\n const configTypeName = getConfigTypeName(configType);\n\n const details: ConfigDetails = {\n configType,\n configTypeName,\n description: this.describeConfigChange(configType, configData),\n changes: this.parseConfigChanges(configType, configData),\n };\n\n const warnings: RiskWarning[] = [{\n level: 'warning',\n type: 'config_change',\n message: 'This transaction will modify your vault settings',\n }];\n\n return {\n action: 'config',\n title: configTypeName,\n description: `Update vault configuration: ${configTypeName}`,\n details,\n vault: {\n address: vaultAddress,\n truncated: truncateAddress(vaultAddress),\n chain,\n },\n fee: {\n gas: formattedCost,\n paidByRelayer: false,\n total: formattedCost,\n },\n warnings,\n raw: {\n actionType: ACTION_CONFIG,\n actionPayload: configData,\n nonce,\n challenge: ethers.hexlify(challenge),\n chainId,\n expiresAt,\n expiresIn: formatTimeRemaining(expiresAt),\n },\n generatedAt: Date.now(),\n };\n }\n\n // ============================================================================\n // Resolution Methods\n // ============================================================================\n\n /**\n * Resolve token address to display info\n */\n private async resolveToken(address: string, amount: bigint): Promise<TokenDisplay> {\n const normalizedAddress = address.toLowerCase();\n const isNative = isNativeToken(address);\n\n // Check registry\n let tokenInfo = this.tokenRegistry.get(normalizedAddress);\n if (!tokenInfo && isNative) {\n tokenInfo = this.tokenRegistry.get('native');\n }\n\n const decimals = tokenInfo?.decimals ?? 18;\n const symbol = tokenInfo?.symbol ?? (isNative ? 'ETH' : 'UNKNOWN');\n const formattedAmount = formatAmount(amount, decimals);\n\n // Try to get USD value\n let usdValue: string | undefined;\n if (this.config.priceOracle) {\n try {\n const price = await this.config.priceOracle(address);\n if (price !== null) {\n const amountNum = parseFloat(formattedAmount);\n usdValue = `$${(amountNum * price).toFixed(2)}`;\n }\n } catch {\n // Price oracle failed, continue without USD value\n }\n }\n\n return {\n symbol,\n amount: formattedAmount,\n rawAmount: amount,\n address: isNative ? ethers.ZeroAddress : address,\n decimals,\n usdValue,\n isNative,\n };\n }\n\n /**\n * Resolve recipient address to display info\n */\n private async resolveRecipient(address: string): Promise<RecipientDisplay> {\n const truncated = truncateAddress(address);\n let ens: string | undefined;\n let isContract: boolean | undefined;\n let isNewRecipient: boolean | undefined;\n let label: string | undefined;\n\n // Check known recipients\n if (this.config.knownRecipients) {\n label = this.config.knownRecipients.get(address.toLowerCase());\n }\n\n // Try ENS resolution\n if (this.config.ensResolver) {\n try {\n const resolved = await this.config.ensResolver(address);\n if (resolved) {\n ens = resolved;\n }\n } catch {\n // ENS resolution failed, continue without\n }\n }\n\n // Check if contract\n if (this.config.contractDetector) {\n try {\n isContract = await this.config.contractDetector(address);\n } catch {\n // Contract detection failed\n }\n }\n\n // Check transaction history\n if (this.config.transactionHistory) {\n isNewRecipient = !this.config.transactionHistory.has(address.toLowerCase());\n }\n\n return {\n address,\n ens,\n truncated,\n isContract,\n isNewRecipient,\n label,\n };\n }\n\n // ============================================================================\n // Risk Assessment Methods\n // ============================================================================\n\n /**\n * Assess risks for a transfer transaction\n */\n private async assessTransferRisks(\n _params: TransferParams,\n token: TokenDisplay,\n recipient: RecipientDisplay\n ): Promise<RiskWarning[]> {\n const warnings: RiskWarning[] = [];\n\n // New recipient warning\n if (recipient.isNewRecipient) {\n warnings.push({\n level: 'warning',\n type: 'new_recipient',\n message: \"You've never sent to this address before\",\n details: 'Double-check the recipient address is correct',\n });\n }\n\n // Large transaction warning\n if (this.config.averageTransactionValue) {\n const threshold = this.config.averageTransactionValue * 10n; // 10x average\n if (token.rawAmount > threshold) {\n warnings.push({\n level: 'warning',\n type: 'large_transaction',\n message: 'This transaction is larger than your usual activity',\n details: `Amount: ${token.amount} ${token.symbol}`,\n });\n }\n }\n\n // Contract interaction warning\n if (recipient.isContract) {\n warnings.push({\n level: 'info',\n type: 'contract_interaction',\n message: 'Recipient is a smart contract',\n });\n }\n\n // Unknown token warning\n const tokenInfo = this.tokenRegistry.get(token.address.toLowerCase());\n if (!tokenInfo?.verified) {\n warnings.push({\n level: 'warning',\n type: 'unknown_token',\n message: 'This token is not in our verified list',\n details: 'Verify the token address is correct',\n });\n }\n\n return warnings;\n }\n\n /**\n * Assess risks for a bridge transaction\n */\n private async assessBridgeRisks(\n _params: BridgeParams,\n token: TokenDisplay,\n sourceChain: ChainDisplay,\n destinationChain: ChainDisplay\n ): Promise<RiskWarning[]> {\n const warnings: RiskWarning[] = [];\n\n // Cross-chain operation info\n warnings.push({\n level: 'info',\n type: 'cross_chain',\n message: `This is a cross-chain transfer from ${sourceChain.name} to ${destinationChain.name}`,\n details: 'Funds will be locked on the source chain and released on the destination',\n });\n\n // Large transaction warning\n if (this.config.averageTransactionValue) {\n const threshold = this.config.averageTransactionValue * 10n;\n if (token.rawAmount > threshold) {\n warnings.push({\n level: 'warning',\n type: 'large_transaction',\n message: 'This transaction is larger than your usual activity',\n });\n }\n }\n\n return warnings;\n }\n\n /**\n * Assess risks for an execute transaction\n */\n private async assessExecuteRisks(\n _target: string,\n value: bigint,\n _calldata: string,\n recipient: RecipientDisplay\n ): Promise<RiskWarning[]> {\n const warnings: RiskWarning[] = [];\n\n // Contract interaction is inherently risky\n warnings.push({\n level: 'warning',\n type: 'contract_interaction',\n message: 'This transaction calls an external contract',\n details: 'Review the contract and function being called',\n });\n\n // New recipient warning\n if (recipient.isNewRecipient) {\n warnings.push({\n level: 'warning',\n type: 'new_recipient',\n message: \"You've never interacted with this contract before\",\n });\n }\n\n // Value transfer with contract call\n if (value > 0n) {\n warnings.push({\n level: 'info',\n type: 'large_transaction',\n message: `This transaction sends ${formatAmount(value, 18)} ETH along with the contract call`,\n });\n }\n\n return warnings;\n }\n\n // ============================================================================\n // Helper Methods\n // ============================================================================\n\n /**\n * Estimate bridge completion time\n */\n private estimateBridgeTime(_sourceChain: number, _destChain: number): string {\n // Wormhole typically takes 2-15 minutes depending on chains\n // Query-based is faster (~5-7 seconds), VAA-based is slower (~2+ minutes)\n return '~2-5 minutes';\n }\n\n /**\n * Try to decode a function call from calldata\n */\n private decodeFunctionCall(calldata: string): { name: string; args: Record<string, unknown> } | null {\n if (calldata.length < 10) return null;\n\n // Common function selectors\n const KNOWN_SELECTORS: Record<string, string> = {\n '0xa9059cbb': 'transfer',\n '0x23b872dd': 'transferFrom',\n '0x095ea7b3': 'approve',\n '0x70a08231': 'balanceOf',\n '0x18160ddd': 'totalSupply',\n '0x313ce567': 'decimals',\n '0x06fdde03': 'name',\n '0x95d89b41': 'symbol',\n };\n\n const selector = calldata.slice(0, 10).toLowerCase();\n const name = KNOWN_SELECTORS[selector];\n\n if (name) {\n return { name, args: {} }; // Would need ABI to decode args\n }\n\n return null;\n }\n\n /**\n * Describe a config change in human-readable terms\n */\n private describeConfigChange(configType: number, _configData: string): string {\n const name = getConfigTypeName(configType);\n return `This will update your vault's ${name.toLowerCase()}`;\n }\n\n /**\n * Parse config changes into structured format\n */\n private parseConfigChanges(configType: number, configData: string): Array<{ field: string; newValue: string }> {\n // Basic parsing - would need more context for full implementation\n return [{\n field: getConfigTypeName(configType),\n newValue: configData.length > 66 ? `${configData.slice(0, 66)}...` : configData,\n }];\n }\n\n /**\n * Update parser configuration\n */\n updateConfig(config: Partial<TransactionParserConfig>): void {\n this.config = { ...this.config, ...config };\n if (config.knownTokens) {\n this.tokenRegistry = config.knownTokens;\n }\n }\n\n /**\n * Add a known token to the registry\n */\n addKnownToken(address: string, info: TokenInfo): void {\n this.tokenRegistry.set(address.toLowerCase(), info);\n }\n\n /**\n * Add a known recipient label\n */\n addKnownRecipient(address: string, label: string): void {\n if (!this.config.knownRecipients) {\n this.config.knownRecipients = new Map();\n }\n this.config.knownRecipients.set(address.toLowerCase(), label);\n }\n}\n\n// ============================================================================\n// Audit Logging Types and Functions\n// ============================================================================\n\n/**\n * Audit log entry for transaction summaries\n * Used for security audits and debugging\n */\nexport interface TransactionAuditEntry {\n /** Unique identifier matching the TransactionSummary.id */\n summaryId: string;\n /** ISO timestamp when summary was generated */\n timestamp: string;\n /** Action type that was parsed */\n actionType: string;\n /** Human-readable title shown to user */\n titleDisplayed: string;\n /** Human-readable description shown to user */\n descriptionDisplayed: string;\n /** Number of risk warnings shown */\n riskWarningCount: number;\n /** Highest risk level in warnings */\n highestRiskLevel: string | null;\n /** Whether technical details were available */\n hasTechnicalDetails: boolean;\n /** Hash of the raw payload for verification */\n payloadHash: string;\n /** Expiration time shown */\n expiresAt: number;\n /** Chain ID of the transaction */\n targetChain: number;\n /** Gas cost formatted as shown to user */\n gasCostDisplayed: string;\n}\n\n/**\n * Create an audit log entry from a transaction summary\n * \n * @param summary - The transaction summary that was displayed\n * @returns Audit entry for logging\n */\nexport function createAuditEntry(summary: TransactionSummary): TransactionAuditEntry {\n const highestRisk = summary.warnings.reduce<string | null>((acc, r) => {\n const order: Record<string, number> = { critical: 0, high: 1, warning: 2, info: 3 };\n if (acc === null) return r.level;\n if (order[r.level] < order[acc]) {\n return r.level;\n }\n return acc;\n }, null);\n\n return {\n summaryId: `${summary.generatedAt}-${summary.action}`,\n timestamp: new Date().toISOString(),\n actionType: summary.action,\n titleDisplayed: summary.title,\n descriptionDisplayed: summary.description,\n riskWarningCount: summary.warnings.length,\n highestRiskLevel: highestRisk,\n hasTechnicalDetails: !!summary.raw,\n payloadHash: summary.raw?.actionPayload ? ethers.keccak256(summary.raw.actionPayload) : '',\n expiresAt: summary.raw?.expiresAt ?? 0,\n targetChain: summary.raw?.chainId ?? 0,\n gasCostDisplayed: summary.fee.total,\n };\n}\n\n/**\n * Log a transaction summary for audit purposes\n * \n * @param summary - The transaction summary to log\n * @param logger - Optional custom logger (defaults to console.info)\n */\nexport function logTransactionSummary(\n summary: TransactionSummary,\n logger: (entry: TransactionAuditEntry) => void = (entry) => {\n // Default: structured console logging\n console.info('[VERIDEX_TX_AUDIT]', JSON.stringify(entry));\n }\n): TransactionAuditEntry {\n const entry = createAuditEntry(summary);\n logger(entry);\n return entry;\n}\n\n// ============================================================================\n// Factory Function\n// ============================================================================\n\n/**\n * Create a transaction parser with optional configuration\n */\nexport function createTransactionParser(config?: TransactionParserConfig): TransactionParser {\n return new TransactionParser(config);\n}\n","/**\n * Veridex Protocol SDK - Transaction Summary Types\n * \n * Human-readable transaction summary types for security and UX (Issue #26)\n * \n * These types enable users to understand what they're signing before\n * providing biometric authentication, preventing phishing and social engineering.\n */\n\n// ============================================================================\n// Action Display Types\n// ============================================================================\n\n/**\n * Human-readable action type\n */\nexport type ActionDisplayType = 'transfer' | 'bridge' | 'config' | 'execute' | 'unknown';\n\n/**\n * Token display information\n */\nexport interface TokenDisplay {\n /** Token symbol (e.g., \"ETH\", \"USDC\") */\n symbol: string;\n /** Human-readable amount (e.g., \"1.5\") */\n amount: string;\n /** Raw amount in smallest unit */\n rawAmount: bigint;\n /** Token contract address */\n address: string;\n /** Number of decimals */\n decimals: number;\n /** Estimated USD value (if available) */\n usdValue?: string;\n /** Whether this is the native token */\n isNative: boolean;\n}\n\n/**\n * Recipient display information\n */\nexport interface RecipientDisplay {\n /** Raw address (hex) */\n address: string;\n /** ENS name (if resolved) */\n ens?: string;\n /** Truncated address for display (e.g., \"0x1234...5678\") */\n truncated: string;\n /** Whether this is a contract address */\n isContract?: boolean;\n /** Whether this is a new recipient (never sent to before) */\n isNewRecipient?: boolean;\n /** Label if known (e.g., \"My Wallet\", \"Exchange\") */\n label?: string;\n}\n\n/**\n * Chain display information\n */\nexport interface ChainDisplay {\n /** Wormhole chain ID */\n id: number;\n /** Human-readable chain name */\n name: string;\n /** Chain icon URL (optional) */\n iconUrl?: string;\n /** Whether this is a testnet */\n isTestnet: boolean;\n}\n\n// ============================================================================\n// Risk Warning Types\n// ============================================================================\n\n/**\n * Risk level for warnings\n */\nexport type RiskLevel = 'info' | 'warning' | 'high' | 'critical';\n\n/**\n * Risk warning with message and metadata\n */\nexport interface RiskWarning {\n /** Severity level */\n level: RiskLevel;\n /** Human-readable warning message */\n message: string;\n /** Warning type for programmatic handling */\n type: RiskWarningType;\n /** Additional context/details */\n details?: string;\n}\n\n/**\n * Types of risk warnings\n */\nexport type RiskWarningType =\n | 'large_transaction' // Amount exceeds usual activity\n | 'new_recipient' // First time sending to this address\n | 'contract_interaction' // Calling an external contract\n | 'full_balance' // Transferring all assets\n | 'high_gas' // Gas cost is unusually high\n | 'unknown_token' // Token not in verified list\n | 'cross_chain' // Cross-chain operation\n | 'config_change' // Vault configuration change\n | 'all_tokens' // Affects all tokens in vault\n | 'irreversible'; // Action cannot be undone\n\n// ============================================================================\n// Transaction Summary Types\n// ============================================================================\n\n/**\n * Transfer-specific details\n */\nexport interface TransferDetails {\n token: TokenDisplay;\n recipient: RecipientDisplay;\n chain: ChainDisplay;\n}\n\n/**\n * Bridge-specific details\n */\nexport interface BridgeDetails {\n token: TokenDisplay;\n sourceChain: ChainDisplay;\n destinationChain: ChainDisplay;\n recipient: RecipientDisplay;\n /** Estimated bridge fee */\n bridgeFee?: string;\n /** Estimated arrival time */\n estimatedTime?: string;\n}\n\n/**\n * Execute (contract call) details\n */\nexport interface ExecuteDetails {\n target: RecipientDisplay;\n value: TokenDisplay;\n chain: ChainDisplay;\n /** Function signature if decodable */\n functionName?: string;\n /** Decoded function arguments if available */\n decodedArgs?: Record<string, unknown>;\n /** Raw calldata (hex) */\n calldata: string;\n}\n\n/**\n * Config change details\n */\nexport interface ConfigDetails {\n configType: number;\n configTypeName: string;\n description: string;\n changes: Array<{\n field: string;\n oldValue?: string;\n newValue: string;\n }>;\n}\n\n/**\n * Union type for all action-specific details\n */\nexport type ActionDetails = TransferDetails | BridgeDetails | ExecuteDetails | ConfigDetails;\n\n/**\n * Complete transaction summary for display\n */\nexport interface TransactionSummary {\n /** Action type for display */\n action: ActionDisplayType;\n\n /** Human-readable title (e.g., \"Send ETH\", \"Bridge USDC\") */\n title: string;\n\n /** Human-readable description */\n description: string;\n\n /** Action-specific details */\n details: TransferDetails | BridgeDetails | ExecuteDetails | ConfigDetails | null;\n\n /** Source vault information */\n vault: {\n address: string;\n truncated: string;\n chain: ChainDisplay;\n };\n\n /** Fee information */\n fee: {\n /** Estimated gas fee */\n gas: string;\n /** Gas in USD (if available) */\n gasUsd?: string;\n /** Whether fee is paid by relayer */\n paidByRelayer: boolean;\n /** Relayer fee (if applicable) */\n relayerFee?: string;\n /** Total fee */\n total: string;\n };\n\n /** Risk warnings */\n warnings: RiskWarning[];\n\n /** Raw technical details for advanced users */\n raw: {\n actionType: number;\n actionPayload: string;\n nonce: bigint;\n challenge: string;\n chainId: number;\n /** Expiration timestamp */\n expiresAt: number;\n /** Time until expiration in human readable form */\n expiresIn: string;\n };\n\n /** Timestamp when summary was generated */\n generatedAt: number;\n}\n\n// ============================================================================\n// Parser Configuration\n// ============================================================================\n\n/**\n * Configuration for the transaction parser\n */\nexport interface TransactionParserConfig {\n /** Default chain ID for vault operations */\n defaultChainId?: number;\n /** Known token registry (address -> info) */\n knownTokens?: Map<string, TokenInfo>;\n /** Known recipient labels (address -> label) */\n knownRecipients?: Map<string, string>;\n /** ENS resolver function */\n ensResolver?: (address: string) => Promise<string | null>;\n /** Contract detector function */\n contractDetector?: (address: string) => Promise<boolean>;\n /** Price oracle for USD values */\n priceOracle?: (tokenAddress: string) => Promise<number | null>;\n /** User's transaction history for new recipient detection */\n transactionHistory?: Set<string>;\n /** User's average transaction value for large tx detection */\n averageTransactionValue?: bigint;\n}\n\n/**\n * Token info for registry\n */\nexport interface TokenInfo {\n symbol: string;\n name: string;\n decimals: number;\n logoUrl?: string;\n verified: boolean;\n}\n\n// ============================================================================\n// Chain Name Mapping\n// ============================================================================\n\n/**\n * Get chain display info from Wormhole chain ID\n */\nexport const CHAIN_DISPLAY_INFO: Record<number, Omit<ChainDisplay, 'id'>> = {\n // Mainnets\n 1: { name: 'Solana', isTestnet: false },\n 2: { name: 'Ethereum', isTestnet: false },\n 4: { name: 'BSC', isTestnet: false },\n 5: { name: 'Polygon', isTestnet: false },\n 6: { name: 'Avalanche', isTestnet: false },\n 21: { name: 'Sui', isTestnet: false },\n 22: { name: 'Aptos', isTestnet: false },\n 23: { name: 'Arbitrum', isTestnet: false },\n 24: { name: 'Optimism', isTestnet: false },\n 30: { name: 'Base', isTestnet: false },\n\n // Testnets\n 10002: { name: 'Sepolia', isTestnet: true },\n 10003: { name: 'Arbitrum Sepolia', isTestnet: true },\n 10004: { name: 'Base Sepolia', isTestnet: true },\n 10005: { name: 'Optimism Sepolia', isTestnet: true },\n 50001: { name: 'Starknet Sepolia', isTestnet: true },\n // Note: Avalanche Fuji also uses Wormhole chain ID 6 — same as mainnet.\n // The isTestnet flag on mainnet entry (6) is set to false; frontends should\n // detect testnet via EVM chainId (43113 vs 43114) rather than Wormhole chain ID.\n};\n\n/**\n * Get chain display info with fallback\n */\nexport function getChainDisplay(chainId: number): ChainDisplay {\n const info = CHAIN_DISPLAY_INFO[chainId];\n if (info) {\n return { id: chainId, ...info };\n }\n return {\n id: chainId,\n name: `Chain ${chainId}`,\n isTestnet: chainId >= 10000,\n };\n}\n\n// ============================================================================\n// Config Type Names\n// ============================================================================\n\nexport const CONFIG_TYPE_NAMES: Record<number, string> = {\n 1: 'Update Spending Limits',\n 2: 'Add Guardian',\n 3: 'Remove Guardian',\n 4: 'Update Recovery Threshold',\n 5: 'Add Session Key',\n 6: 'Revoke Session Key',\n 7: 'Update Emergency Contact',\n};\n\n/**\n * Get config type name with fallback\n */\nexport function getConfigTypeName(configType: number): string {\n return CONFIG_TYPE_NAMES[configType] ?? `Config Update (Type ${configType})`;\n}\n","/**\n * Veridex Protocol SDK - Spending Limits Manager (Issue #27)\n * \n * Manages vault spending limits including:\n * - Reading current limits and usage from on-chain state\n * - Preparing limit update transactions (requires passkey signature)\n * - Checking transactions against limits before signing\n * - Formatting limits for UI display\n * \n * Security Considerations:\n * - All limit changes require Hub authentication (passkey signature)\n * - Changes are propagated via VAA to spoke chains\n * - Local checks are advisory; on-chain enforcement is authoritative\n */\n\nimport { ethers } from 'ethers';\nimport {\n type SpendingLimits,\n type FormattedSpendingLimits,\n type LimitCheckResult,\n type LimitViolationSuggestion,\n type SpendingTransaction,\n type DailySpendingSummary,\n type DurationDisplay,\n type SpendingLimitConfig,\n type SpendingLimitChangedEvent,\n type SpendingLimitEventCallback,\n CONFIG_TYPE,\n formatDuration,\n calculatePercentage,\n formatLargeAmount,\n} from './SpendingLimits.types.js';\nimport { encodeConfigAction } from '../payload.js';\n\n// ============================================================================\n// Vault ABI Fragment (spending limit related functions)\n// ============================================================================\n\nconst VAULT_ABI = [\n 'function dailyLimit() view returns (uint256)',\n 'function dailyWithdrawn() view returns (uint256)',\n 'function dayStart() view returns (uint256)',\n 'function paused() view returns (bool)',\n 'function getRemainingDailyLimit() view returns (uint256)',\n 'event Paused(bool paused)',\n 'event DailyLimitUpdated(uint256 newLimit)',\n];\n\n// ============================================================================\n// Constants\n// ============================================================================\n\n/** One day in seconds */\nconst DAY_SECONDS = 86400;\n\n/** One day in milliseconds */\nconst DAY_MS = DAY_SECONDS * 1000;\n\n// ============================================================================\n// Configuration\n// ============================================================================\n\nexport interface SpendingLimitsManagerConfig {\n /** Default token decimals for formatting */\n defaultDecimals?: number;\n \n /** Default token symbol for formatting */\n defaultSymbol?: string;\n \n /** Custom RPC URLs by chain ID */\n rpcUrls?: Record<number, string>;\n \n /** Cache TTL in milliseconds */\n cacheTtl?: number;\n \n /** Event callback for limit changes */\n onLimitChange?: SpendingLimitEventCallback;\n}\n\n// ============================================================================\n// Main Class\n// ============================================================================\n\nexport class SpendingLimitsManager {\n private config: Required<SpendingLimitsManagerConfig>;\n private cache: Map<string, { data: SpendingLimits; expiry: number }> = new Map();\n private eventListeners: SpendingLimitEventCallback[] = [];\n \n constructor(config: SpendingLimitsManagerConfig = {}) {\n this.config = {\n defaultDecimals: config.defaultDecimals ?? 18,\n defaultSymbol: config.defaultSymbol ?? 'ETH',\n rpcUrls: config.rpcUrls ?? {},\n cacheTtl: config.cacheTtl ?? 10000, // 10 seconds\n onLimitChange: config.onLimitChange ?? (() => {}),\n };\n \n if (config.onLimitChange) {\n this.eventListeners.push(config.onLimitChange);\n }\n }\n \n // ============================================================================\n // Read Spending Limits\n // ============================================================================\n \n /**\n * Get current spending limits for a vault\n * @param vaultAddress - Vault contract address\n * @param chainId - Chain ID where the vault is deployed\n * @param rpcUrl - Optional RPC URL override\n */\n async getSpendingLimits(\n vaultAddress: string,\n chainId: number,\n rpcUrl?: string\n ): Promise<SpendingLimits> {\n // Check cache first\n const cacheKey = `${chainId}:${vaultAddress.toLowerCase()}`;\n const cached = this.cache.get(cacheKey);\n if (cached && Date.now() < cached.expiry) {\n return cached.data;\n }\n \n const provider = this.getProvider(chainId, rpcUrl);\n const vault = new ethers.Contract(vaultAddress, VAULT_ABI, provider);\n \n // Fetch all values in parallel\n const [dailyLimit, dailyWithdrawn, dayStart, paused] = await Promise.all([\n vault.dailyLimit() as Promise<bigint>,\n vault.dailyWithdrawn() as Promise<bigint>,\n vault.dayStart() as Promise<bigint>,\n vault.paused() as Promise<boolean>,\n ]);\n \n const now = Date.now();\n const dayStartMs = Number(dayStart) * 1000;\n const dayEndMs = dayStartMs + DAY_MS;\n \n // Calculate effective values (handle day rollover)\n let effectiveSpent = dailyWithdrawn;\n let effectiveResetTime = new Date(dayEndMs);\n let timeUntilReset = dayEndMs - now;\n \n if (now >= dayEndMs) {\n // New day has started, spent resets to 0\n effectiveSpent = 0n;\n // Calculate next reset time\n const daysSinceStart = Math.floor((now - dayStartMs) / DAY_MS);\n const nextDayStart = dayStartMs + (daysSinceStart + 1) * DAY_MS;\n effectiveResetTime = new Date(nextDayStart);\n timeUntilReset = nextDayStart - now;\n }\n \n const dailyRemaining = dailyLimit === 0n \n ? BigInt('0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff') // max uint256\n : dailyLimit > effectiveSpent \n ? dailyLimit - effectiveSpent \n : 0n;\n \n const limits: SpendingLimits = {\n dailyLimit,\n dailySpent: effectiveSpent,\n dailyRemaining,\n dayResetTime: effectiveResetTime,\n timeUntilReset: Math.max(0, timeUntilReset),\n transactionLimit: 0n, // Per-tx limits are in SpendingLimitModule, not base vault\n isPaused: paused,\n lastUpdated: new Date(),\n chainId,\n };\n \n // Cache the result\n this.cache.set(cacheKey, {\n data: limits,\n expiry: now + this.config.cacheTtl,\n });\n \n return limits;\n }\n \n /**\n * Get spending limits formatted for UI display\n */\n async getFormattedSpendingLimits(\n vaultAddress: string,\n chainId: number,\n options?: {\n rpcUrl?: string;\n decimals?: number;\n symbol?: string;\n }\n ): Promise<FormattedSpendingLimits> {\n const limits = await this.getSpendingLimits(vaultAddress, chainId, options?.rpcUrl);\n const decimals = options?.decimals ?? this.config.defaultDecimals;\n const symbol = options?.symbol ?? this.config.defaultSymbol;\n \n return this.formatLimits(limits, decimals, symbol);\n }\n \n /**\n * Format raw limits for display\n */\n formatLimits(\n limits: SpendingLimits,\n decimals: number = 18,\n symbol: string = 'ETH'\n ): FormattedSpendingLimits {\n const hasDailyLimit = limits.dailyLimit > 0n;\n \n // Convert to number for display (safe for typical amounts)\n const toNumber = (val: bigint): number => {\n const divisor = 10n ** BigInt(decimals);\n return Number(val * 10000n / divisor) / 10000;\n };\n \n return {\n dailyLimit: hasDailyLimit \n ? formatLargeAmount(limits.dailyLimit, decimals, symbol)\n : 'Unlimited',\n dailyLimitValue: toNumber(limits.dailyLimit),\n dailySpent: formatLargeAmount(limits.dailySpent, decimals, symbol),\n dailySpentValue: toNumber(limits.dailySpent),\n dailyRemaining: hasDailyLimit \n ? formatLargeAmount(limits.dailyRemaining, decimals, symbol)\n : 'Unlimited',\n dailyRemainingValue: toNumber(limits.dailyRemaining),\n dailyUsedPercentage: hasDailyLimit \n ? calculatePercentage(limits.dailySpent, limits.dailyLimit)\n : 0,\n timeUntilReset: formatDuration(limits.timeUntilReset).formatted,\n transactionLimit: limits.transactionLimit > 0n\n ? formatLargeAmount(limits.transactionLimit, decimals, symbol)\n : 'Unlimited',\n transactionLimitValue: toNumber(limits.transactionLimit),\n isPaused: limits.isPaused,\n hasDailyLimit,\n hasTransactionLimit: limits.transactionLimit > 0n,\n };\n }\n \n // ============================================================================\n // Limit Checks\n // ============================================================================\n \n /**\n * Check if a transaction amount is within limits\n * @param vaultAddress - Vault to check\n * @param chainId - Chain ID\n * @param amount - Amount to transfer (in base units)\n * @returns Result indicating if transfer is allowed\n */\n async checkTransactionLimit(\n vaultAddress: string,\n chainId: number,\n amount: bigint,\n options?: { rpcUrl?: string }\n ): Promise<LimitCheckResult> {\n const limits = await this.getSpendingLimits(vaultAddress, chainId, options?.rpcUrl);\n \n // Check if paused first\n if (limits.isPaused) {\n return {\n allowed: false,\n reason: 'vault_paused',\n message: 'Vault is paused. Unpause to continue.',\n suggestions: [\n {\n action: 'unpause_vault',\n label: 'Unpause Vault',\n },\n ],\n };\n }\n \n // Check per-transaction limit\n if (limits.transactionLimit > 0n && amount > limits.transactionLimit) {\n return {\n allowed: false,\n reason: 'transaction_limit_exceeded',\n message: `Transaction exceeds per-transaction limit of ${formatLargeAmount(limits.transactionLimit, this.config.defaultDecimals, this.config.defaultSymbol)}`,\n allowedAmount: limits.transactionLimit,\n excessAmount: amount - limits.transactionLimit,\n suggestions: [\n {\n action: 'send_partial',\n label: `Send ${formatLargeAmount(limits.transactionLimit, this.config.defaultDecimals, this.config.defaultSymbol)} (within limit)`,\n data: { amount: limits.transactionLimit },\n },\n {\n action: 'increase_limit',\n label: 'Increase Transaction Limit',\n },\n ],\n };\n }\n \n // Check daily limit\n if (limits.dailyLimit > 0n) {\n const wouldSpend = limits.dailySpent + amount;\n \n if (wouldSpend > limits.dailyLimit) {\n const excessAmount = wouldSpend - limits.dailyLimit;\n const suggestions: LimitViolationSuggestion[] = [];\n \n // Suggest partial transfer if some amount is available\n if (limits.dailyRemaining > 0n) {\n suggestions.push({\n action: 'send_partial',\n label: `Send ${formatLargeAmount(limits.dailyRemaining, this.config.defaultDecimals, this.config.defaultSymbol)} (within limit)`,\n data: { amount: limits.dailyRemaining },\n });\n }\n \n suggestions.push({\n action: 'increase_limit',\n label: 'Increase Daily Limit',\n data: { newLimit: wouldSpend },\n });\n \n suggestions.push({\n action: 'wait_for_reset',\n label: `Wait ${formatDuration(limits.timeUntilReset).formatted} for limit reset`,\n data: { waitTimeMs: limits.timeUntilReset },\n });\n \n return {\n allowed: false,\n reason: 'daily_limit_exceeded',\n message: `Transaction would exceed daily limit. Already spent ${formatLargeAmount(limits.dailySpent, this.config.defaultDecimals, this.config.defaultSymbol)} of ${formatLargeAmount(limits.dailyLimit, this.config.defaultDecimals, this.config.defaultSymbol)} today.`,\n allowedAmount: limits.dailyRemaining,\n excessAmount,\n waitTime: limits.timeUntilReset,\n suggestions,\n };\n }\n }\n \n return {\n allowed: true,\n message: 'Transaction is within limits',\n };\n }\n \n // ============================================================================\n // Limit Configuration (Prepare for Signing)\n // ============================================================================\n \n /**\n * Prepare a transaction to update the daily spending limit\n * Returns the config action payload that needs to be signed via passkey\n * \n * @param newLimit - New daily limit in base units (0 = unlimited)\n * @returns Config action payload for signing\n */\n prepareDailyLimitUpdate(newLimit: bigint): string {\n // Config type 1 = daily limit update\n // Config data format: [limit(32)]\n const limitBytes = ethers.zeroPadValue(ethers.toBeHex(newLimit), 32);\n return encodeConfigAction(CONFIG_TYPE.DAILY_LIMIT, limitBytes);\n }\n \n /**\n * Prepare a transaction to pause the vault\n * @returns Config action payload for signing\n */\n preparePauseVault(): string {\n // Config type 2 = pause, config data: [paused(1)] where 1 = paused\n const pausedByte = ethers.toBeHex(1, 1);\n return encodeConfigAction(CONFIG_TYPE.PAUSE, pausedByte);\n }\n \n /**\n * Prepare a transaction to unpause the vault\n * @returns Config action payload for signing\n */\n prepareUnpauseVault(): string {\n // Config type 2 = pause, config data: [paused(1)] where 0 = unpaused\n const unpausedByte = ethers.toBeHex(0, 1);\n return encodeConfigAction(CONFIG_TYPE.PAUSE, unpausedByte);\n }\n \n /**\n * Get the full spending limit configuration encoded as config payload\n * Used during vault creation to set initial limits\n */\n encodeInitialLimits(config: SpendingLimitConfig): string {\n if (!config.dailyLimit || config.dailyLimit === 0n) {\n // No limit configuration needed\n return '';\n }\n return this.prepareDailyLimitUpdate(config.dailyLimit);\n }\n \n // ============================================================================\n // Transaction History\n // ============================================================================\n \n /**\n * Get recent spending transactions for a vault\n * Note: This requires indexer integration for full history\n * @param vaultAddress - Vault to query\n * @param chainId - Chain ID\n * @param limit - Maximum number of transactions to return\n */\n async getRecentTransactions(\n vaultAddress: string,\n chainId: number,\n limit: number = 10\n ): Promise<SpendingTransaction[]> {\n // Note: Full implementation requires indexer/subgraph integration\n // For now, return empty array - UI should handle gracefully\n // In production, this would query a subgraph or indexer API\n console.log(`[SpendingLimitsManager] getRecentTransactions not fully implemented. Vault: ${vaultAddress}, Chain: ${chainId}, Limit: ${limit}`);\n return [];\n }\n \n /**\n * Get daily spending summary\n */\n async getDailySpendingSummary(\n vaultAddress: string,\n chainId: number,\n date?: Date\n ): Promise<DailySpendingSummary> {\n const targetDate = date ?? new Date();\n const transactions = await this.getRecentTransactions(vaultAddress, chainId, 100);\n \n // Filter transactions from the target date\n const startOfDay = new Date(targetDate);\n startOfDay.setHours(0, 0, 0, 0);\n const endOfDay = new Date(startOfDay);\n endOfDay.setDate(endOfDay.getDate() + 1);\n \n const dayTransactions = transactions.filter(\n tx => tx.timestamp >= startOfDay && tx.timestamp < endOfDay\n );\n \n const totalSpent = dayTransactions.reduce(\n (sum, tx) => sum + tx.amount,\n 0n\n );\n \n return {\n date: targetDate,\n totalSpent,\n formattedTotal: formatLargeAmount(totalSpent, this.config.defaultDecimals, this.config.defaultSymbol),\n transactionCount: dayTransactions.length,\n transactions: dayTransactions,\n };\n }\n \n // ============================================================================\n // Event Subscription\n // ============================================================================\n \n /**\n * Subscribe to spending limit change events\n */\n onLimitChange(callback: SpendingLimitEventCallback): () => void {\n this.eventListeners.push(callback);\n return () => {\n const index = this.eventListeners.indexOf(callback);\n if (index >= 0) {\n this.eventListeners.splice(index, 1);\n }\n };\n }\n \n /**\n * Notify listeners of a limit change event\n * Call this after a successful limit update transaction\n */\n notifyLimitChange(event: SpendingLimitChangedEvent): void {\n for (const listener of this.eventListeners) {\n try {\n listener(event);\n } catch (error) {\n console.error('[SpendingLimitsManager] Event listener error:', error);\n }\n }\n }\n \n // ============================================================================\n // Countdown Timer\n // ============================================================================\n \n /**\n * Get a live countdown to daily limit reset\n * Returns an object with current time remaining that updates\n */\n async getResetCountdown(\n vaultAddress: string,\n chainId: number,\n options?: { rpcUrl?: string }\n ): Promise<{\n getCurrentTimeRemaining: () => DurationDisplay;\n timeUntilResetMs: number;\n resetTime: Date;\n }> {\n const limits = await this.getSpendingLimits(vaultAddress, chainId, options?.rpcUrl);\n const fetchTime = Date.now();\n \n return {\n getCurrentTimeRemaining: () => {\n const elapsed = Date.now() - fetchTime;\n const remaining = Math.max(0, limits.timeUntilReset - elapsed);\n return formatDuration(remaining);\n },\n timeUntilResetMs: limits.timeUntilReset,\n resetTime: limits.dayResetTime,\n };\n }\n \n // ============================================================================\n // Cache Management\n // ============================================================================\n \n /**\n * Clear the cache for a specific vault or all vaults\n */\n clearCache(vaultAddress?: string, chainId?: number): void {\n if (vaultAddress && chainId) {\n this.cache.delete(`${chainId}:${vaultAddress.toLowerCase()}`);\n } else {\n this.cache.clear();\n }\n }\n \n /**\n * Invalidate cache after a limit change\n */\n invalidateCacheAfterChange(vaultAddress: string, chainId: number): void {\n this.clearCache(vaultAddress, chainId);\n }\n \n // ============================================================================\n // Helpers\n // ============================================================================\n \n /**\n * Get a provider for the specified chain\n */\n private getProvider(chainId: number, rpcUrl?: string): ethers.Provider {\n const url = rpcUrl ?? this.config.rpcUrls[chainId];\n if (!url) {\n throw new Error(`No RPC URL configured for chain ${chainId}`);\n }\n return new ethers.JsonRpcProvider(url);\n }\n}\n\n// ============================================================================\n// Factory Function\n// ============================================================================\n\n/**\n * Create a SpendingLimitsManager instance\n */\nexport function createSpendingLimitsManager(\n config?: SpendingLimitsManagerConfig\n): SpendingLimitsManager {\n return new SpendingLimitsManager(config);\n}\n","/**\n * Veridex Protocol SDK - Spending Limits Type Definitions (Issue #27)\n * \n * Types for configuring, viewing, and enforcing spending limits on vaults.\n * Spending limits provide an additional security layer against:\n * - Compromised passkeys draining entire vault\n * - Accidental large transactions\n * - Malicious session key abuse\n * \n * Security Model:\n * - Limits are enforced on-chain by the vault contract\n * - Limit changes require passkey signature (Hub authentication)\n * - Circuit breaker auto-pauses vault on limit violation\n * - Daily limits reset 24 hours from first spend\n */\n\n// ============================================================================\n// Core Types\n// ============================================================================\n\n/**\n * Current spending limits and usage for a vault\n */\nexport interface SpendingLimits {\n /** Daily spending limit (0 = unlimited) */\n dailyLimit: bigint;\n \n /** Amount spent in current 24-hour period */\n dailySpent: bigint;\n \n /** Remaining daily allowance */\n dailyRemaining: bigint;\n \n /** When the daily counter resets (UTC timestamp) */\n dayResetTime: Date;\n \n /** Time remaining until daily reset (milliseconds) */\n timeUntilReset: number;\n \n /** Per-transaction limit (0 = unlimited) */\n transactionLimit: bigint;\n \n /** Whether the vault is currently paused */\n isPaused: boolean;\n \n /** Last updated timestamp */\n lastUpdated: Date;\n \n /** Chain where these limits are enforced */\n chainId: number;\n}\n\n/**\n * Formatted spending limits for UI display\n */\nexport interface FormattedSpendingLimits {\n /** Daily limit as human-readable string (e.g., \"1,000 USDC\") */\n dailyLimit: string;\n \n /** Daily limit as raw number for calculations */\n dailyLimitValue: number;\n \n /** Amount spent today as human-readable string */\n dailySpent: string;\n \n /** Amount spent as raw number */\n dailySpentValue: number;\n \n /** Remaining daily allowance as human-readable string */\n dailyRemaining: string;\n \n /** Remaining as raw number */\n dailyRemainingValue: number;\n \n /** Percentage of daily limit used (0-100) */\n dailyUsedPercentage: number;\n \n /** Time until reset as human-readable string (e.g., \"6h 23m\") */\n timeUntilReset: string;\n \n /** Transaction limit as human-readable string */\n transactionLimit: string;\n \n /** Transaction limit as raw number */\n transactionLimitValue: number;\n \n /** Whether the vault is paused */\n isPaused: boolean;\n \n /** Whether daily limit is set (false = unlimited) */\n hasDailyLimit: boolean;\n \n /** Whether transaction limit is set (false = unlimited) */\n hasTransactionLimit: boolean;\n}\n\n/**\n * Spending limit configuration during vault creation\n */\nexport interface SpendingLimitConfig {\n /** Daily spending limit (optional, 0 = unlimited) */\n dailyLimit?: bigint;\n \n /** Per-transaction limit (optional, 0 = unlimited) */\n transactionLimit?: bigint;\n \n /** Whether to require 2FA for transactions above threshold */\n requireMultiSigAbove?: bigint;\n \n /** Whitelisted recipients (unlimited transfers allowed) */\n whitelistedRecipients?: string[];\n}\n\n/**\n * Parameters for setting daily limit\n */\nexport interface SetDailyLimitParams {\n /** New daily limit in wei/lamports/base units */\n limit: bigint;\n \n /** Optional chain to configure (defaults to current chain) */\n chainId?: number;\n}\n\n/**\n * Parameters for setting transaction limit\n */\nexport interface SetTransactionLimitParams {\n /** New transaction limit in wei/lamports/base units */\n limit: bigint;\n \n /** Optional chain to configure (defaults to current chain) */\n chainId?: number;\n}\n\n// ============================================================================\n// Limit Enforcement Types\n// ============================================================================\n\n/**\n * Result of checking if a transaction is within limits\n */\nexport interface LimitCheckResult {\n /** Whether the transaction is allowed */\n allowed: boolean;\n \n /** Reason code if not allowed */\n reason?: LimitViolationType;\n \n /** Human-readable message */\n message: string;\n \n /** Amount that would be allowed (if partially allowed) */\n allowedAmount?: bigint;\n \n /** Amount that exceeds limit */\n excessAmount?: bigint;\n \n /** Time to wait if daily limit reached */\n waitTime?: number;\n \n /** Suggested actions for the user */\n suggestions?: LimitViolationSuggestion[];\n}\n\n/**\n * Types of limit violations\n */\nexport type LimitViolationType =\n | 'daily_limit_exceeded'\n | 'transaction_limit_exceeded'\n | 'vault_paused'\n | 'insufficient_balance'\n | 'daily_limit_would_exceed';\n\n/**\n * Suggestion for resolving a limit violation\n */\nexport interface LimitViolationSuggestion {\n /** Action type */\n action: 'send_partial' | 'increase_limit' | 'wait_for_reset' | 'unpause_vault';\n \n /** Human-readable label */\n label: string;\n \n /** Additional data for the action */\n data?: {\n amount?: bigint;\n waitTimeMs?: number;\n newLimit?: bigint;\n };\n}\n\n// ============================================================================\n// Transaction History Types\n// ============================================================================\n\n/**\n * A spending transaction in the history\n */\nexport interface SpendingTransaction {\n /** Transaction hash */\n hash: string;\n \n /** Amount spent (in wei/lamports) */\n amount: bigint;\n \n /** Human-readable amount */\n formattedAmount: string;\n \n /** Token symbol */\n tokenSymbol: string;\n \n /** Recipient address */\n recipient: string;\n \n /** Recipient display name (ENS, label, or truncated) */\n recipientDisplay: string;\n \n /** When the transaction occurred */\n timestamp: Date;\n \n /** Relative time (e.g., \"2h ago\") */\n relativeTime: string;\n \n /** Transaction type */\n type: 'transfer' | 'bridge' | 'execute';\n \n /** Whether this counted against daily limit */\n countedAgainstLimit: boolean;\n}\n\n/**\n * Daily spending summary\n */\nexport interface DailySpendingSummary {\n /** Date for this summary */\n date: Date;\n \n /** Total amount spent */\n totalSpent: bigint;\n \n /** Formatted total */\n formattedTotal: string;\n \n /** Number of transactions */\n transactionCount: number;\n \n /** Individual transactions */\n transactions: SpendingTransaction[];\n}\n\n// ============================================================================\n// Config Action Encoding\n// ============================================================================\n\n/**\n * Config types matching VeridexVault.sol\n */\nexport const CONFIG_TYPE = {\n /** Update daily limit */\n DAILY_LIMIT: 1,\n /** Pause/unpause vault */\n PAUSE: 2,\n /** Update guardians */\n GUARDIANS: 3,\n /** Register sender */\n REGISTER_SENDER: 4,\n /** Allow source chain */\n ALLOW_CHAIN: 5,\n /** Set query verifier */\n QUERY_VERIFIER: 6,\n} as const;\n\nexport type ConfigType = (typeof CONFIG_TYPE)[keyof typeof CONFIG_TYPE];\n\n// ============================================================================\n// Event Types\n// ============================================================================\n\n/**\n * Event emitted when spending limits change\n */\nexport interface SpendingLimitChangedEvent {\n /** Event type */\n type: 'daily_limit_changed' | 'transaction_limit_changed' | 'vault_paused' | 'vault_unpaused';\n \n /** Previous value */\n previousValue: bigint | boolean;\n \n /** New value */\n newValue: bigint | boolean;\n \n /** Transaction hash */\n txHash: string;\n \n /** Block timestamp */\n timestamp: Date;\n}\n\n/**\n * Callback for spending limit events\n */\nexport type SpendingLimitEventCallback = (event: SpendingLimitChangedEvent) => void;\n\n// ============================================================================\n// Preset Configurations\n// ============================================================================\n\n/**\n * Predefined spending limit configurations\n */\nexport interface LimitPreset {\n /** Preset identifier */\n id: string;\n \n /** Display name */\n name: string;\n \n /** Description */\n description: string;\n \n /** Daily limit suggestion (in USD equivalent) */\n dailyLimitUsd: number;\n \n /** Transaction limit suggestion (in USD equivalent) */\n transactionLimitUsd: number;\n \n /** Icon for UI */\n icon: string;\n \n /** Recommended for user type */\n recommendedFor: string;\n}\n\n/**\n * Standard limit presets\n */\nexport const LIMIT_PRESETS: LimitPreset[] = [\n {\n id: 'conservative',\n name: 'Conservative',\n description: 'Low limits for maximum security',\n dailyLimitUsd: 500,\n transactionLimitUsd: 100,\n icon: '🔒',\n recommendedFor: 'New users or high-value vaults',\n },\n {\n id: 'balanced',\n name: 'Balanced',\n description: 'Moderate limits for everyday use',\n dailyLimitUsd: 2500,\n transactionLimitUsd: 500,\n icon: '⚖️',\n recommendedFor: 'Regular users',\n },\n {\n id: 'generous',\n name: 'Generous',\n description: 'Higher limits for active traders',\n dailyLimitUsd: 10000,\n transactionLimitUsd: 2500,\n icon: '🚀',\n recommendedFor: 'Active traders and power users',\n },\n {\n id: 'unlimited',\n name: 'No Limits',\n description: 'No spending restrictions (not recommended)',\n dailyLimitUsd: 0, // 0 = unlimited\n transactionLimitUsd: 0,\n icon: '⚠️',\n recommendedFor: 'Advanced users who accept full risk',\n },\n];\n\n// ============================================================================\n// Utility Types\n// ============================================================================\n\n/**\n * Duration display for reset countdown\n */\nexport interface DurationDisplay {\n hours: number;\n minutes: number;\n seconds: number;\n formatted: string; // e.g., \"6h 23m\"\n}\n\n/**\n * Calculate duration display from milliseconds\n */\nexport function formatDuration(ms: number): DurationDisplay {\n const totalSeconds = Math.max(0, Math.floor(ms / 1000));\n const hours = Math.floor(totalSeconds / 3600);\n const minutes = Math.floor((totalSeconds % 3600) / 60);\n const seconds = totalSeconds % 60;\n \n let formatted: string;\n if (hours > 0) {\n formatted = `${hours}h ${minutes}m`;\n } else if (minutes > 0) {\n formatted = `${minutes}m ${seconds}s`;\n } else {\n formatted = `${seconds}s`;\n }\n \n return { hours, minutes, seconds, formatted };\n}\n\n/**\n * Calculate percentage safely (handles zero division)\n */\nexport function calculatePercentage(spent: bigint, limit: bigint): number {\n if (limit === 0n) return 0;\n // Use fixed-point math to avoid precision loss\n const percentage = Number((spent * 10000n) / limit) / 100;\n return Math.min(100, Math.max(0, percentage));\n}\n\n/**\n * Format large numbers with appropriate units\n */\nexport function formatLargeAmount(\n amount: bigint,\n decimals: number = 18,\n symbol: string = 'ETH'\n): string {\n const divisor = 10n ** BigInt(decimals);\n const whole = amount / divisor;\n const fraction = amount % divisor;\n \n // Format with up to 4 decimal places\n const fractionStr = fraction.toString().padStart(decimals, '0').slice(0, 4);\n const trimmedFraction = fractionStr.replace(/0+$/, '');\n \n const numStr = trimmedFraction \n ? `${whole.toLocaleString()}.${trimmedFraction}`\n : whole.toLocaleString();\n \n return `${numStr} ${symbol}`;\n}\n","import type { PasskeyManager, PasskeyCredential } from './PasskeyManager.js';\nimport type { WalletManager, ChainAddressConfig } from './WalletManager.js';\nimport type { ChainAddress, ChainClient, UnifiedIdentity } from './types.js';\nimport type { SessionKey } from '../types.js';\nimport { CHAIN_PRESETS, type ChainName, type NetworkType } from '../presets.js';\nimport {\n RelayerClient,\n type CredentialMetadataRecord,\n type RegisteredAppDetail,\n type RegisteredAppStatus,\n type RegisteredAppSummary,\n type RegisteredAppTrustLevel,\n type RelayerAppSession,\n} from './RelayerClient.js';\n\ntype RecoveryGuardiansResult = {\n guardians: string[];\n threshold: bigint;\n isConfigured: boolean;\n};\n\ntype RecoveryStatusResult = {\n isActive: boolean;\n newOwnerKeyHash: string;\n initiatedAt: bigint;\n approvalCount: bigint;\n threshold: bigint;\n canExecuteAt: bigint;\n expiresAt: bigint;\n};\n\ntype RecoveryCapableChain = ChainClient & {\n getGuardians(identityKeyHash: string): Promise<RecoveryGuardiansResult>;\n getRecoveryStatus(identityKeyHash: string): Promise<RecoveryStatusResult>;\n};\n\ntype OnchainSessionCapableChain = ChainClient & {\n getUserSessions(userKeyHash: string): Promise<SessionKey[]>;\n};\n\nexport interface PortabilityOverview {\n credential: PasskeyCredential;\n unifiedIdentity: UnifiedIdentity;\n supportedChainIdentity: UnifiedIdentity;\n localCredentialCount: number;\n remoteCredentials: CredentialMetadataRecord[];\n syncedCredentialCount: number;\n backupEligibleCount: number;\n backupBackedCount: number;\n rootCredentialCount: number;\n supportedChainCount: number;\n nonEvmAddressCount: number;\n}\n\nexport interface RecoveryOverview {\n identityKeyHash: string;\n guardians: string[];\n threshold: bigint;\n isConfigured: boolean;\n recovery: RecoveryStatusResult;\n}\n\nexport interface AccountManagerConfig {\n passkey: PasskeyManager;\n wallet: WalletManager;\n chain: ChainClient;\n relayer?: RelayerClient;\n testnet?: boolean;\n getUnifiedIdentity: () => Promise<UnifiedIdentity>;\n}\n\nfunction isRecoveryCapableChain(chain: ChainClient): chain is RecoveryCapableChain {\n return typeof (chain as RecoveryCapableChain).getGuardians === 'function'\n && typeof (chain as RecoveryCapableChain).getRecoveryStatus === 'function';\n}\n\nfunction isOnchainSessionCapableChain(chain: ChainClient): chain is OnchainSessionCapableChain {\n return typeof (chain as OnchainSessionCapableChain).getUserSessions === 'function';\n}\n\nexport class AccountManager {\n private readonly passkey: PasskeyManager;\n private readonly wallet: WalletManager;\n private readonly chain: ChainClient;\n private readonly relayer?: RelayerClient;\n private readonly network: NetworkType;\n private readonly getUnifiedIdentityImpl: () => Promise<UnifiedIdentity>;\n\n constructor(config: AccountManagerConfig) {\n this.passkey = config.passkey;\n this.wallet = config.wallet;\n this.chain = config.chain;\n this.relayer = config.relayer;\n this.network = config.testnet === false ? 'mainnet' : 'testnet';\n this.getUnifiedIdentityImpl = config.getUnifiedIdentity;\n }\n\n private requireCredential(): PasskeyCredential {\n const credential = this.passkey.getCredential();\n if (!credential) {\n throw new Error('No credential set. Call passkey.register() or passkey.authenticate() first.');\n }\n return credential;\n }\n\n private requireRelayer(): RelayerClient {\n if (!this.relayer) {\n throw new Error('Relayer integration is not configured for this SDK instance.');\n }\n return this.relayer;\n }\n\n async getPortabilityOverview(): Promise<PortabilityOverview> {\n const credential = this.requireCredential();\n const localCredentials = this.passkey.getAllStoredCredentials();\n const unifiedIdentity = await this.getUnifiedIdentityImpl();\n const supportedChainIdentity = await this.getSupportedChainIdentity();\n const remoteCredentials = this.relayer\n ? await this.relayer.listCredentialMetadata(credential.keyHash)\n : [];\n\n return {\n credential,\n unifiedIdentity,\n supportedChainIdentity,\n localCredentialCount: localCredentials.length,\n remoteCredentials,\n syncedCredentialCount: remoteCredentials.filter((item) => item.backupState === true).length,\n backupEligibleCount: remoteCredentials.filter((item) => item.backupEligible === true).length,\n backupBackedCount: remoteCredentials.filter((item) => item.backupState === true).length,\n rootCredentialCount: remoteCredentials.filter((item) => item.isRoot).length,\n supportedChainCount: supportedChainIdentity.addresses.length,\n nonEvmAddressCount: supportedChainIdentity.addresses.filter((item) => item.isEvm === false).length,\n };\n }\n\n async getSupportedChainIdentity(chainNames?: ChainName[]): Promise<UnifiedIdentity> {\n const credential = this.requireCredential();\n return this.wallet.getUnifiedIdentity(credential, this.buildChainAddressConfigMap(chainNames));\n }\n\n async getSupportedChainAddresses(chainNames?: ChainName[]): Promise<ChainAddress[]> {\n const identity = await this.getSupportedChainIdentity(chainNames);\n return identity.addresses;\n }\n\n async listCredentialMetadata(keyHash?: string): Promise<CredentialMetadataRecord[]> {\n const relayer = this.requireRelayer();\n const resolvedKeyHash = keyHash ?? this.requireCredential().keyHash;\n return relayer.listCredentialMetadata(resolvedKeyHash);\n }\n\n async getRecoveryOverview(identityKeyHash?: string): Promise<RecoveryOverview> {\n if (!isRecoveryCapableChain(this.chain)) {\n throw new Error('The configured chain client does not support recovery queries.');\n }\n\n const resolvedKeyHash = identityKeyHash ?? this.requireCredential().keyHash;\n const [guardians, recovery] = await Promise.all([\n this.chain.getGuardians(resolvedKeyHash),\n this.chain.getRecoveryStatus(resolvedKeyHash),\n ]);\n\n return {\n identityKeyHash: resolvedKeyHash,\n guardians: guardians.guardians,\n threshold: guardians.threshold,\n isConfigured: guardians.isConfigured,\n recovery,\n };\n }\n\n async getOnchainSessions(identityKeyHash?: string): Promise<SessionKey[]> {\n if (!isOnchainSessionCapableChain(this.chain)) {\n throw new Error('The configured chain client does not support on-chain session queries.');\n }\n\n const resolvedKeyHash = identityKeyHash ?? this.requireCredential().keyHash;\n return this.chain.getUserSessions(resolvedKeyHash);\n }\n\n async listApps(): Promise<RegisteredAppSummary[]> {\n return this.requireRelayer().listApps();\n }\n\n async getApp(appId: string): Promise<RegisteredAppDetail> {\n return this.requireRelayer().getApp(appId);\n }\n\n async updateAppStatus(appId: string, status: RegisteredAppStatus): Promise<void> {\n await this.requireRelayer().updateAppStatus(appId, status);\n }\n\n async updateAppTrustLevel(appId: string, trustLevel: RegisteredAppTrustLevel): Promise<void> {\n await this.requireRelayer().updateAppTrustLevel(appId, trustLevel);\n }\n\n async listAppSessions(appId: string, options?: { includeRevoked?: boolean }): Promise<RelayerAppSession[]> {\n return this.requireRelayer().listAppSessions(appId, options);\n }\n\n async revokeAppSession(appId: string, sessionId: string): Promise<number> {\n return this.requireRelayer().revokeAppSessions(appId, sessionId);\n }\n\n async revokeAllAppSessions(appId: string): Promise<number> {\n return this.requireRelayer().revokeAppSessions(appId);\n }\n\n private buildChainAddressConfigMap(chainNames?: ChainName[]): Map<number, ChainAddressConfig> {\n const names = chainNames ?? (Object.keys(CHAIN_PRESETS) as ChainName[]);\n const chainConfigs = new Map<number, ChainAddressConfig>();\n\n for (const chainName of names) {\n const preset = CHAIN_PRESETS[chainName];\n const networkConfig = preset[this.network];\n\n chainConfigs.set(networkConfig.wormholeChainId, {\n chainName: preset.displayName,\n isEvm: preset.type === 'evm',\n factoryAddress: networkConfig.contracts?.vaultFactory,\n implementationAddress: networkConfig.contracts?.vaultImplementation,\n });\n }\n\n return chainConfigs;\n }\n}","/**\n * Veridex Protocol SDK — Recovery Manager\n *\n * Orchestrates the full guardian-based social recovery lifecycle on top of the\n * low-level EVMClient methods. Provides a high-level, ergonomic API for:\n *\n * 1. Guardian configuration (setup / add / remove)\n * 2. Recovery initiation (initiateRecovery — called from a guardian device)\n * 3. Approval collection (approveRecovery — each guardian signs)\n * 4. Execution (executeRecovery — permissionless after threshold + timelock)\n * 5. Cancellation (cancelRecovery — by the current owner)\n * 6. Status monitoring (readiness, state, approvals)\n *\n * Design rationale\n * ────────────────\n * • All mutating operations require a WebAuthn signature and an on-chain signer\n * (ethers.Signer). The SDK never holds private-key material — ADR-0040.\n * • The manager delegates on-chain calls to the provided ChainClient, which must\n * implement {@link RecoveryCapableChainClient}. At runtime this is checked via\n * duck-typing so non-EVM chains that lack recovery simply throw clearly.\n * • Cross-chain propagation of recovery results (new-owner VAA) is out of scope\n * for this manager; it is handled by the relayer once the Hub emits the VAA.\n *\n * @module RecoveryManager\n */\n\nimport type { PasskeyManager } from './PasskeyManager.js';\nimport type {\n ChainClient,\n WebAuthnSignature,\n\n} from './types.js';\n\n// ============================================================================\n// Recovery-capable chain detection\n// ============================================================================\n\n/**\n * Subset of ChainClient that supports the guardian / recovery contract surface.\n * EVMClient satisfies this; non-EVM clients currently do not.\n */\nexport interface RecoveryCapableChainClient extends ChainClient {\n getGuardians(identityKeyHash: string): Promise<GuardiansResult>;\n getRecoveryStatus(identityKeyHash: string): Promise<RecoveryStatusResult>;\n hasGuardianApproved(identityKeyHash: string, guardianKeyHash: string): Promise<boolean>;\n setupGuardians(\n signature: WebAuthnSignature,\n publicKeyX: bigint,\n publicKeyY: bigint,\n guardians: string[],\n threshold: bigint,\n signer: unknown,\n ): Promise<{ receipt: unknown; sequence: bigint }>;\n addGuardian(\n signature: WebAuthnSignature,\n publicKeyX: bigint,\n publicKeyY: bigint,\n guardianKeyHash: string,\n signer: unknown,\n ): Promise<{ receipt: unknown; sequence: bigint }>;\n removeGuardian(\n signature: WebAuthnSignature,\n publicKeyX: bigint,\n publicKeyY: bigint,\n guardianKeyHash: string,\n signer: unknown,\n ): Promise<{ receipt: unknown; sequence: bigint }>;\n initiateRecovery(\n signature: WebAuthnSignature,\n publicKeyX: bigint,\n publicKeyY: bigint,\n identityToRecover: string,\n newOwnerKeyHash: string,\n signer: unknown,\n ): Promise<{ receipt: unknown; sequence: bigint }>;\n approveRecovery(\n signature: WebAuthnSignature,\n publicKeyX: bigint,\n publicKeyY: bigint,\n identityToRecover: string,\n signer: unknown,\n ): Promise<{ receipt: unknown; sequence: bigint }>;\n executeRecovery(\n identityToRecover: string,\n newPublicKeyX: bigint,\n newPublicKeyY: bigint,\n signer: unknown,\n ): Promise<{ receipt: unknown; sequence: bigint }>;\n cancelRecovery(\n signature: WebAuthnSignature,\n publicKeyX: bigint,\n publicKeyY: bigint,\n signer: unknown,\n ): Promise<{ receipt: unknown; sequence: bigint }>;\n}\n\n// ============================================================================\n// Public types\n// ============================================================================\n\nexport interface GuardiansResult {\n guardians: string[];\n threshold: bigint;\n isConfigured: boolean;\n}\n\nexport interface RecoveryStatusResult {\n isActive: boolean;\n newOwnerKeyHash: string;\n initiatedAt: bigint;\n approvalCount: bigint;\n threshold: bigint;\n canExecuteAt: bigint;\n expiresAt: bigint;\n}\n\nexport interface RecoveryReadiness {\n /** Whether at least one guardian is configured */\n guardiansConfigured: boolean;\n /** Number of guardians */\n guardianCount: number;\n /** Required approval count */\n threshold: bigint;\n /** Whether a recovery is currently in progress */\n recoveryInProgress: boolean;\n /** If in progress, whether it can be executed now */\n canExecuteNow: boolean;\n /** If in progress, whether it has expired */\n isExpired: boolean;\n /** If in progress, how many more approvals are needed (0 when ready) */\n approvalsRemaining: number;\n /** Full recovery status if active */\n recoveryStatus: RecoveryStatusResult | null;\n /** List of guardian key hashes */\n guardians: string[];\n}\n\nexport interface SetupGuardiansParams {\n /** WebAuthn assertion for the operation */\n signature: WebAuthnSignature;\n /** Guardian key hashes to set */\n guardians: string[];\n /** Approval threshold (must be >= 1 and <= guardians.length) */\n threshold: number;\n /** Ethers signer to submit the transaction */\n signer: unknown;\n}\n\nexport interface AddGuardianParams {\n signature: WebAuthnSignature;\n guardianKeyHash: string;\n signer: unknown;\n}\n\nexport interface RemoveGuardianParams {\n signature: WebAuthnSignature;\n guardianKeyHash: string;\n signer: unknown;\n}\n\nexport interface InitiateRecoveryParams {\n signature: WebAuthnSignature;\n /** Identity key hash to recover */\n identityToRecover: string;\n /** New owner key hash that will replace the old one */\n newOwnerKeyHash: string;\n signer: unknown;\n}\n\nexport interface ApproveRecoveryParams {\n signature: WebAuthnSignature;\n identityToRecover: string;\n signer: unknown;\n}\n\nexport interface ExecuteRecoveryParams {\n identityToRecover: string;\n /** The new owner's P-256 public key X coordinate */\n newPublicKeyX: bigint;\n /** The new owner's P-256 public key Y coordinate */\n newPublicKeyY: bigint;\n signer: unknown;\n}\n\nexport interface CancelRecoveryParams {\n signature: WebAuthnSignature;\n signer: unknown;\n}\n\nexport interface RecoveryManagerConfig {\n passkey: PasskeyManager;\n chain: ChainClient;\n}\n\n// ============================================================================\n// RecoveryManager\n// ============================================================================\n\nexport class RecoveryManager {\n private readonly passkey: PasskeyManager;\n private readonly chain: RecoveryCapableChainClient;\n\n constructor(config: RecoveryManagerConfig) {\n this.passkey = config.passkey;\n\n if (!isRecoveryCapable(config.chain)) {\n throw new Error(\n 'RecoveryManager requires a chain client that supports guardian and recovery methods. ' +\n 'Currently only EVMClient implements RecoveryCapableChainClient.',\n );\n }\n this.chain = config.chain;\n }\n\n // ────────────────────────────────────────────────────────────────────────\n // Queries\n // ────────────────────────────────────────────────────────────────────────\n\n /**\n * Get full recovery readiness — combines guardian config and recovery state\n * into a single, user-friendly view.\n */\n async getReadiness(identityKeyHash?: string): Promise<RecoveryReadiness> {\n const keyHash = identityKeyHash ?? this.requireCredential().keyHash;\n\n const [guardians, status] = await Promise.all([\n this.chain.getGuardians(keyHash),\n this.chain.getRecoveryStatus(keyHash),\n ]);\n\n const nowSec = BigInt(Math.floor(Date.now() / 1000));\n const canExecuteNow = status.isActive\n && status.approvalCount >= status.threshold\n && nowSec >= status.canExecuteAt\n && nowSec < status.expiresAt;\n const isExpired = status.isActive && nowSec >= status.expiresAt;\n const approvalsRemaining = status.isActive\n ? Math.max(0, Number(status.threshold - status.approvalCount))\n : 0;\n\n return {\n guardiansConfigured: guardians.isConfigured,\n guardianCount: guardians.guardians.length,\n threshold: guardians.threshold,\n recoveryInProgress: status.isActive,\n canExecuteNow,\n isExpired,\n approvalsRemaining,\n recoveryStatus: status.isActive ? status : null,\n guardians: guardians.guardians,\n };\n }\n\n /**\n * Check whether a specific guardian has already approved the active recovery.\n */\n async hasGuardianApproved(\n identityKeyHash: string,\n guardianKeyHash: string,\n ): Promise<boolean> {\n return this.chain.hasGuardianApproved(identityKeyHash, guardianKeyHash);\n }\n\n /**\n * Get the raw guardian configuration for a given identity.\n */\n async getGuardians(identityKeyHash?: string): Promise<GuardiansResult> {\n const keyHash = identityKeyHash ?? this.requireCredential().keyHash;\n return this.chain.getGuardians(keyHash);\n }\n\n /**\n * Get the raw recovery status for a given identity.\n */\n async getRecoveryStatus(identityKeyHash?: string): Promise<RecoveryStatusResult> {\n const keyHash = identityKeyHash ?? this.requireCredential().keyHash;\n return this.chain.getRecoveryStatus(keyHash);\n }\n\n // ────────────────────────────────────────────────────────────────────────\n // Mutations\n // ────────────────────────────────────────────────────────────────────────\n\n /**\n * Configure the guardian set and approval threshold for the current identity.\n *\n * @throws If threshold < 1 or threshold > guardians.length\n */\n async setupGuardians(params: SetupGuardiansParams): Promise<{ sequence: bigint }> {\n const { signature, guardians, threshold, signer } = params;\n\n if (threshold < 1 || threshold > guardians.length) {\n throw new Error(\n `Invalid threshold ${threshold}: must be between 1 and ${guardians.length} (guardian count).`,\n );\n }\n\n const credential = this.requireCredential();\n const result = await this.chain.setupGuardians(\n signature,\n credential.publicKeyX,\n credential.publicKeyY,\n guardians,\n BigInt(threshold),\n signer,\n );\n return { sequence: result.sequence };\n }\n\n /**\n * Add a single guardian to the current identity's guardian set.\n */\n async addGuardian(params: AddGuardianParams): Promise<{ sequence: bigint }> {\n const credential = this.requireCredential();\n const result = await this.chain.addGuardian(\n params.signature,\n credential.publicKeyX,\n credential.publicKeyY,\n params.guardianKeyHash,\n params.signer,\n );\n return { sequence: result.sequence };\n }\n\n /**\n * Remove a guardian from the current identity's guardian set.\n */\n async removeGuardian(params: RemoveGuardianParams): Promise<{ sequence: bigint }> {\n const credential = this.requireCredential();\n const result = await this.chain.removeGuardian(\n params.signature,\n credential.publicKeyX,\n credential.publicKeyY,\n params.guardianKeyHash,\n params.signer,\n );\n return { sequence: result.sequence };\n }\n\n /**\n * Initiate social recovery — typically called from a guardian's device.\n *\n * The caller must be a guardian of the identity being recovered.\n */\n async initiateRecovery(params: InitiateRecoveryParams): Promise<{ sequence: bigint }> {\n const credential = this.requireCredential();\n const result = await this.chain.initiateRecovery(\n params.signature,\n credential.publicKeyX,\n credential.publicKeyY,\n params.identityToRecover,\n params.newOwnerKeyHash,\n params.signer,\n );\n return { sequence: result.sequence };\n }\n\n /**\n * Approve an in-progress recovery — each guardian calls this once.\n */\n async approveRecovery(params: ApproveRecoveryParams): Promise<{ sequence: bigint }> {\n const credential = this.requireCredential();\n const result = await this.chain.approveRecovery(\n params.signature,\n credential.publicKeyX,\n credential.publicKeyY,\n params.identityToRecover,\n params.signer,\n );\n return { sequence: result.sequence };\n }\n\n /**\n * Execute a recovery after threshold + timelock are satisfied.\n *\n * This is permissionless — anyone may call it. No WebAuthn signature required.\n */\n async executeRecovery(params: ExecuteRecoveryParams): Promise<{ sequence: bigint }> {\n const result = await this.chain.executeRecovery(\n params.identityToRecover,\n params.newPublicKeyX,\n params.newPublicKeyY,\n params.signer,\n );\n return { sequence: result.sequence };\n }\n\n /**\n * Cancel an in-progress recovery — only the current owner can do this.\n */\n async cancelRecovery(params: CancelRecoveryParams): Promise<{ sequence: bigint }> {\n const credential = this.requireCredential();\n const result = await this.chain.cancelRecovery(\n params.signature,\n credential.publicKeyX,\n credential.publicKeyY,\n params.signer,\n );\n return { sequence: result.sequence };\n }\n\n // ────────────────────────────────────────────────────────────────────────\n // Internal helpers\n // ────────────────────────────────────────────────────────────────────────\n\n private requireCredential() {\n const credential = this.passkey.getCredential();\n if (!credential) {\n throw new Error(\n 'No credential set. Call passkey.register() or passkey.authenticate() first.',\n );\n }\n return credential;\n }\n}\n\n// ============================================================================\n// Runtime type guard\n// ============================================================================\n\nfunction isRecoveryCapable(chain: ChainClient): chain is RecoveryCapableChainClient {\n const c = chain as Partial<RecoveryCapableChainClient>;\n return (\n typeof c.getGuardians === 'function' &&\n typeof c.getRecoveryStatus === 'function' &&\n typeof c.hasGuardianApproved === 'function' &&\n typeof c.setupGuardians === 'function' &&\n typeof c.initiateRecovery === 'function' &&\n typeof c.approveRecovery === 'function' &&\n typeof c.executeRecovery === 'function' &&\n typeof c.cancelRecovery === 'function'\n );\n}\n","/**\n * Veridex Protocol SDK — Multisig Manager (ADR-0037)\n *\n * Implements the SDK surface for **threshold multisig transaction authorization**.\n *\n * Architecture summary (from ADR-0037):\n * ─────────────────────────────────────\n * • A per-identity **TransactionPolicy** on the Hub defines whether threshold\n * approval is required. When `policy.enabled === true`, direct dispatch of\n * protected actions (transfer, execute, bridge, config) reverts on-chain.\n * • Instead, an authorized key **creates a proposal**. Other authorized keys\n * **approve** it. Once `approvalCount >= threshold`, anyone may **execute** it.\n * • Sessions are disabled for threshold-governed identities in Phase 1.\n * • Proposals expire after `proposalTtl`.\n * • Execution emits a Wormhole VAA wrapping the inner action\n * (ACTION_EXECUTE_MULTISIG = 14).\n *\n * This manager exposes:\n * 1. Policy configuration & queries\n * 2. Proposal lifecycle (create / approve / cancel / execute / query)\n * 3. Convenience proposal creators for transfer, execute, bridge\n * 4. Policy-aware guard for direct dispatch (`assertDirectDispatchAllowed`)\n *\n * @module MultisigManager\n */\n\nimport type { PasskeyManager } from './PasskeyManager.js';\nimport type {\n ChainClient,\n WebAuthnSignature,\n TransferParams,\n ExecuteParams,\n BridgeParams,\n DispatchResult,\n} from './types.js';\n\n// ============================================================================\n// Multisig types (ADR-0037 §3, §4, §11)\n// ============================================================================\n\n/** Phase 1 action type bitmask values (ADR-0037 §2) */\nexport const PROTECTED_ACTION = {\n TRANSFER: 1 << 0,\n EXECUTE: 1 << 1,\n BRIDGE: 1 << 2,\n CONFIG: 1 << 3,\n} as const;\n\n/** Default protected-action mask covering all sensitive operations */\nexport const DEFAULT_PROTECTED_ACTION_MASK =\n PROTECTED_ACTION.TRANSFER |\n PROTECTED_ACTION.EXECUTE |\n PROTECTED_ACTION.BRIDGE |\n PROTECTED_ACTION.CONFIG;\n\n/** Default proposal TTL in seconds (24 hours) */\nexport const DEFAULT_PROPOSAL_TTL = 86_400;\n\nexport type ProposalState =\n | 'none'\n | 'pending'\n | 'approved'\n | 'executed'\n | 'cancelled'\n | 'expired';\n\n/**\n * Per-identity transaction policy stored on-chain (Hub).\n */\nexport interface MultisigPolicy {\n enabled: boolean;\n threshold: number;\n protectedActionMask: number;\n proposalTtl: number;\n disableSessions: boolean;\n}\n\n/**\n * On-chain transaction proposal.\n */\nexport interface TransactionProposal {\n proposalId: string;\n identityKeyHash: string;\n proposerKeyHash: string;\n targetChain: number;\n actionType: number;\n actionHash: string;\n actionPayload: string;\n createdAt: bigint;\n expiresAt: bigint;\n approvalCount: number;\n requiredThreshold: number;\n state: ProposalState;\n}\n\n/**\n * Human-readable summary of a proposal's action payload.\n */\nexport interface ProposalActionSummary {\n type: 'transfer' | 'execute' | 'bridge' | 'config' | 'unknown';\n description: string;\n targetChain: number;\n /** Decoded parameters — shape depends on `type` */\n params: TransferParams | ExecuteParams | BridgeParams | Record<string, unknown>;\n}\n\nexport interface CreateProposalResult {\n proposalId: string;\n sequence: bigint;\n summary: ProposalActionSummary;\n}\n\nexport interface ApproveProposalResult {\n proposalId: string;\n approvalCount: number;\n thresholdReached: boolean;\n}\n\nexport interface ExecuteProposalResult {\n proposalId: string;\n sequence: bigint;\n dispatch: DispatchResult;\n}\n\n// ============================================================================\n// Multisig-capable chain detection\n// ============================================================================\n\n/**\n * Chain client methods required for threshold multisig.\n * In Phase 1 these exist only on EVMClient (Hub chain).\n */\nexport interface MultisigCapableChainClient extends ChainClient {\n configureTransactionPolicy(\n signature: WebAuthnSignature,\n publicKeyX: bigint,\n publicKeyY: bigint,\n threshold: number,\n protectedActionMask: number,\n proposalTtl: number,\n disableSessions: boolean,\n signer: unknown,\n ): Promise<{ receipt: unknown }>;\n\n getTransactionPolicy(identityKeyHash: string): Promise<MultisigPolicy>;\n\n createTransactionProposal(\n signature: WebAuthnSignature,\n publicKeyX: bigint,\n publicKeyY: bigint,\n targetChain: number,\n actionPayload: string,\n signer: unknown,\n ): Promise<{ proposalId: string; receipt: unknown; sequence: bigint }>;\n\n approveTransactionProposal(\n signature: WebAuthnSignature,\n publicKeyX: bigint,\n publicKeyY: bigint,\n proposalId: string,\n signer: unknown,\n ): Promise<{ receipt: unknown; approvalCount: number; thresholdReached: boolean }>;\n\n cancelTransactionProposal(\n signature: WebAuthnSignature,\n publicKeyX: bigint,\n publicKeyY: bigint,\n proposalId: string,\n signer: unknown,\n ): Promise<{ receipt: unknown }>;\n\n executeTransactionProposal(\n proposalId: string,\n signer: unknown,\n ): Promise<{ receipt: unknown; sequence: bigint }>;\n\n getTransactionProposal(proposalId: string): Promise<TransactionProposal>;\n\n hasApprovedTransactionProposal(\n proposalId: string,\n keyHash: string,\n ): Promise<boolean>;\n}\n\n// ============================================================================\n// Configuration\n// ============================================================================\n\nexport interface MultisigManagerConfig {\n passkey: PasskeyManager;\n chain: ChainClient;\n}\n\nexport interface ConfigurePolicyParams {\n signature: WebAuthnSignature;\n threshold: number;\n protectedActionMask?: number;\n proposalTtl?: number;\n disableSessions?: boolean;\n signer: unknown;\n}\n\nexport interface CreateProposalParams {\n signature: WebAuthnSignature;\n targetChain: number;\n actionPayload: string;\n signer: unknown;\n}\n\nexport interface ApproveProposalParams {\n signature: WebAuthnSignature;\n proposalId: string;\n signer: unknown;\n}\n\nexport interface CancelProposalParams {\n signature: WebAuthnSignature;\n proposalId: string;\n signer: unknown;\n}\n\nexport interface ExecuteProposalParams {\n proposalId: string;\n signer: unknown;\n}\n\n// ============================================================================\n// MultisigManager\n// ============================================================================\n\nexport class MultisigManager {\n private readonly passkey: PasskeyManager;\n private readonly chain: MultisigCapableChainClient;\n\n constructor(config: MultisigManagerConfig) {\n this.passkey = config.passkey;\n\n if (!isMultisigCapable(config.chain)) {\n throw new Error(\n 'MultisigManager requires a chain client that supports threshold multisig. ' +\n 'Ensure your EVMClient implements the ADR-0037 contract extensions.',\n );\n }\n this.chain = config.chain;\n }\n\n // ────────────────────────────────────────────────────────────────────────\n // Policy\n // ────────────────────────────────────────────────────────────────────────\n\n /**\n * Query the current transaction policy for the active identity.\n */\n async getPolicy(identityKeyHash?: string): Promise<MultisigPolicy> {\n const keyHash = identityKeyHash ?? this.requireCredential().keyHash;\n return this.chain.getTransactionPolicy(keyHash);\n }\n\n /**\n * Configure (or update) the transaction policy for the current identity.\n *\n * @throws If threshold < 2\n */\n async configurePolicy(params: ConfigurePolicyParams): Promise<void> {\n const { signature, threshold, signer } = params;\n const protectedActionMask = params.protectedActionMask ?? DEFAULT_PROTECTED_ACTION_MASK;\n const proposalTtl = params.proposalTtl ?? DEFAULT_PROPOSAL_TTL;\n const disableSessions = params.disableSessions ?? true;\n\n if (threshold < 2) {\n throw new Error(\n `Threshold must be >= 2 for multisig policy. Got ${threshold}.`,\n );\n }\n\n const credential = this.requireCredential();\n await this.chain.configureTransactionPolicy(\n signature,\n credential.publicKeyX,\n credential.publicKeyY,\n threshold,\n protectedActionMask,\n proposalTtl,\n disableSessions,\n signer,\n );\n }\n\n /**\n * Check whether direct (single-signer) dispatch is allowed for the given\n * action type under the current policy. Throws a descriptive error when\n * threshold approval is required instead.\n *\n * Call this before `sdk.transfer()` / `sdk.execute()` / `sdk.bridge()`\n * to fail fast in the SDK rather than reverting on-chain.\n */\n async assertDirectDispatchAllowed(\n actionType: 'transfer' | 'execute' | 'bridge' | 'config',\n identityKeyHash?: string,\n ): Promise<void> {\n const keyHash = identityKeyHash ?? this.requireCredential().keyHash;\n const policy = await this.chain.getTransactionPolicy(keyHash);\n\n if (!policy.enabled) return; // single-signer is fine\n\n const bit = actionTypeToBit(actionType);\n if ((policy.protectedActionMask & bit) !== 0) {\n throw new Error(\n `Direct dispatch of \"${actionType}\" is not allowed: identity ${keyHash} ` +\n `requires threshold multisig approval (threshold=${policy.threshold}). ` +\n 'Use sdk.multisig.createProposal() instead.',\n );\n }\n }\n\n // ────────────────────────────────────────────────────────────────────────\n // Proposal lifecycle\n // ────────────────────────────────────────────────────────────────────────\n\n /**\n * Create a new transaction proposal.\n *\n * The proposer's signature counts as the first approval automatically.\n */\n async createProposal(params: CreateProposalParams): Promise<CreateProposalResult> {\n const credential = this.requireCredential();\n const result = await this.chain.createTransactionProposal(\n params.signature,\n credential.publicKeyX,\n credential.publicKeyY,\n params.targetChain,\n params.actionPayload,\n params.signer,\n );\n\n const summary = decodeActionSummary(params.targetChain, params.actionPayload);\n\n return {\n proposalId: result.proposalId,\n sequence: result.sequence,\n summary,\n };\n }\n\n /**\n * Approve an existing proposal. Each authorized key may approve once.\n */\n async approveProposal(params: ApproveProposalParams): Promise<ApproveProposalResult> {\n const credential = this.requireCredential();\n const result = await this.chain.approveTransactionProposal(\n params.signature,\n credential.publicKeyX,\n credential.publicKeyY,\n params.proposalId,\n params.signer,\n );\n return {\n proposalId: params.proposalId,\n approvalCount: result.approvalCount,\n thresholdReached: result.thresholdReached,\n };\n }\n\n /**\n * Cancel a proposal — only allowed by an authorized key of the identity.\n */\n async cancelProposal(params: CancelProposalParams): Promise<void> {\n const credential = this.requireCredential();\n await this.chain.cancelTransactionProposal(\n params.signature,\n credential.publicKeyX,\n credential.publicKeyY,\n params.proposalId,\n params.signer,\n );\n }\n\n /**\n * Execute a proposal after threshold + timelock are satisfied.\n * Permissionless — anyone may call.\n */\n async executeProposal(params: ExecuteProposalParams): Promise<ExecuteProposalResult> {\n const result = await this.chain.executeTransactionProposal(\n params.proposalId,\n params.signer,\n );\n return {\n proposalId: params.proposalId,\n sequence: result.sequence,\n dispatch: {\n transactionHash: '', // filled by chain client\n sequence: result.sequence,\n userKeyHash: '',\n targetChain: 0,\n },\n };\n }\n\n // ────────────────────────────────────────────────────────────────────────\n // Queries\n // ────────────────────────────────────────────────────────────────────────\n\n /**\n * Retrieve a proposal by ID.\n */\n async getProposal(proposalId: string): Promise<TransactionProposal> {\n return this.chain.getTransactionProposal(proposalId);\n }\n\n /**\n * Check whether a specific key has approved a given proposal.\n */\n async hasApproved(proposalId: string, keyHash?: string): Promise<boolean> {\n const resolvedKeyHash = keyHash ?? this.requireCredential().keyHash;\n return this.chain.hasApprovedTransactionProposal(proposalId, resolvedKeyHash);\n }\n\n /**\n * Convenience: check if a proposal is ready for execution.\n */\n async isProposalExecutable(proposalId: string): Promise<boolean> {\n const proposal = await this.getProposal(proposalId);\n if (proposal.state !== 'pending' && proposal.state !== 'approved') return false;\n\n const nowSec = BigInt(Math.floor(Date.now() / 1000));\n return (\n proposal.approvalCount >= proposal.requiredThreshold &&\n nowSec < proposal.expiresAt\n );\n }\n\n // ────────────────────────────────────────────────────────────────────────\n // Internal\n // ────────────────────────────────────────────────────────────────────────\n\n private requireCredential() {\n const credential = this.passkey.getCredential();\n if (!credential) {\n throw new Error(\n 'No credential set. Call passkey.register() or passkey.authenticate() first.',\n );\n }\n return credential;\n }\n}\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\nfunction isMultisigCapable(chain: ChainClient): chain is MultisigCapableChainClient {\n const c = chain as Partial<MultisigCapableChainClient>;\n return (\n typeof c.configureTransactionPolicy === 'function' &&\n typeof c.getTransactionPolicy === 'function' &&\n typeof c.createTransactionProposal === 'function' &&\n typeof c.approveTransactionProposal === 'function' &&\n typeof c.cancelTransactionProposal === 'function' &&\n typeof c.executeTransactionProposal === 'function' &&\n typeof c.getTransactionProposal === 'function' &&\n typeof c.hasApprovedTransactionProposal === 'function'\n );\n}\n\nfunction actionTypeToBit(type: 'transfer' | 'execute' | 'bridge' | 'config'): number {\n switch (type) {\n case 'transfer': return PROTECTED_ACTION.TRANSFER;\n case 'execute': return PROTECTED_ACTION.EXECUTE;\n case 'bridge': return PROTECTED_ACTION.BRIDGE;\n case 'config': return PROTECTED_ACTION.CONFIG;\n }\n}\n\n/**\n * Best-effort decode of an action payload for human-readable display.\n * Falls back to an opaque summary if decoding fails.\n */\nfunction decodeActionSummary(targetChain: number, actionPayload: string): ProposalActionSummary {\n // Action payloads are ABI-encoded with a leading action-type byte.\n // We attempt a lightweight decode here; full parsing is done by\n // TransactionParser if the integrator wants richer display.\n try {\n const bytes = hexToBytes(actionPayload);\n if (bytes.length === 0) {\n return { type: 'unknown', description: 'Empty payload', targetChain, params: {} };\n }\n\n const actionByte = bytes[0];\n switch (actionByte) {\n case 1: return { type: 'transfer', description: 'Token transfer', targetChain, params: {} as TransferParams };\n case 2: return { type: 'execute', description: 'Contract execution', targetChain, params: {} as ExecuteParams };\n case 3: return { type: 'bridge', description: 'Cross-chain bridge', targetChain, params: {} as BridgeParams };\n case 4: return { type: 'config', description: 'Configuration change', targetChain, params: {} };\n default: return { type: 'unknown', description: `Action type ${actionByte}`, targetChain, params: {} };\n }\n } catch {\n return { type: 'unknown', description: 'Unable to decode payload', targetChain, params: {} };\n }\n}\n\nfunction hexToBytes(hex: string): Uint8Array {\n const clean = hex.startsWith('0x') ? hex.slice(2) : hex;\n if (clean.length === 0) return new Uint8Array(0);\n const bytes = new Uint8Array(clean.length / 2);\n for (let i = 0; i < bytes.length; i++) {\n bytes[i] = parseInt(clean.substring(i * 2, i * 2 + 2), 16);\n }\n return bytes;\n}\n","/**\n * Veridex Protocol SDK — Launch Gate & Policy Enforcement (ADR-0040)\n *\n * Runtime validation layer that enforces the product boundaries defined in\n * ADR-0040 across the SDK surface. Every SDK operation that touches\n * credentials, sessions, or dispatch is funnelled through this module's\n * `validate*` helpers to catch violations early with clear developer errors.\n *\n * Non-negotiables enforced here:\n *\n * 1. Passkeys are non-extractable. No API may expose private-key material.\n * 2. Self-custody is preserved. The SDK never constructs or transmits\n * private keys.\n * 3. Cross-site passkey reuse is scoped to the Veridex RP federation model.\n * 4. Cross-ecosystem portability requires explicit credential registration.\n * 5. MetaMask interop is limited to smart-account / injected-wallet flows.\n * 6. Chain parity claims require real cryptographic verification.\n *\n * Additionally this module exposes a lightweight **CapabilityMatrix** that\n * integrators can use to understand what is available on a given platform,\n * browser, and chain combination — preventing false assumptions at the UI\n * level.\n *\n * @module PolicyEnforcement\n */\n\n// ============================================================================\n// Product boundary constants\n// ============================================================================\n\n/**\n * Capability tiers per chain type — used to gate SDK features at runtime.\n */\nexport type ChainCapabilityTier = 'full' | 'partial' | 'unsupported';\n\nexport interface ChainCapabilities {\n /** WebAuthn P-256 verification on-chain */\n passkeyVerification: ChainCapabilityTier;\n /** On-chain session key registration and validation */\n sessionKeys: ChainCapabilityTier;\n /** Guardian recovery initiation, approval, execution */\n recovery: ChainCapabilityTier;\n /** Threshold multisig (ADR-0037) */\n multisig: ChainCapabilityTier;\n /** Cross-chain VAA reception (Wormhole spoke) */\n crossChainReceive: ChainCapabilityTier;\n}\n\n/**\n * Canonical capability definitions per chain type.\n * These are validated before claiming \"supported\" status.\n */\nexport const CHAIN_CAPABILITIES: Record<string, ChainCapabilities> = {\n evm: {\n passkeyVerification: 'full',\n sessionKeys: 'full',\n recovery: 'full',\n multisig: 'full',\n crossChainReceive: 'full',\n },\n avalanche: {\n passkeyVerification: 'full', // ACP-204 native P-256\n sessionKeys: 'full',\n recovery: 'full',\n multisig: 'full',\n crossChainReceive: 'full',\n },\n solana: {\n passkeyVerification: 'partial', // via precompile / verifier program\n sessionKeys: 'partial',\n recovery: 'unsupported',\n multisig: 'unsupported',\n crossChainReceive: 'full',\n },\n aptos: {\n passkeyVerification: 'partial',\n sessionKeys: 'partial',\n recovery: 'unsupported',\n multisig: 'unsupported',\n crossChainReceive: 'full',\n },\n sui: {\n passkeyVerification: 'partial',\n sessionKeys: 'partial',\n recovery: 'unsupported',\n multisig: 'unsupported',\n crossChainReceive: 'full',\n },\n starknet: {\n passkeyVerification: 'partial',\n sessionKeys: 'unsupported',\n recovery: 'unsupported',\n multisig: 'unsupported',\n crossChainReceive: 'partial',\n },\n stacks: {\n passkeyVerification: 'partial',\n sessionKeys: 'partial',\n recovery: 'unsupported',\n multisig: 'unsupported',\n crossChainReceive: 'partial',\n },\n};\n\n// ============================================================================\n// Validation helpers\n// ============================================================================\n\n/**\n * Prevent any code path that would attempt to export or derive private keys\n * from passkey material (ADR-0040, Non-Negotiable #1).\n */\nexport function validateNoKeyExtraction(operation: string): void {\n const forbidden = [\n 'exportPrivateKey', 'derivePrivateKey', 'getMnemonic',\n 'getSeedPhrase', 'getKeystore', 'extractKey',\n 'exportSeed', 'deriveSeed', 'getEntropy',\n ];\n const lower = operation.toLowerCase();\n for (const keyword of forbidden) {\n if (lower.includes(keyword.toLowerCase())) {\n throw new PolicyViolationError(\n `Operation \"${operation}\" violates Veridex security policy: ` +\n 'passkey credentials are non-extractable WebAuthn keys and cannot be ' +\n 'exported as private keys, mnemonics, or keystore files.',\n 'NON_EXTRACTABLE_CREDENTIAL',\n );\n }\n }\n}\n\n/**\n * Validate that a chain has real (not placeholder) support for a capability\n * before claiming it is available (ADR-0040, Non-Negotiable #6).\n */\nexport function validateChainCapability(\n chainType: string,\n capability: keyof ChainCapabilities,\n operation: string,\n): void {\n const caps = CHAIN_CAPABILITIES[chainType];\n if (!caps) {\n throw new PolicyViolationError(\n `Unknown chain type \"${chainType}\" — cannot validate capability \"${capability}\" ` +\n `for operation \"${operation}\".`,\n 'UNKNOWN_CHAIN_TYPE',\n );\n }\n\n const tier = caps[capability];\n if (tier === 'unsupported') {\n throw new PolicyViolationError(\n `Chain type \"${chainType}\" does not support \"${capability}\". ` +\n `Operation \"${operation}\" is not available on this chain.`,\n 'UNSUPPORTED_CAPABILITY',\n );\n }\n}\n\n/**\n * Validate that MetaMask interop claims are limited to the smart-account\n * execution path (ADR-0040, Non-Negotiable #5).\n */\nexport function validateMetaMaskInteropClaim(interopType: string): void {\n const allowed = [\n 'injected-wallet',\n 'smart-account-control',\n 'session-key-delegation',\n 'companion-wallet',\n 'funding-deposit',\n ];\n if (!allowed.includes(interopType)) {\n throw new PolicyViolationError(\n `MetaMask interop type \"${interopType}\" is not supported. ` +\n `Allowed types: ${allowed.join(', ')}. ` +\n 'Native passkey import into MetaMask is not yet available.',\n 'UNSUPPORTED_METAMASK_INTEROP',\n );\n }\n}\n\n/**\n * Validate that session creation is allowed for the given identity's\n * multisig policy state (ADR-0037 §9).\n */\nexport function validateSessionCreationPolicy(\n policyEnabled: boolean,\n sessionsDisabled: boolean,\n): void {\n if (policyEnabled && sessionsDisabled) {\n throw new PolicyViolationError(\n 'Session key creation is disabled for this identity because a threshold ' +\n 'multisig policy is active with disableSessions=true. ' +\n 'Use the proposal workflow instead.',\n 'SESSIONS_DISABLED_BY_POLICY',\n );\n }\n}\n\n/**\n * Validate that cross-site passkey reuse is within the Veridex federation\n * model (ADR-0040, Non-Negotiable #3).\n */\nexport function validateFederatedOrigin(\n rpId: string,\n allowedRpIds: string[] = ['veridex.network'],\n): void {\n const isAllowed = allowedRpIds.some(\n allowed => rpId === allowed || rpId.endsWith('.' + allowed),\n );\n if (!isAllowed) {\n throw new PolicyViolationError(\n `Origin RP ID \"${rpId}\" is not part of the Veridex federation model. ` +\n 'Cross-site passkey reuse requires federation via Related Origin Requests ' +\n 'or the Auth Portal fallback.',\n 'UNFEDERATED_ORIGIN',\n );\n }\n}\n\n// ============================================================================\n// Capability matrix for integrator UX\n// ============================================================================\n\nexport interface PlatformCapabilityMatrix {\n /** Whether passkeys (WebAuthn) are supported on this platform */\n webauthnSupported: boolean;\n /** Whether conditional UI (autofill) is available */\n conditionalUISupported: boolean;\n /** Whether platform authenticators are available (Touch ID, Face ID, etc.) */\n platformAuthenticatorAvailable: boolean;\n /** Chain-specific capabilities */\n chainCapabilities: ChainCapabilities;\n /** Feature set available for the current configuration */\n features: {\n passkeyAuth: boolean;\n sessionKeys: boolean;\n socialRecovery: boolean;\n thresholdMultisig: boolean;\n crossChainBridge: boolean;\n injectedWalletInterop: boolean;\n gaslessTransactions: boolean;\n };\n}\n\n/**\n * Build a capability matrix for the current platform and chain configuration.\n * Used by integrator UIs to show/hide features appropriately.\n */\nexport function buildCapabilityMatrix(\n chainType: string,\n platformInfo: {\n webauthnSupported: boolean;\n conditionalUISupported: boolean;\n platformAuthenticatorAvailable: boolean;\n },\n hasRelayer: boolean,\n): PlatformCapabilityMatrix {\n const caps = CHAIN_CAPABILITIES[chainType] ?? CHAIN_CAPABILITIES['evm']!;\n\n return {\n webauthnSupported: platformInfo.webauthnSupported,\n conditionalUISupported: platformInfo.conditionalUISupported,\n platformAuthenticatorAvailable: platformInfo.platformAuthenticatorAvailable,\n chainCapabilities: caps,\n features: {\n passkeyAuth: platformInfo.webauthnSupported && caps.passkeyVerification !== 'unsupported',\n sessionKeys: caps.sessionKeys === 'full',\n socialRecovery: caps.recovery === 'full',\n thresholdMultisig: caps.multisig === 'full',\n crossChainBridge: caps.crossChainReceive !== 'unsupported',\n injectedWalletInterop: typeof globalThis !== 'undefined' && 'ethereum' in (globalThis as Record<string, unknown>),\n gaslessTransactions: hasRelayer,\n },\n };\n}\n\n// ============================================================================\n// Error type\n// ============================================================================\n\nexport type PolicyViolationCode =\n | 'NON_EXTRACTABLE_CREDENTIAL'\n | 'UNKNOWN_CHAIN_TYPE'\n | 'UNSUPPORTED_CAPABILITY'\n | 'UNSUPPORTED_METAMASK_INTEROP'\n | 'SESSIONS_DISABLED_BY_POLICY'\n | 'UNFEDERATED_ORIGIN';\n\nexport class PolicyViolationError extends Error {\n public readonly code: PolicyViolationCode;\n\n constructor(message: string, code: PolicyViolationCode) {\n super(message);\n this.name = 'PolicyViolationError';\n this.code = code;\n }\n}\n","/**\n * Veridex Protocol SDK — Unified Error Normalization\n *\n * Wraps chain-specific errors (ethers, Anchor, Clarity, Starknet felt, etc.)\n * into a single VeridexError class with a unified code, human-readable message,\n * and chain identifier. Integrators can catch `VeridexError` consistently\n * regardless of which chain's SDK surfaced the underlying fault.\n */\n\n// ============================================================================\n// Unified Error Codes\n// ============================================================================\n\n/**\n * Language-agnostic error codes that map consistently across all chains.\n */\nexport enum VeridexErrorCode {\n // Wallet / identity errors\n NO_CREDENTIAL = 'NO_CREDENTIAL',\n UNAUTHORIZED = 'UNAUTHORIZED',\n INVALID_SIGNATURE = 'INVALID_SIGNATURE',\n\n // Vault state errors\n VAULT_NOT_FOUND = 'VAULT_NOT_FOUND',\n VAULT_PAUSED = 'VAULT_PAUSED',\n PROTOCOL_PAUSED = 'PROTOCOL_PAUSED',\n\n // Balance / limits errors\n INSUFFICIENT_FUNDS = 'INSUFFICIENT_FUNDS',\n DAILY_LIMIT_EXCEEDED = 'DAILY_LIMIT_EXCEEDED',\n\n // Payload / dispatch errors\n INVALID_PAYLOAD = 'INVALID_PAYLOAD',\n INVALID_ACTION = 'INVALID_ACTION',\n EXPIRED = 'EXPIRED',\n\n // Cross-chain / Wormhole errors\n VAA_ALREADY_PROCESSED = 'VAA_ALREADY_PROCESSED',\n INVALID_VAA = 'INVALID_VAA',\n INVALID_EMITTER = 'INVALID_EMITTER',\n BRIDGE_ERROR = 'BRIDGE_ERROR',\n\n // Network / RPC errors\n RPC_ERROR = 'RPC_ERROR',\n TIMEOUT = 'TIMEOUT',\n RELAYER_ERROR = 'RELAYER_ERROR',\n\n // Session errors\n SESSION_EXPIRED = 'SESSION_EXPIRED',\n SESSION_INVALID = 'SESSION_INVALID',\n\n // Capability errors\n UNSUPPORTED_FEATURE = 'UNSUPPORTED_FEATURE',\n\n // Catch-all\n UNKNOWN = 'UNKNOWN',\n}\n\n/**\n * Default human-readable messages for each unified error code.\n */\nconst DEFAULT_MESSAGES: Record<VeridexErrorCode, string> = {\n [VeridexErrorCode.NO_CREDENTIAL]: 'No credential set. Call passkey.register() or passkey.setCredential() first.',\n [VeridexErrorCode.UNAUTHORIZED]: 'Unauthorized: the signer is not an owner of this vault.',\n [VeridexErrorCode.INVALID_SIGNATURE]: 'Signature verification failed.',\n [VeridexErrorCode.VAULT_NOT_FOUND]: 'Vault does not exist. Call ensureVault() first.',\n [VeridexErrorCode.VAULT_PAUSED]: 'Vault is paused. Unpause before continuing.',\n [VeridexErrorCode.PROTOCOL_PAUSED]: 'Protocol is paused. Try again later.',\n [VeridexErrorCode.INSUFFICIENT_FUNDS]: 'Insufficient funds in vault.',\n [VeridexErrorCode.DAILY_LIMIT_EXCEEDED]: 'Daily spending limit exceeded. Try a smaller amount or wait for reset.',\n [VeridexErrorCode.INVALID_PAYLOAD]: 'Invalid action payload.',\n [VeridexErrorCode.INVALID_ACTION]: 'Unknown or invalid action type.',\n [VeridexErrorCode.EXPIRED]: 'Prepared transaction has expired. Please prepare again.',\n [VeridexErrorCode.VAA_ALREADY_PROCESSED]: 'This cross-chain message has already been processed (replay protection).',\n [VeridexErrorCode.INVALID_VAA]: 'Invalid VAA: verification failed.',\n [VeridexErrorCode.INVALID_EMITTER]: 'Invalid emitter: message source is not trusted.',\n [VeridexErrorCode.BRIDGE_ERROR]: 'Cross-chain bridge error.',\n [VeridexErrorCode.RPC_ERROR]: 'RPC call failed. The node may be unavailable.',\n [VeridexErrorCode.TIMEOUT]: 'Operation timed out.',\n [VeridexErrorCode.RELAYER_ERROR]: 'Relayer submission failed.',\n [VeridexErrorCode.SESSION_EXPIRED]: 'Session key has expired. Create a new session.',\n [VeridexErrorCode.SESSION_INVALID]: 'Session key is invalid or revoked.',\n [VeridexErrorCode.UNSUPPORTED_FEATURE]: 'This feature is not supported on the current chain.',\n [VeridexErrorCode.UNKNOWN]: 'An unknown error occurred.',\n};\n\n// ============================================================================\n// VeridexError class\n// ============================================================================\n\n/**\n * Unified error class for all Veridex SDK operations.\n *\n * @example\n * ```typescript\n * try {\n * await sdk.executeTransfer(prepared, signer);\n * } catch (err) {\n * if (err instanceof VeridexError) {\n * console.log(err.code); // 'INSUFFICIENT_FUNDS'\n * console.log(err.chain); // 'base'\n * console.log(err.cause); // original ethers error\n * }\n * }\n * ```\n */\nexport class VeridexError extends Error {\n /** Unified error code */\n public readonly code: VeridexErrorCode;\n /** Chain name where the error originated (e.g. 'base', 'solana') */\n public readonly chain: string | undefined;\n /** Original chain-specific error */\n public override readonly cause: unknown;\n /** Whether the operation could succeed if retried */\n public readonly retryable: boolean;\n\n constructor(\n code: VeridexErrorCode,\n message?: string,\n options?: {\n chain?: string;\n cause?: unknown;\n retryable?: boolean;\n },\n ) {\n super(message ?? DEFAULT_MESSAGES[code]);\n this.name = 'VeridexError';\n this.code = code;\n this.chain = options?.chain;\n this.cause = options?.cause;\n this.retryable = options?.retryable ?? RETRYABLE_CODES.has(code);\n }\n}\n\n/** Codes that are inherently retryable (transient failures) */\nconst RETRYABLE_CODES = new Set<VeridexErrorCode>([\n VeridexErrorCode.RPC_ERROR,\n VeridexErrorCode.TIMEOUT,\n VeridexErrorCode.RELAYER_ERROR,\n]);\n\n// ============================================================================\n// Chain-specific error normalization\n// ============================================================================\n\n// Regex / string patterns used to detect common chain errors\nconst EVM_PATTERNS: Array<[RegExp | string, VeridexErrorCode]> = [\n [/insufficient funds/i, VeridexErrorCode.INSUFFICIENT_FUNDS],\n [/execution reverted.*paused/i, VeridexErrorCode.VAULT_PAUSED],\n [/execution reverted.*unauthorized|not\\s*owner/i, VeridexErrorCode.UNAUTHORIZED],\n [/daily.*limit/i, VeridexErrorCode.DAILY_LIMIT_EXCEEDED],\n [/nonce.*expired|nonce.*too\\s*low/i, VeridexErrorCode.EXPIRED],\n [/already.*processed|already\\s*known/i, VeridexErrorCode.VAA_ALREADY_PROCESSED],\n [/invalid.*signature|ECDSA/i, VeridexErrorCode.INVALID_SIGNATURE],\n [/timeout|ETIMEDOUT|ECONNREFUSED/i, VeridexErrorCode.TIMEOUT],\n [/could not detect network|failed to fetch|network/i, VeridexErrorCode.RPC_ERROR],\n];\n\nconst SOLANA_CODE_MAP: Record<number, VeridexErrorCode> = {\n 6000: VeridexErrorCode.PROTOCOL_PAUSED,\n 6001: VeridexErrorCode.VAULT_PAUSED,\n 6002: VeridexErrorCode.VAA_ALREADY_PROCESSED,\n 6003: VeridexErrorCode.INVALID_EMITTER,\n 6004: VeridexErrorCode.INVALID_EMITTER,\n 6005: VeridexErrorCode.UNAUTHORIZED,\n 6006: VeridexErrorCode.BRIDGE_ERROR,\n 6007: VeridexErrorCode.INVALID_PAYLOAD,\n 6008: VeridexErrorCode.INVALID_PAYLOAD,\n 6009: VeridexErrorCode.INVALID_ACTION,\n 6010: VeridexErrorCode.DAILY_LIMIT_EXCEEDED,\n 6011: VeridexErrorCode.INSUFFICIENT_FUNDS,\n 6012: VeridexErrorCode.UNAUTHORIZED,\n 6013: VeridexErrorCode.INVALID_VAA,\n};\n\nconst STARKNET_PATTERNS: Array<[RegExp | string, VeridexErrorCode]> = [\n [/insufficient.*balance|not enough/i, VeridexErrorCode.INSUFFICIENT_FUNDS],\n [/PAUSED|is paused/i, VeridexErrorCode.VAULT_PAUSED],\n [/UNAUTHORIZED|not.*authorized/i, VeridexErrorCode.UNAUTHORIZED],\n [/already.*processed/i, VeridexErrorCode.VAA_ALREADY_PROCESSED],\n [/invalid.*signature/i, VeridexErrorCode.INVALID_SIGNATURE],\n];\n\nconst STACKS_CLARITY_MAP: Record<number, VeridexErrorCode> = {\n 100: VeridexErrorCode.UNAUTHORIZED, // err-unauthorized\n 101: VeridexErrorCode.VAULT_PAUSED, // err-paused\n 102: VeridexErrorCode.INVALID_PAYLOAD, // err-invalid-payload\n 103: VeridexErrorCode.INSUFFICIENT_FUNDS, // err-insufficient-funds\n 104: VeridexErrorCode.DAILY_LIMIT_EXCEEDED, // err-limit-exceeded\n 105: VeridexErrorCode.VAULT_NOT_FOUND, // err-not-found\n 106: VeridexErrorCode.INVALID_SIGNATURE, // err-invalid-signature\n 200: VeridexErrorCode.VAA_ALREADY_PROCESSED, // err-already-processed\n 201: VeridexErrorCode.INVALID_VAA, // err-invalid-vaa\n 202: VeridexErrorCode.INVALID_EMITTER, // err-invalid-emitter\n};\n\n/**\n * Normalize any chain-specific error into a VeridexError.\n *\n * Call this at SDK boundaries (dispatch, balance fetch, vault creation) to\n * give integrators a consistent error surface.\n *\n * @param error - The original error from chain client / RPC / Anchor / etc.\n * @param chain - Chain identifier string (e.g. 'base', 'solana', 'starknet')\n * @returns A VeridexError wrapping the original\n */\nexport function normalizeError(error: unknown, chain?: string): VeridexError {\n // Already normalized\n if (error instanceof VeridexError) {\n return error;\n }\n\n const msg = error instanceof Error ? error.message : String(error);\n\n // --- Solana / Anchor numeric codes ---\n const anchorMatch = msg.match(/custom program error:\\s*0x([0-9a-fA-F]+)/i)\n ?? msg.match(/Error Code:\\s*(\\w+)\\.\\s*Error Number:\\s*(\\d+)/i);\n if (anchorMatch) {\n const code = anchorMatch[2]\n ? parseInt(anchorMatch[2], 10)\n : parseInt(anchorMatch[1], 16);\n const mapped = SOLANA_CODE_MAP[code];\n if (mapped) {\n return new VeridexError(mapped, undefined, { chain: chain ?? 'solana', cause: error });\n }\n }\n\n // --- Stacks Clarity error codes ---\n const clarityMatch = msg.match(/\\(err\\s+u(\\d+)\\)/i);\n if (clarityMatch) {\n const code = parseInt(clarityMatch[1], 10);\n const mapped = STACKS_CLARITY_MAP[code];\n if (mapped) {\n return new VeridexError(mapped, undefined, { chain: chain ?? 'stacks', cause: error });\n }\n }\n\n // --- Starknet patterns ---\n if (chain === 'starknet' || /felt|starknet|cairo/i.test(msg)) {\n for (const [pattern, code] of STARKNET_PATTERNS) {\n if (typeof pattern === 'string' ? msg.includes(pattern) : pattern.test(msg)) {\n return new VeridexError(code, undefined, { chain: chain ?? 'starknet', cause: error });\n }\n }\n }\n\n // --- EVM patterns (including ethers error codes) ---\n for (const [pattern, code] of EVM_PATTERNS) {\n if (typeof pattern === 'string' ? msg.includes(pattern) : pattern.test(msg)) {\n return new VeridexError(code, undefined, { chain, cause: error });\n }\n }\n\n // --- ethers specific error codes ---\n const ethersError = error as any;\n if (ethersError?.code === 'INSUFFICIENT_FUNDS') {\n return new VeridexError(VeridexErrorCode.INSUFFICIENT_FUNDS, undefined, { chain, cause: error });\n }\n if (ethersError?.code === 'CALL_EXCEPTION') {\n return new VeridexError(VeridexErrorCode.RPC_ERROR, `Contract call failed: ${msg}`, { chain, cause: error });\n }\n if (ethersError?.code === 'NETWORK_ERROR' || ethersError?.code === 'SERVER_ERROR') {\n return new VeridexError(VeridexErrorCode.RPC_ERROR, undefined, { chain, cause: error, retryable: true });\n }\n if (ethersError?.code === 'TIMEOUT') {\n return new VeridexError(VeridexErrorCode.TIMEOUT, undefined, { chain, cause: error, retryable: true });\n }\n\n // --- Generic fallback ---\n return new VeridexError(VeridexErrorCode.UNKNOWN, msg, { chain, cause: error });\n}\n","/**\n * Veridex Protocol SDK — Balance Watcher\n *\n * Provides a polling-based subscription API for vault balance changes.\n * Returns an unsubscribe function so integrators can react to incoming\n * transfers, outgoing withdrawals, or spending limit resets without\n * manually implementing polling.\n *\n * Where chains expose WebSocket endpoints in the future, this module\n * can be extended to use push-based notifications without changing the\n * public API surface.\n */\n\nimport type { PortfolioBalance, TokenBalance } from './BalanceManager.js';\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/** Event types emitted by the balance watcher */\nexport type BalanceEventType = 'balanceChange' | 'error';\n\n/** Callback signature for balance change events */\nexport type BalanceChangeCallback = (event: BalanceChangeEvent) => void;\n\n/** Callback signature for error events */\nexport type BalanceErrorCallback = (error: Error) => void;\n\n/** A balance change event delivered to subscribers */\nexport interface BalanceChangeEvent {\n /** Wormhole chain ID */\n wormholeChainId: number;\n /** Vault address */\n address: string;\n /** Updated portfolio snapshot */\n portfolio: PortfolioBalance;\n /** Individual tokens whose balance changed since last poll */\n changes: TokenBalanceChange[];\n /** Timestamp of this poll */\n timestamp: number;\n}\n\n/** Describes a single token balance that changed */\nexport interface TokenBalanceChange {\n token: TokenBalance['token'];\n previousBalance: bigint;\n currentBalance: bigint;\n /** Positive = received, negative = sent/withdrawn */\n delta: bigint;\n}\n\n/** Options for the watcher */\nexport interface BalanceWatcherOptions {\n /** Poll interval in milliseconds (default: 15_000 — 15 seconds) */\n intervalMs?: number;\n /** Minimum interval allowed (floor, to protect against aggressive polling) */\n minIntervalMs?: number;\n /** Whether to emit an initial event immediately with current balances */\n emitInitial?: boolean;\n}\n\n/** Function to stop watching */\nexport type Unsubscribe = () => void;\n\n// ============================================================================\n// Constants\n// ============================================================================\n\nconst DEFAULT_INTERVAL_MS = 15_000;\nconst MIN_INTERVAL_MS = 5_000;\n\n// ============================================================================\n// BalanceWatcher class\n// ============================================================================\n\n/**\n * Watch vault balances for changes via periodic polling.\n *\n * @example\n * ```typescript\n * const watcher = new BalanceWatcher(fetchBalance);\n *\n * const unsub = watcher.watch(\n * 10004, '0xVaultAddr',\n * (event) => {\n * for (const c of event.changes) {\n * console.log(`${c.token.symbol}: ${c.delta > 0n ? '+' : ''}${c.delta}`);\n * }\n * },\n * { intervalMs: 10_000 }\n * );\n *\n * // Later:\n * unsub();\n * ```\n */\nexport class BalanceWatcher {\n private subscriptions = new Map<string, Subscription>();\n\n /**\n * @param fetchBalance - Function that fetches the current portfolio balance.\n * Typically bound to `BalanceManager.getPortfolioBalance` or the SDK's\n * `getVaultBalances()`.\n */\n constructor(\n private readonly fetchBalance: (\n wormholeChainId: number,\n address: string,\n ) => Promise<PortfolioBalance>,\n ) {}\n\n /**\n * Start watching a vault's balances.\n *\n * @returns An unsubscribe function that stops polling.\n */\n watch(\n wormholeChainId: number,\n address: string,\n onChange: BalanceChangeCallback,\n options?: BalanceWatcherOptions,\n onError?: BalanceErrorCallback,\n ): Unsubscribe {\n const key = `${wormholeChainId}:${address}`;\n const interval = Math.max(\n options?.minIntervalMs ?? MIN_INTERVAL_MS,\n options?.intervalMs ?? DEFAULT_INTERVAL_MS,\n );\n\n // If there's already a subscription for this combo, add the callback\n const existing = this.subscriptions.get(key);\n if (existing) {\n existing.onChangeCallbacks.push(onChange);\n if (onError) existing.onErrorCallbacks.push(onError);\n return () => this.removeCallback(key, onChange, onError);\n }\n\n const sub: Subscription = {\n wormholeChainId,\n address,\n intervalMs: interval,\n onChangeCallbacks: [onChange],\n onErrorCallbacks: onError ? [onError] : [],\n lastSnapshot: null,\n timer: null,\n };\n\n this.subscriptions.set(key, sub);\n\n // Start polling\n const poll = async () => {\n try {\n const portfolio = await this.fetchBalance(wormholeChainId, address);\n const changes = this.diffBalances(sub.lastSnapshot, portfolio);\n\n const isInitial = sub.lastSnapshot === null;\n sub.lastSnapshot = portfolio;\n\n // Only emit if there are actual changes, or if emitInitial is set\n if (changes.length > 0 || (isInitial && options?.emitInitial)) {\n const event: BalanceChangeEvent = {\n wormholeChainId,\n address,\n portfolio,\n changes,\n timestamp: Date.now(),\n };\n for (const cb of sub.onChangeCallbacks) {\n try { cb(event); } catch { /* subscriber error — don't crash poller */ }\n }\n }\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n for (const cb of sub.onErrorCallbacks) {\n try { cb(error); } catch { /* ignore */ }\n }\n }\n };\n\n // Immediate first poll if requested\n if (options?.emitInitial) {\n void poll();\n }\n\n sub.timer = setInterval(poll, interval) as unknown as number;\n\n return () => this.removeCallback(key, onChange, onError);\n }\n\n /**\n * Stop all watchers.\n */\n stopAll(): void {\n for (const [key, sub] of this.subscriptions) {\n if (sub.timer !== null) {\n clearInterval(sub.timer);\n }\n this.subscriptions.delete(key);\n }\n }\n\n /**\n * Get the number of active subscriptions.\n */\n get activeCount(): number {\n return this.subscriptions.size;\n }\n\n // --- Internal helpers ---\n\n private removeCallback(\n key: string,\n onChange: BalanceChangeCallback,\n onError?: BalanceErrorCallback,\n ): void {\n const sub = this.subscriptions.get(key);\n if (!sub) return;\n\n sub.onChangeCallbacks = sub.onChangeCallbacks.filter(cb => cb !== onChange);\n if (onError) {\n sub.onErrorCallbacks = sub.onErrorCallbacks.filter(cb => cb !== onError);\n }\n\n // If no more callbacks, tear down the subscription\n if (sub.onChangeCallbacks.length === 0) {\n if (sub.timer !== null) {\n clearInterval(sub.timer);\n }\n this.subscriptions.delete(key);\n }\n }\n\n private diffBalances(\n previous: PortfolioBalance | null,\n current: PortfolioBalance,\n ): TokenBalanceChange[] {\n if (!previous) return [];\n\n const prevMap = new Map(\n previous.tokens.map(t => [t.token.address.toLowerCase(), t]),\n );\n\n const changes: TokenBalanceChange[] = [];\n\n for (const curr of current.tokens) {\n const key = curr.token.address.toLowerCase();\n const prev = prevMap.get(key);\n const previousBalance = prev?.balance ?? 0n;\n\n if (curr.balance !== previousBalance) {\n changes.push({\n token: curr.token,\n previousBalance,\n currentBalance: curr.balance,\n delta: curr.balance - previousBalance,\n });\n }\n }\n\n // Check for tokens that disappeared (balance went to 0 or token removed)\n for (const [key, prev] of prevMap) {\n const inCurrent = current.tokens.some(\n t => t.token.address.toLowerCase() === key,\n );\n if (!inCurrent && prev.balance > 0n) {\n changes.push({\n token: prev.token,\n previousBalance: prev.balance,\n currentBalance: 0n,\n delta: -prev.balance,\n });\n }\n }\n\n return changes;\n }\n}\n\n// ============================================================================\n// Internal types\n// ============================================================================\n\ninterface Subscription {\n wormholeChainId: number;\n address: string;\n intervalMs: number;\n onChangeCallbacks: BalanceChangeCallback[];\n onErrorCallbacks: BalanceErrorCallback[];\n lastSnapshot: PortfolioBalance | null;\n timer: number | null;\n}\n","/**\n * Veridex Protocol SDK - Main SDK Class\n */\n\nimport { PasskeyManager } from './PasskeyManager.js';\nimport { WalletManager } from './WalletManager.js';\nimport { BalanceManager, type TokenBalance, type PortfolioBalance } from './BalanceManager.js';\nimport { TransactionTracker, type TransactionState, type TransactionCallback } from './TransactionTracker.js';\nimport { \n CrossChainManager, \n type CrossChainResult,\n type CrossChainFees,\n type CrossChainProgressCallback,\n} from './CrossChainManager.js';\nimport { RelayerClient, type SubmitSignedActionRequest } from './RelayerClient.js';\nimport { ChainDetector } from './ChainDetector.js';\nimport { TransactionParser } from './TransactionParser.js';\nimport type { TransactionSummary } from './TransactionSummary.types.js';\nimport { SpendingLimitsManager } from './SpendingLimitsManager.js';\nimport { AccountManager } from './AccountManager.js';\nimport { RecoveryManager } from './RecoveryManager.js';\nimport { MultisigManager } from './MultisigManager.js';\nimport { buildCapabilityMatrix, CHAIN_CAPABILITIES } from './PolicyEnforcement.js';\nimport type { PlatformCapabilityMatrix, ChainCapabilities } from './PolicyEnforcement.js';\nimport { normalizeError, VeridexError, VeridexErrorCode } from './VeridexError.js';\nimport { BalanceWatcher } from './BalanceWatcher.js';\nimport type { BalanceChangeCallback, BalanceErrorCallback, BalanceWatcherOptions, Unsubscribe } from './BalanceWatcher.js';\nimport type { SpendingLimits, FormattedSpendingLimits, LimitCheckResult } from './SpendingLimits.types.js';\nimport { ethers } from 'ethers';\n// NOTE: authenticateAndPrepare and queryPortfolio are loaded via dynamic import()\n// to avoid pulling @wormhole-foundation/wormhole-query-sdk into the static\n// module graph, which causes a TDZ crash in browser/SSR bundles.\nimport { \n GasSponsor, \n type SponsoredVaultResult, \n type MultiChainVaultResult,\n type ChainDeploymentConfig,\n} from './GasSponsor.js';\nimport { buildChallenge, buildGaslessChallenge } from '../payload.js';\nimport { normalizeEmitterAddress } from '../wormhole.js';\nimport { \n getAllTokens, \n getTokenBySymbol, \n isNativeToken,\n type TokenInfo \n} from '../constants/tokens.js';\nimport type {\n VeridexConfig,\n ChainClient,\n PasskeyCredential,\n TransferParams,\n ExecuteParams,\n BridgeParams,\n DispatchResult,\n VaultInfo,\n UnifiedIdentity,\n ChainAddress,\n VaultCreationResult,\n PreparedTransfer,\n TransferResult,\n ReceiveAddress,\n BridgeResult,\n PreparedBridge,\n IdentityState,\n AddBackupKeyResult,\n RemoveKeyResult,\n AuthorizedKey,\n} from './types.js';\n\n/** Default expiration time for prepared transfers (5 minutes) */\nconst DEFAULT_PREPARED_TRANSFER_TTL = 5 * 60 * 1000;\n/** Maximum allowed TTL for prepared transfers (30 minutes) */\nconst MAX_PREPARED_TRANSFER_TTL = 30 * 60 * 1000;\n\nexport class VeridexSDK {\n public readonly passkey: PasskeyManager;\n public readonly wallet: WalletManager;\n public readonly account: AccountManager;\n public readonly balance: BalanceManager;\n public readonly transactions: TransactionTracker;\n public readonly crossChain: CrossChainManager;\n public readonly sponsor: GasSponsor;\n public readonly transactionParser: TransactionParser;\n public readonly spendingLimits: SpendingLimitsManager;\n public readonly recovery: RecoveryManager | null;\n public readonly multisig: MultisigManager | null;\n public readonly balanceWatcher: BalanceWatcher;\n private readonly chain: ChainClient;\n private readonly relayer?: RelayerClient;\n // TODO: Use relayerApiKey when relayer integration is complete (Issue #8)\n // private readonly relayerApiKey?: string;\n private readonly queryApiKey?: string;\n private readonly testnet: boolean;\n private readonly sponsorPrivateKey?: string;\n private readonly chainRpcUrls?: Record<number, string>;\n private readonly chainDetector: ChainDetector;\n private readonly preparedTransferTtl: number;\n private unifiedIdentity: UnifiedIdentity | null = null;\n\n constructor(config: VeridexConfig) {\n this.chain = config.chain;\n this.testnet = config.testnet ?? true;\n this.sponsorPrivateKey = config.sponsorPrivateKey;\n this.chainRpcUrls = config.chainRpcUrls;\n // TODO: Uncomment when relayerApiKey is used (Issue #8)\n // this.relayerApiKey = config.relayerApiKey;\n this.queryApiKey = config.queryApiKey ?? config.relayerApiKey;\n this.passkey = new PasskeyManager({\n relayerUrl: config.relayerUrl,\n });\n this.wallet = new WalletManager({\n cacheAddresses: true,\n persistToStorage: config.persistWallet ?? true,\n });\n this.balance = new BalanceManager({\n cacheBalances: true,\n cacheTtl: 30_000, // 30 seconds\n customRpcUrls: config.chainRpcUrls ?? {},\n });\n this.transactions = new TransactionTracker({\n pollingInterval: 2000,\n requiredConfirmations: 1,\n });\n\n this.chainDetector = new ChainDetector({\n testnet: this.testnet,\n rpcUrls: config.chainRpcUrls ?? {},\n });\n this.crossChain = new CrossChainManager({\n testnet: this.testnet,\n relayerUrl: config.relayerUrl,\n autoRelay: !!config.relayerUrl,\n });\n this.sponsor = new GasSponsor({\n // Veridex fallback sponsorship\n sponsorPrivateKey: config.sponsorPrivateKey,\n // Integrator-provided sponsorship (takes priority over Veridex)\n integratorSponsorKey: config.integratorSponsorKey,\n // Relayer for remote sponsorship (future primary method)\n relayerUrl: config.relayerUrl,\n relayerApiKey: config.relayerApiKey,\n // Chain configuration\n testnet: this.testnet,\n customRpcUrls: config.chainRpcUrls,\n });\n\n // Initialize relayer client if URL provided\n if (config.relayerUrl) {\n this.relayer = new RelayerClient({\n baseUrl: config.relayerUrl,\n apiKey: config.relayerApiKey,\n });\n }\n\n this.account = new AccountManager({\n passkey: this.passkey,\n wallet: this.wallet,\n chain: this.chain,\n relayer: this.relayer,\n testnet: this.testnet,\n getUnifiedIdentity: () => this.getUnifiedIdentity(),\n });\n\n // Initialize transaction parser for human-readable summaries (Issue #26)\n this.transactionParser = new TransactionParser({\n defaultChainId: this.chain.getConfig().wormholeChainId,\n // TODO: Integrate ENS resolution via relayer when available\n // resolveEnsName: async (address) => { ... }\n // TODO: Integrate price oracle when available\n // getTokenPrice: async (token, chainId) => { ... }\n });\n\n // Initialize recovery manager (ADR-0040) — only on recovery-capable chains\n try {\n this.recovery = new RecoveryManager({\n passkey: this.passkey,\n chain: this.chain,\n });\n } catch {\n this.recovery = null;\n }\n\n // Initialize multisig manager (ADR-0037) — only on multisig-capable chains\n try {\n this.multisig = new MultisigManager({\n passkey: this.passkey,\n chain: this.chain,\n });\n } catch {\n this.multisig = null;\n }\n\n // Initialize spending limits manager (Issue #27)\n this.spendingLimits = new SpendingLimitsManager({\n defaultDecimals: 18,\n defaultSymbol: this.chain.getConfig().name.includes('Solana') ? 'SOL' : 'ETH',\n rpcUrls: config.chainRpcUrls ?? {},\n cacheTtl: 10000, // 10 seconds\n });\n\n // Initialize balance watcher (polling-based subscription)\n this.balanceWatcher = new BalanceWatcher(\n async (chainId, address) => {\n return this.balance.getPortfolioBalance(chainId, address, false);\n },\n );\n\n // Configurable TTL for prepared transfers (clamped to MAX)\n this.preparedTransferTtl = Math.min(\n config.preparedTransferTtl ?? DEFAULT_PREPARED_TRANSFER_TTL,\n MAX_PREPARED_TRANSFER_TTL,\n );\n }\n\n getChainConfig() {\n return this.chain.getConfig();\n }\n\n getChainClient(): ChainClient {\n return this.chain;\n }\n\n /**\n * Returns a capability matrix for the current chain, useful for integrator\n * UIs to understand what operations the platform supports.\n */\n getCapabilityMatrix(platformInfo?: {\n webauthnSupported: boolean;\n conditionalUISupported: boolean;\n platformAuthenticatorAvailable: boolean;\n }): PlatformCapabilityMatrix {\n const config = this.chain.getConfig();\n const platform = platformInfo ?? {\n webauthnSupported: typeof globalThis !== 'undefined' && 'PublicKeyCredential' in globalThis,\n conditionalUISupported: false,\n platformAuthenticatorAvailable: false,\n };\n return buildCapabilityMatrix(config.name.toLowerCase(), platform, !!this.relayer);\n }\n\n /**\n * Check if a specific feature is supported on the current chain.\n *\n * Unlike `getCapabilityMatrix()` which returns the full matrix, this is a\n * simple boolean check for the most common per-chain capability queries.\n *\n * @param feature - Feature name to check\n * @returns `true` if fully or partially supported; `false` if unsupported\n *\n * @example\n * ```typescript\n * if (sdk.supportsFeature('recovery')) {\n * // Show recovery UI\n * }\n * ```\n */\n supportsFeature(feature: keyof ChainCapabilities): boolean {\n const chainType = this.chain.getConfig().name.toLowerCase();\n // Resolve the canonical chain type string used in CHAIN_CAPABILITIES\n const type = this.resolveChainType(chainType);\n const caps = CHAIN_CAPABILITIES[type];\n if (!caps) return false;\n return caps[feature] !== 'unsupported';\n }\n\n /**\n * Resolve a chain name to its CHAIN_CAPABILITIES key.\n */\n private resolveChainType(chainName: string): string {\n // Direct match\n if (CHAIN_CAPABILITIES[chainName]) return chainName;\n // Common renames\n if (chainName.includes('base') || chainName.includes('optimism') || chainName.includes('arbitrum') || chainName.includes('ethereum') || chainName.includes('polygon') || chainName.includes('celo')) return 'evm';\n if (chainName.includes('avalanche') || chainName.includes('fuji')) return 'avalanche';\n if (chainName.includes('solana')) return 'solana';\n if (chainName.includes('aptos')) return 'aptos';\n if (chainName.includes('sui')) return 'sui';\n if (chainName.includes('starknet')) return 'starknet';\n if (chainName.includes('stacks')) return 'stacks';\n return 'evm'; // safe default\n }\n\n /**\n * Watch for balance changes on a vault.\n *\n * Uses polling under the hood; the returned function stops the watcher.\n *\n * @example\n * ```typescript\n * const unsub = sdk.watchBalance(\n * (event) => console.log('Balance changed:', event.changes),\n * { intervalMs: 10_000 },\n * );\n *\n * // later\n * unsub();\n * ```\n */\n watchBalance(\n onChange: BalanceChangeCallback,\n options?: BalanceWatcherOptions,\n onError?: BalanceErrorCallback,\n ): Unsubscribe {\n const chainConfig = this.chain.getConfig();\n const vaultAddress = this.getVaultAddress();\n return this.balanceWatcher.watch(\n chainConfig.wormholeChainId,\n vaultAddress,\n onChange,\n options,\n onError,\n );\n }\n\n async getNonce(): Promise<bigint> {\n const credential = this.passkey.getCredential();\n if (!credential) {\n throw new VeridexError(VeridexErrorCode.NO_CREDENTIAL);\n }\n return await this.chain.getNonce(credential.keyHash);\n }\n\n async getMessageFee(): Promise<bigint> {\n return await this.chain.getMessageFee();\n }\n\n async buildTransferPayload(params: TransferParams): Promise<string> {\n return await this.chain.buildTransferPayload(params);\n }\n\n async buildExecutePayload(params: ExecuteParams): Promise<string> {\n return await this.chain.buildExecutePayload(params);\n }\n\n async buildBridgePayload(params: BridgeParams): Promise<string> {\n return await this.chain.buildBridgePayload(params);\n }\n\n async transfer(params: TransferParams, signer: any): Promise<DispatchResult> {\n const credential = this.passkey.getCredential();\n if (!credential) {\n throw new VeridexError(VeridexErrorCode.NO_CREDENTIAL);\n }\n\n // ADR-0037: Block direct dispatch if multisig policy protects transfers\n await this.multisig?.assertDirectDispatchAllowed('transfer');\n\n try {\n const actionPayload = await this.buildTransferPayload(params);\n const nonce = await this.getNonce();\n const challenge = buildChallenge(\n credential.keyHash,\n params.targetChain,\n nonce,\n actionPayload\n );\n\n const signature = await this.passkey.sign(challenge);\n\n return await this.chain.dispatch(\n signature,\n credential.publicKeyX,\n credential.publicKeyY,\n params.targetChain,\n actionPayload,\n nonce,\n signer\n );\n } catch (err) {\n throw normalizeError(err, this.chain.getConfig().name);\n }\n }\n\n async execute(params: ExecuteParams, signer: any): Promise<DispatchResult> {\n const credential = this.passkey.getCredential();\n if (!credential) {\n throw new VeridexError(VeridexErrorCode.NO_CREDENTIAL);\n }\n\n // ADR-0037: Block direct dispatch if multisig policy protects executions\n await this.multisig?.assertDirectDispatchAllowed('execute');\n\n try {\n const actionPayload = await this.buildExecutePayload(params);\n const nonce = await this.getNonce();\n const challenge = buildChallenge(\n credential.keyHash,\n params.targetChain,\n nonce,\n actionPayload\n );\n\n const signature = await this.passkey.sign(challenge);\n\n return await this.chain.dispatch(\n signature,\n credential.publicKeyX,\n credential.publicKeyY,\n params.targetChain,\n actionPayload,\n nonce,\n signer\n );\n } catch (err) {\n throw normalizeError(err, this.chain.getConfig().name);\n }\n }\n\n async bridge(params: BridgeParams, signer: any): Promise<DispatchResult> {\n const credential = this.passkey.getCredential();\n if (!credential) {\n throw new VeridexError(VeridexErrorCode.NO_CREDENTIAL);\n }\n\n // ADR-0037: Block direct dispatch if multisig policy protects bridge operations\n await this.multisig?.assertDirectDispatchAllowed('bridge');\n\n try {\n const actionPayload = await this.buildBridgePayload(params);\n const nonce = await this.getNonce();\n\n const challenge = buildChallenge(\n credential.keyHash,\n params.sourceChain,\n nonce,\n actionPayload\n );\n\n const signature = await this.passkey.sign(challenge);\n\n return await this.chain.dispatch(\n signature,\n credential.publicKeyX,\n credential.publicKeyY,\n params.sourceChain,\n actionPayload,\n nonce,\n signer\n );\n } catch (err) {\n throw normalizeError(err, this.chain.getConfig().name);\n }\n }\n\n // ========================================================================\n // Phase 3: Cross-Chain Transfers\n // ========================================================================\n\n /**\n * Prepare a bridge/cross-chain transfer with fee estimation\n * \n * @param params - Bridge parameters\n * @returns PreparedBridge with fee estimates\n */\n async prepareBridge(params: BridgeParams): Promise<PreparedBridge> {\n const credential = this.passkey.getCredential();\n if (!credential) {\n throw new VeridexError(VeridexErrorCode.NO_CREDENTIAL);\n }\n\n // Build payload and get nonce\n const actionPayload = await this.buildBridgePayload(params);\n const nonce = await this.getNonce();\n \n // Build challenge\n const challenge = buildChallenge(\n credential.keyHash,\n params.sourceChain,\n nonce,\n actionPayload\n );\n\n // Get chain config\n const chainConfig = this.chain.getConfig();\n\n // Estimate fees using CrossChainManager\n const evmClient = this.chain as any;\n const provider = evmClient.provider ?? evmClient.getProvider?.();\n \n let fees: CrossChainFees = {\n sourceGas: 300_000n * 1_000_000_000n, // Default estimate\n messageFee: 0n,\n relayerFee: 0n,\n totalCost: 300_000n * 1_000_000_000n,\n formattedTotal: '0.0003 ETH',\n currency: 'ETH',\n };\n\n if (provider) {\n try {\n fees = await this.crossChain.estimateFees(params, chainConfig, provider);\n } catch (e) {\n console.warn('Fee estimation failed, using defaults:', e);\n }\n }\n\n return {\n params,\n actionPayload,\n nonce,\n challenge,\n fees,\n sourceChain: params.sourceChain,\n destinationChain: params.destinationChain,\n preparedAt: Date.now(),\n expiresAt: Date.now() + this.preparedTransferTtl,\n };\n }\n\n /**\n * Execute a prepared bridge with full cross-chain tracking\n * \n * @param prepared - PreparedBridge from prepareBridge()\n * @param signer - Signer to pay for gas\n * @param onProgress - Optional callback for progress updates\n * @returns BridgeResult with cross-chain tracking info\n */\n async executeBridge(\n prepared: PreparedBridge,\n signer: any,\n onProgress?: CrossChainProgressCallback\n ): Promise<BridgeResult> {\n const credential = this.passkey.getCredential();\n if (!credential) {\n throw new VeridexError(VeridexErrorCode.NO_CREDENTIAL);\n }\n\n // ADR-0037: Block direct dispatch if multisig policy protects bridge operations\n await this.multisig?.assertDirectDispatchAllowed('bridge');\n\n // Check expiration\n if (Date.now() > prepared.expiresAt) {\n throw new VeridexError(VeridexErrorCode.EXPIRED);\n }\n\n const startTime = Date.now();\n const chainConfig = this.chain.getConfig();\n const hubEmitter = normalizeEmitterAddress(chainConfig.contracts.hub ?? '');\n\n // Step 1: Sign with passkey\n onProgress?.({\n status: 'signing',\n step: 1,\n totalSteps: 6,\n message: 'Sign with your passkey...',\n });\n\n const signature = await this.passkey.sign(prepared.challenge);\n\n // Step 2: Dispatch transaction\n onProgress?.({\n status: 'dispatching',\n step: 2,\n totalSteps: 6,\n message: 'Submitting transaction to blockchain...',\n });\n\n const dispatchResult = await this.chain.dispatch(\n signature,\n credential.publicKeyX,\n credential.publicKeyY,\n prepared.params.sourceChain,\n prepared.actionPayload,\n prepared.nonce,\n signer\n );\n\n // Step 3: Wait for confirmations\n onProgress?.({\n status: 'waiting_confirmations',\n step: 3,\n totalSteps: 6,\n message: 'Waiting for block confirmations...',\n details: { txHash: dispatchResult.transactionHash },\n });\n\n // Track the cross-chain transfer\n this.crossChain.trackTransfer(\n dispatchResult.transactionHash,\n prepared.sourceChain,\n prepared.destinationChain,\n dispatchResult.sequence,\n hubEmitter\n );\n\n // Track in transaction tracker too\n this.transactions.track(\n dispatchResult.transactionHash,\n chainConfig.wormholeChainId,\n undefined,\n dispatchResult.sequence\n );\n\n // Step 4-5: Fetch VAA (CrossChainManager handles this)\n let vaa: string | undefined;\n try {\n vaa = await this.crossChain.fetchVAAByTxHash(\n dispatchResult.transactionHash,\n onProgress\n );\n \n this.crossChain.completeTransfer(\n dispatchResult.transactionHash,\n vaa\n );\n } catch (error) {\n // VAA fetch failed, but transaction was successful\n // User can retry VAA fetch later\n console.warn('VAA fetch failed:', error);\n }\n\n // Step 6: Submit to relayer (if configured)\n // The relayer auto-relays by observing hub Dispatch events; there is\n // currently no relay-job API to poll for destination tx hashes.\n let destinationTxHash: string | undefined;\n if (vaa && this.relayer) {\n onProgress?.({\n status: 'relaying',\n step: 6,\n totalSteps: 6,\n message: 'Relayer will submit to destination chain automatically...',\n });\n }\n\n onProgress?.({\n status: 'completed',\n step: 6,\n totalSteps: 6,\n message: 'Cross-chain transfer complete!',\n details: {\n txHash: dispatchResult.transactionHash,\n sequence: dispatchResult.sequence,\n vaaReady: !!vaa,\n destinationTxHash,\n },\n });\n\n // Schedule balance cache invalidation on confirmation\n const vaultAddress = this.getVaultAddress();\n this.transactions.track(\n dispatchResult.transactionHash,\n chainConfig.wormholeChainId,\n (state) => {\n if (state.status === 'confirmed' || state.status === 'failed') {\n this.balance.invalidateCache(chainConfig.wormholeChainId, vaultAddress);\n }\n },\n dispatchResult.sequence\n );\n\n return {\n ...dispatchResult,\n params: prepared.params,\n sourceChain: prepared.sourceChain,\n destinationChain: prepared.destinationChain,\n vaa,\n destinationTxHash,\n duration: Date.now() - startTime,\n timestamp: Date.now(),\n };\n }\n\n /**\n * Execute a gasless bridge using the relayer\n *\n * The relayer pays for the Hub transaction (and Wormhole fee), then observes\n * the resulting Dispatch event and relays the VAA to the destination spoke.\n */\n async bridgeViaRelayer(\n params: BridgeParams,\n onProgress?: CrossChainProgressCallback\n ): Promise<BridgeResult> {\n const credential = this.passkey.getCredential();\n if (!credential) {\n throw new VeridexError(VeridexErrorCode.NO_CREDENTIAL);\n }\n\n // ADR-0037: Block direct dispatch if multisig policy protects bridge operations\n await this.multisig?.assertDirectDispatchAllowed('bridge');\n\n if (!this.relayer) {\n throw new VeridexError(VeridexErrorCode.RELAYER_ERROR, 'Relayer not configured. Please provide relayerUrl in SDK config.');\n }\n\n const startTime = Date.now();\n\n onProgress?.({\n status: 'preparing',\n step: 0,\n totalSteps: 6,\n message: 'Preparing gasless bridge...',\n });\n\n // Bridge actions target the *sourceChain* (where the vault holds funds)\n const actionPayload = await this.buildBridgePayload(params);\n const nonce = await this.getNonce();\n const chainConfig = this.chain.getConfig();\n const hubChainId = chainConfig.hubChainId ?? chainConfig.wormholeChainId;\n\n onProgress?.({\n status: 'signing',\n step: 1,\n totalSteps: 6,\n message: 'Sign with your passkey...',\n });\n\n // BRIDGE actions target sourceChain (where funds are held)\n // The destinationChain is encoded in the actionPayload itself\n // The VAA will be executed on the SOURCE vault to initiate Token Bridge transfer\n const challenge = buildGaslessChallenge(\n params.sourceChain,\n actionPayload,\n nonce,\n hubChainId\n );\n const signature = await this.passkey.sign(challenge);\n\n onProgress?.({\n status: 'dispatching',\n step: 2,\n totalSteps: 6,\n message: 'Submitting gasless bridge to relayer...',\n });\n\n // Use full WebAuthn data for authenticateAndDispatch\n // For BRIDGE: targetChain = sourceChain (where funds are)\n // The destination is in the actionPayload\n const submitRequest: SubmitSignedActionRequest = {\n authenticatorData: signature.authenticatorData,\n clientDataJSON: signature.clientDataJSON,\n challengeIndex: signature.challengeIndex,\n typeIndex: signature.typeIndex,\n r: '0x' + signature.r.toString(16).padStart(64, '0'),\n s: '0x' + signature.s.toString(16).padStart(64, '0'),\n publicKeyX: '0x' + credential.publicKeyX.toString(16).padStart(64, '0'),\n publicKeyY: '0x' + credential.publicKeyY.toString(16).padStart(64, '0'),\n targetChain: params.sourceChain,\n actionPayload,\n nonce: Number(nonce),\n };\n\n const relayerResult = await this.relayer.submitSignedAction(submitRequest);\n if (!relayerResult.success) {\n throw new VeridexError(VeridexErrorCode.RELAYER_ERROR, `Relayer submission failed: ${relayerResult.error}`);\n }\n\n const txHash = relayerResult.txHash ?? '';\n const sequence = relayerResult.sequence ? BigInt(relayerResult.sequence) : 0n;\n\n if (txHash) {\n this.transactions.track(txHash, hubChainId, undefined, sequence || undefined);\n }\n\n // Try to fetch VAA for UI feedback (relayer will still execute even if this fails)\n let vaa: string | undefined;\n try {\n vaa = await this.crossChain.fetchVAAByTxHash(txHash, onProgress);\n } catch {\n // ignore: user can retry fetch later\n }\n\n onProgress?.({\n status: 'completed',\n step: 6,\n totalSteps: 6,\n message: 'Gasless bridge submitted. Relayer will complete execution.',\n details: {\n txHash,\n sequence,\n vaaReady: !!vaa,\n },\n });\n\n // For BRIDGE: targetChain (where VAA is executed) = sourceChain\n // The actual destination for funds is in destinationChain\n return {\n transactionHash: txHash,\n sequence,\n userKeyHash: credential.keyHash,\n targetChain: params.sourceChain,\n blockNumber: 0,\n params,\n sourceChain: params.sourceChain,\n destinationChain: params.destinationChain,\n vaa,\n destinationTxHash: undefined,\n duration: Date.now() - startTime,\n timestamp: Date.now(),\n };\n }\n\n /**\n * Execute a full bridge with automatic preparation\n * \n * @param params - Bridge parameters\n * @param signer - Signer to pay for gas\n * @param onProgress - Optional callback for progress updates\n * @returns BridgeResult with cross-chain tracking info\n */\n async bridgeWithTracking(\n params: BridgeParams,\n signer: any,\n onProgress?: CrossChainProgressCallback\n ): Promise<BridgeResult> {\n onProgress?.({\n status: 'preparing',\n step: 0,\n totalSteps: 6,\n message: 'Preparing cross-chain transfer...',\n });\n\n const prepared = await this.prepareBridge(params);\n return await this.executeBridge(prepared, signer, onProgress);\n }\n\n /**\n * Fetch VAA for a completed transaction\n * Use this if VAA fetch failed during bridge execution\n * \n * @param txHash - Source chain transaction hash\n * @returns VAA base64 string\n */\n async fetchVAAForTransaction(txHash: string): Promise<string> {\n return await this.crossChain.fetchVAAByTxHash(txHash);\n }\n\n /**\n * Get cross-chain transfer fees\n * \n * @param params - Bridge parameters\n * @returns CrossChainFees with breakdown\n */\n async getBridgeFees(params: BridgeParams): Promise<CrossChainFees> {\n const chainConfig = this.chain.getConfig();\n const evmClient = this.chain as any;\n const provider = evmClient.provider ?? evmClient.getProvider?.();\n\n if (!provider) {\n throw new VeridexError(VeridexErrorCode.RPC_ERROR, 'Provider not available');\n }\n\n return await this.crossChain.estimateFees(params, chainConfig, provider);\n }\n\n /**\n * Get all pending cross-chain transfers\n */\n getPendingBridges(): CrossChainResult[] {\n return this.crossChain.getAllPendingTransfers();\n }\n\n /**\n * Get Wormholescan explorer URL for a cross-chain transfer\n */\n getWormholeExplorerUrl(sequence: bigint): string {\n const chainConfig = this.chain.getConfig();\n const hubEmitter = chainConfig.contracts.hub ?? '';\n return this.crossChain.getWormholeExplorerUrl(\n chainConfig.wormholeChainId,\n hubEmitter,\n sequence\n );\n }\n\n // ========================================================================\n // Phase 2: Send & Receive Funds\n // ========================================================================\n\n /**\n * Prepare a transfer with gas estimation\n * Call this before transfer() to show user the cost\n * \n * @param params - Transfer parameters\n * @returns PreparedTransfer with gas estimates and challenge\n */\n async prepareTransfer(params: TransferParams): Promise<PreparedTransfer> {\n const credential = this.passkey.getCredential();\n if (!credential) {\n throw new VeridexError(VeridexErrorCode.NO_CREDENTIAL);\n }\n\n // Build payload and get nonce\n const actionPayload = await this.buildTransferPayload(params);\n const nonce = await this.getNonce();\n \n // Build challenge\n const challenge = buildChallenge(\n credential.keyHash,\n params.targetChain,\n nonce,\n actionPayload\n );\n\n // Get gas estimates - need to type cast for EVM-specific methods\n const evmClient = this.chain as any;\n let estimatedGas = 500000n; // Default\n let gasPrice = 0n;\n \n if (typeof evmClient.getGasPrice === 'function') {\n gasPrice = await evmClient.getGasPrice();\n }\n\n // Get message fee\n const messageFee = await this.getMessageFee();\n\n // Calculate total cost\n const gasCost = estimatedGas * gasPrice;\n const totalCost = gasCost + messageFee;\n const formattedCost = this.formatWei(totalCost);\n\n return {\n params,\n actionPayload,\n nonce,\n challenge,\n estimatedGas,\n gasPrice,\n messageFee,\n totalCost,\n formattedCost,\n preparedAt: Date.now(),\n expiresAt: Date.now() + this.preparedTransferTtl,\n };\n }\n\n /**\n * Get a human-readable summary of a prepared transfer (Issue #26)\n * \n * Use this to show users what they're signing before biometric authentication.\n * The summary includes:\n * - Action type (transfer, bridge, execute, config)\n * - Human-readable amounts (not wei)\n * - Recipient display (truncated address, ENS if available)\n * - Chain information\n * - Risk warnings for unusual transactions\n * - Gas cost breakdown\n * - Expiration countdown\n * \n * @example\n * ```typescript\n * const prepared = await sdk.prepareTransfer({\n * recipient: '0x123...',\n * amount: '1000000000000000000', // 1 ETH in wei\n * tokenAddress: NATIVE_TOKEN_ADDRESS,\n * targetChain: 10004, // Base Sepolia\n * });\n * \n * const summary = await sdk.getTransactionSummary(prepared);\n * console.log(summary.title); // \"Transfer\"\n * console.log(summary.description); // \"Send 1.0 ETH to 0x123...abc\"\n * console.log(summary.details.formattedAmount); // \"1.0\"\n * console.log(summary.risks); // [{ type: 'large_transaction', level: 'high', ... }]\n * ```\n * \n * @param prepared - PreparedTransfer or PreparedBridge from prepare methods\n * @returns Promise<TransactionSummary> with human-readable details\n */\n async getTransactionSummary(prepared: PreparedTransfer | PreparedBridge): Promise<TransactionSummary> {\n return this.transactionParser.parse(prepared);\n }\n\n // ============================================================================\n // Spending Limits (Issue #27)\n // ============================================================================\n\n /**\n * Get current spending limits for your vault\n * \n * @example\n * ```typescript\n * const limits = await sdk.getSpendingLimits();\n * console.log(`Daily remaining: ${limits.dailyRemaining}`);\n * console.log(`Resets in: ${limits.timeUntilReset}ms`);\n * ```\n * \n * @param chainId - Optional chain ID (defaults to current chain)\n * @returns Promise<SpendingLimits> with current limits and usage\n */\n async getSpendingLimits(chainId?: number): Promise<SpendingLimits> {\n const vaultAddress = this.getVaultAddress();\n const effectiveChainId = chainId ?? this.chain.getConfig().wormholeChainId;\n const rpcUrl = this.chainRpcUrls?.[effectiveChainId] ?? this.chain.getConfig().rpcUrl;\n \n return this.spendingLimits.getSpendingLimits(vaultAddress, effectiveChainId, rpcUrl);\n }\n\n /**\n * Get spending limits formatted for UI display\n * \n * @example\n * ```typescript\n * const formatted = await sdk.getFormattedSpendingLimits();\n * console.log(`${formatted.dailyUsedPercentage}% of daily limit used`);\n * console.log(`Resets in: ${formatted.timeUntilReset}`);\n * ```\n */\n async getFormattedSpendingLimits(chainId?: number): Promise<FormattedSpendingLimits> {\n const vaultAddress = this.getVaultAddress();\n const effectiveChainId = chainId ?? this.chain.getConfig().wormholeChainId;\n const rpcUrl = this.chainRpcUrls?.[effectiveChainId] ?? this.chain.getConfig().rpcUrl;\n \n return this.spendingLimits.getFormattedSpendingLimits(vaultAddress, effectiveChainId, { rpcUrl });\n }\n\n /**\n * Check if a transaction amount is within spending limits\n * \n * @example\n * ```typescript\n * const check = await sdk.checkSpendingLimit(ethers.parseEther(\"1.0\"));\n * if (!check.allowed) {\n * console.log(check.message);\n * console.log('Suggestions:', check.suggestions);\n * }\n * ```\n * \n * @param amount - Amount to check (in wei/base units)\n * @param chainId - Optional chain ID\n * @returns LimitCheckResult with allowed status and suggestions\n */\n async checkSpendingLimit(amount: bigint, chainId?: number): Promise<LimitCheckResult> {\n const vaultAddress = this.getVaultAddress();\n const effectiveChainId = chainId ?? this.chain.getConfig().wormholeChainId;\n const rpcUrl = this.chainRpcUrls?.[effectiveChainId] ?? this.chain.getConfig().rpcUrl;\n \n return this.spendingLimits.checkTransactionLimit(vaultAddress, effectiveChainId, amount, { rpcUrl });\n }\n\n /**\n * Prepare a transaction to update the daily spending limit\n * Returns a PreparedTransfer that can be signed and executed\n * \n * @example\n * ```typescript\n * // Set daily limit to 5 ETH\n * const prepared = await sdk.prepareSetDailyLimit(ethers.parseEther(\"5.0\"));\n * const result = await sdk.executeTransfer(prepared, signer);\n * ```\n * \n * @param newLimit - New daily limit (0 = unlimited)\n * @returns PreparedTransfer for signing\n */\n async prepareSetDailyLimit(newLimit: bigint): Promise<PreparedTransfer> {\n const credential = this.passkey.getCredential();\n if (!credential) {\n throw new VeridexError(VeridexErrorCode.NO_CREDENTIAL);\n }\n\n const actionPayload = this.spendingLimits.prepareDailyLimitUpdate(newLimit);\n const nonce = await this.getNonce();\n const targetChain = this.chain.getConfig().wormholeChainId;\n const challenge = buildChallenge(credential.keyHash, targetChain, nonce, actionPayload);\n const messageFee = await this.getMessageFee();\n \n return {\n params: {\n targetChain,\n token: 'native',\n recipient: this.getVaultAddress(),\n amount: 0n,\n },\n actionPayload,\n nonce,\n challenge,\n estimatedGas: 0n,\n gasPrice: 0n,\n messageFee,\n totalCost: messageFee,\n formattedCost: '0',\n preparedAt: Date.now(),\n expiresAt: Date.now() + this.preparedTransferTtl,\n };\n }\n\n /**\n * Prepare a transaction to pause the vault (emergency stop)\n * Pausing prevents all withdrawals until unpaused\n * \n * @example\n * ```typescript\n * const prepared = await sdk.preparePauseVault();\n * const result = await sdk.executeTransfer(prepared, signer);\n * ```\n */\n async preparePauseVault(): Promise<PreparedTransfer> {\n const credential = this.passkey.getCredential();\n if (!credential) {\n throw new VeridexError(VeridexErrorCode.NO_CREDENTIAL);\n }\n\n const actionPayload = this.spendingLimits.preparePauseVault();\n const nonce = await this.getNonce();\n const targetChain = this.chain.getConfig().wormholeChainId;\n const challenge = buildChallenge(credential.keyHash, targetChain, nonce, actionPayload);\n const messageFee = await this.getMessageFee();\n \n return {\n params: {\n targetChain,\n token: 'native',\n recipient: this.getVaultAddress(),\n amount: 0n,\n },\n actionPayload,\n nonce,\n challenge,\n estimatedGas: 0n,\n gasPrice: 0n,\n messageFee,\n totalCost: messageFee,\n formattedCost: '0',\n preparedAt: Date.now(),\n expiresAt: Date.now() + this.preparedTransferTtl,\n };\n }\n\n /**\n * Prepare a transaction to unpause the vault\n * \n * @example\n * ```typescript\n * const prepared = await sdk.prepareUnpauseVault();\n * const result = await sdk.executeTransfer(prepared, signer);\n * ```\n */\n async prepareUnpauseVault(): Promise<PreparedTransfer> {\n const credential = this.passkey.getCredential();\n if (!credential) {\n throw new VeridexError(VeridexErrorCode.NO_CREDENTIAL);\n }\n\n const actionPayload = this.spendingLimits.prepareUnpauseVault();\n const nonce = await this.getNonce();\n const targetChain = this.chain.getConfig().wormholeChainId;\n const challenge = buildChallenge(credential.keyHash, targetChain, nonce, actionPayload);\n const messageFee = await this.getMessageFee();\n \n return {\n params: {\n targetChain,\n token: 'native',\n recipient: this.getVaultAddress(),\n amount: 0n,\n },\n actionPayload,\n nonce,\n challenge,\n estimatedGas: 0n,\n gasPrice: 0n,\n messageFee,\n totalCost: messageFee,\n formattedCost: '0',\n preparedAt: Date.now(),\n expiresAt: Date.now() + this.preparedTransferTtl,\n };\n }\n\n /**\n * Execute a prepared transfer\n * Use this after prepareTransfer() for better UX\n * \n * @param prepared - PreparedTransfer from prepareTransfer()\n * @param signer - Signer to pay for gas\n * @returns TransferResult with tracking info\n */\n async executeTransfer(\n prepared: PreparedTransfer, \n signer: any\n ): Promise<TransferResult> {\n const credential = this.passkey.getCredential();\n if (!credential) {\n throw new VeridexError(VeridexErrorCode.NO_CREDENTIAL);\n }\n\n // ADR-0037: Block direct dispatch if multisig policy protects transfers\n await this.multisig?.assertDirectDispatchAllowed('transfer');\n\n // Check if prepared transfer has expired\n if (Date.now() > prepared.expiresAt) {\n throw new VeridexError(VeridexErrorCode.EXPIRED);\n }\n\n try {\n // Sign with passkey\n const signature = await this.passkey.sign(prepared.challenge);\n\n // Dispatch the transaction\n const result = await this.chain.dispatch(\n signature,\n credential.publicKeyX,\n credential.publicKeyY,\n prepared.params.targetChain,\n prepared.actionPayload,\n prepared.nonce,\n signer\n );\n\n // Track the transaction with cache invalidation on confirmation\n const vaultAddress = this.getVaultAddress();\n const chainConfig = this.chain.getConfig();\n if (result.transactionHash) {\n this.transactions.track(\n result.transactionHash,\n chainConfig.wormholeChainId,\n (state) => {\n if (state.status === 'confirmed' || state.status === 'failed') {\n this.balance.invalidateCache(chainConfig.wormholeChainId, vaultAddress);\n }\n },\n result.sequence\n );\n }\n\n return {\n ...result,\n params: prepared.params,\n timestamp: Date.now(),\n };\n } catch (err) {\n throw normalizeError(err, this.chain.getConfig().name);\n }\n }\n\n /**\n * Enhanced transfer with automatic tracking\n * \n * @param params - Transfer parameters\n * @param signer - Signer to pay for gas\n * @param onStatusChange - Optional callback for transaction status updates\n * @returns TransferResult with tracking info\n */\n async transferWithTracking(\n params: TransferParams,\n signer: any,\n onStatusChange?: TransactionCallback\n ): Promise<TransferResult> {\n const credential = this.passkey.getCredential();\n if (!credential) {\n throw new VeridexError(VeridexErrorCode.NO_CREDENTIAL);\n }\n\n // ADR-0037: Block direct dispatch if multisig policy protects transfers\n await this.multisig?.assertDirectDispatchAllowed('transfer');\n\n try {\n // Execute the transfer\n const actionPayload = await this.buildTransferPayload(params);\n const nonce = await this.getNonce();\n const challenge = buildChallenge(\n credential.keyHash,\n params.targetChain,\n nonce,\n actionPayload\n );\n\n const signature = await this.passkey.sign(challenge);\n\n const result = await this.chain.dispatch(\n signature,\n credential.publicKeyX,\n credential.publicKeyY,\n params.targetChain,\n actionPayload,\n nonce,\n signer\n );\n\n // Track the transaction with cache invalidation on confirmation\n const vaultAddress = this.getVaultAddress();\n const chainConfig = this.chain.getConfig();\n if (result.transactionHash) {\n this.transactions.track(\n result.transactionHash,\n chainConfig.wormholeChainId,\n (state) => {\n if (state.status === 'confirmed' || state.status === 'failed') {\n this.balance.invalidateCache(chainConfig.wormholeChainId, vaultAddress);\n }\n onStatusChange?.(state);\n },\n result.sequence\n );\n }\n\n return {\n ...result,\n params,\n timestamp: Date.now(),\n };\n } catch (err) {\n throw normalizeError(err, this.chain.getConfig().name);\n }\n }\n\n /**\n * Execute a gasless transfer using the relayer\n * \n * This method allows users to send funds without paying gas themselves.\n * The relayer service submits the transaction to the Hub and pays the gas.\n * The relayer then automatically relays the VAA to the destination spoke chain.\n * \n * @param params - Transfer parameters (to, amount, token, targetChain)\n * @param onStatusChange - Optional callback for transaction status updates\n * @returns TransferResult with Hub tx hash and tracking info\n */\n async transferViaRelayer(\n params: TransferParams,\n onStatusChange?: TransactionCallback\n ): Promise<TransferResult> {\n const credential = this.passkey.getCredential();\n if (!credential) {\n throw new VeridexError(VeridexErrorCode.NO_CREDENTIAL);\n }\n\n // ADR-0037: Block direct dispatch if multisig policy protects transfers\n await this.multisig?.assertDirectDispatchAllowed('transfer');\n\n // Ensure relayer is available\n if (!this.relayer) {\n throw new VeridexError(VeridexErrorCode.RELAYER_ERROR, 'Relayer not configured. Please provide relayerUrl in SDK config.');\n }\n\n const chainConfig = this.chain.getConfig();\n\n // Build the action payload (canonical encoding from the active chain client)\n const actionPayload = await this.buildTransferPayload(params);\n\n // Client-first preparation:\n // - fetch Guardian-attested nonce via Wormhole Queries when possible\n // - fall back to hub RPC nonce lookup\n // - prompt user to sign once\n const { authenticateAndPrepare } = await import('../auth/prepareAuth.js');\n const prepared = await authenticateAndPrepare(\n {\n credential,\n targetChain: params.targetChain,\n actionPayload,\n },\n this.queryApiKey ?? ''\n );\n\n const submitRequest = JSON.parse(new TextDecoder().decode(prepared.serializedTx)) as SubmitSignedActionRequest;\n\n // Ensure the request body uses our canonical payload (defensive)\n (submitRequest as any).actionPayload = actionPayload;\n\n const relayerResult = await this.relayer.submitSignedAction(submitRequest);\n\n if (!relayerResult.success) {\n throw new VeridexError(VeridexErrorCode.RELAYER_ERROR, `Relayer submission failed: ${relayerResult.error}`);\n }\n\n // Track the Hub transaction with cache invalidation on confirmation\n const vaultAddress = this.getVaultAddress();\n if (relayerResult.txHash) {\n const hubChainId = chainConfig.hubChainId ?? chainConfig.wormholeChainId;\n this.transactions.track(\n relayerResult.txHash,\n hubChainId,\n (state) => {\n if (state.status === 'confirmed' || state.status === 'failed') {\n this.balance.invalidateCache(chainConfig.wormholeChainId, vaultAddress);\n }\n onStatusChange?.(state);\n },\n relayerResult.sequence ? BigInt(relayerResult.sequence) : undefined\n );\n }\n\n return {\n transactionHash: relayerResult.txHash ?? '',\n sequence: relayerResult.sequence ? BigInt(relayerResult.sequence) : 0n,\n userKeyHash: credential.keyHash,\n targetChain: params.targetChain,\n blockNumber: 0, // Hub tx block number not returned by relayer\n params,\n timestamp: Date.now(),\n };\n }\n\n /**\n * Wait for a transaction to confirm\n * \n * @param hash - Transaction hash\n * @returns TransactionState when confirmed\n */\n async waitForTransaction(hash: string): Promise<TransactionState> {\n const chainConfig = this.chain.getConfig();\n return await this.transactions.waitForConfirmation(hash, chainConfig.wormholeChainId);\n }\n\n // ========================================================================\n // Balance Methods\n // ========================================================================\n\n /**\n * Get native token balance for the current vault\n * \n * @returns TokenBalance with native token balance\n */\n async getVaultNativeBalance(): Promise<TokenBalance> {\n const vaultAddress = this.getVaultAddress();\n const chainConfig = this.chain.getConfig();\n return await this.balance.getNativeBalance(chainConfig.wormholeChainId, vaultAddress);\n }\n\n /**\n * Get all token balances for the current vault\n * \n * @param includeZeroBalances - Whether to include tokens with 0 balance\n * @returns PortfolioBalance with all token balances\n */\n async getVaultBalances(includeZeroBalances: boolean = false): Promise<PortfolioBalance> {\n const vaultAddress = this.getVaultAddress();\n const chainConfig = this.chain.getConfig();\n\n // Prefer Wormhole Queries when possible (faster, Guardian-attested), but preserve\n // existing behavior as a fallback.\n const credential = this.passkey.getCredential();\n if (credential && this.queryApiKey) {\n try {\n const wormholeChainId = chainConfig.wormholeChainId;\n const tokenList = getAllTokens(wormholeChainId);\n const erc20Tokens = tokenList\n .filter((t) => !isNativeToken(t.address))\n .map((t) => t.address);\n\n const { queryPortfolio } = await import('../queries/portfolio.js');\n const result = await queryPortfolio(credential.keyHash, this.queryApiKey, {\n network: this.testnet ? 'testnet' : 'mainnet',\n vaultAddresses: { [wormholeChainId]: vaultAddress },\n evmTokenAddresses: { [wormholeChainId]: erc20Tokens },\n rpcUrls: { [wormholeChainId]: chainConfig.rpcUrl },\n maxAge: 60,\n // Testnet Query Proxy can be slow; use a more forgiving timeout.\n timeout: this.testnet ? 15_000 : 10_000,\n maxAttempts: this.testnet ? 3 : 2,\n });\n\n const chain = result.chains.find((c) => c.wormholeChainId === wormholeChainId);\n if (chain && !chain.error) {\n const byAssetId = new Map(chain.balances.map((b) => [b.assetId.toLowerCase(), b] as const));\n const tokens = tokenList.map((t) => {\n if (isNativeToken(t.address)) {\n return null;\n }\n const found = byAssetId.get(t.address.toLowerCase());\n const amount = found?.amount ?? 0n;\n const formatted = ethers.formatUnits(amount, t.decimals);\n return {\n token: t,\n balance: amount,\n formatted,\n usdValue: found?.usdValue,\n };\n }).filter((t): t is NonNullable<typeof t> => !!t);\n\n // Add native token via RPC (Queries don't support native ETH balance).\n const native = await this.balance.getNativeBalance(wormholeChainId, vaultAddress);\n const merged = [native, ...tokens];\n\n const filtered = includeZeroBalances ? merged : merged.filter((t) => t.balance > 0n);\n const totalUsdValue = filtered.reduce((sum, t) => sum + (t.usdValue ?? 0), 0);\n\n return {\n wormholeChainId,\n chainName: chainConfig.name,\n address: vaultAddress,\n tokens: filtered,\n totalUsdValue: totalUsdValue || undefined,\n lastUpdated: Date.now(),\n };\n }\n } catch {\n // Fall back to the existing RPC-based balance logic.\n }\n }\n\n return await this.balance.getPortfolioBalance(chainConfig.wormholeChainId, vaultAddress, includeZeroBalances);\n }\n\n /**\n * Get token balance for a specific token\n * \n * @param tokenAddress - Token contract address or 'native'\n * @returns TokenBalance for the specified token\n */\n async getVaultTokenBalance(tokenAddress: string): Promise<TokenBalance> {\n const vaultAddress = this.getVaultAddress();\n const chainConfig = this.chain.getConfig();\n return await this.balance.getBalance(\n chainConfig.wormholeChainId,\n vaultAddress,\n tokenAddress\n );\n }\n\n /**\n * Get balances across multiple chains\n * \n * @param chainIds - Array of Wormhole chain IDs to check\n * @returns Array of PortfolioBalance for each chain\n */\n async getMultiChainBalances(chainIds: number[]): Promise<PortfolioBalance[]> {\n const credential = this.passkey.getCredential();\n if (!credential) {\n throw new VeridexError(VeridexErrorCode.NO_CREDENTIAL);\n }\n\n // Derive an address per chain and query balances accordingly.\n const results: PortfolioBalance[] = [];\n\n for (const wormholeChainId of chainIds) {\n const chainConfig = this.chainDetector.getChainConfig(wormholeChainId);\n\n // If unknown, skip with a warning.\n if (!chainConfig) {\n // eslint-disable-next-line no-console\n console.warn(`Unknown chainId for balances: ${wormholeChainId}`);\n continue;\n }\n\n // Resolve vault address\n const derived = this.chainDetector.deriveVaultAddress(credential, wormholeChainId);\n const address = derived?.address ?? (wormholeChainId === this.chain.getConfig().wormholeChainId\n ? this.getVaultAddress()\n : credential.keyHash);\n\n if (chainConfig.isEvm) {\n try {\n const portfolio = await this.balance.getPortfolioBalance(wormholeChainId, address, false);\n results.push(portfolio);\n } catch (error) {\n // eslint-disable-next-line no-console\n console.warn(`Failed to fetch EVM balances for chain ${wormholeChainId}:`, error);\n }\n continue;\n }\n\n // Non-EVM: fetch native balance via chain-specific client\n try {\n const client: any = this.chainDetector.createClient(wormholeChainId);\n if (typeof client.getNativeBalance !== 'function') {\n // eslint-disable-next-line no-console\n console.warn(`No native balance support for chain ${wormholeChainId}`);\n continue;\n }\n\n const native = await client.getNativeBalance(address);\n const meta = this.chainDetector.getNonEvmNativeTokenMeta(wormholeChainId);\n\n const decimals = meta?.decimals ?? 0;\n const formatted = decimals > 0 ? ethers.formatUnits(native, decimals) : native.toString();\n\n results.push({\n wormholeChainId,\n chainName: chainConfig.name,\n address,\n tokens: [\n {\n token: {\n symbol: meta?.symbol ?? 'NATIVE',\n name: meta?.name ?? 'Native Token',\n address: 'native',\n decimals,\n isNative: true,\n },\n balance: native,\n formatted,\n },\n ],\n lastUpdated: Date.now(),\n });\n } catch (error) {\n // eslint-disable-next-line no-console\n console.warn(`Failed to fetch non-EVM balances for chain ${wormholeChainId}:`, error);\n }\n }\n\n return results;\n }\n\n /**\n * Get token list for a chain\n */\n getTokenList(wormholeChainId?: number): TokenInfo[] {\n const chainId = wormholeChainId ?? this.chain.getConfig().wormholeChainId;\n return getAllTokens(chainId);\n }\n\n /**\n * Get token by symbol\n */\n getTokenBySymbol(symbol: string, wormholeChainId?: number): TokenInfo | null {\n const chainId = wormholeChainId ?? this.chain.getConfig().wormholeChainId;\n return getTokenBySymbol(chainId, symbol);\n }\n\n // ========================================================================\n // Multi-Chain Convenience Methods\n // ========================================================================\n\n /**\n * Get vault addresses across all supported chains at once.\n *\n * Unlike calling `getVaultAddressForChain()` in a loop, this returns a\n * structured map that frontends can render directly.\n *\n * @example\n * ```typescript\n * const addresses = sdk.getMultiChainAddresses();\n * for (const [chainId, addr] of Object.entries(addresses)) {\n * console.log(`Chain ${chainId}: ${addr}`);\n * }\n * ```\n */\n getMultiChainAddresses(): Record<number, string> {\n const credential = this.passkey.getCredential();\n if (!credential) {\n throw new VeridexError(VeridexErrorCode.NO_CREDENTIAL);\n }\n\n const supportedChains = this.sponsor.getSupportedChains();\n const addresses: Record<number, string> = {};\n\n // Always include the current chain\n const currentChainId = this.chain.getConfig().wormholeChainId;\n addresses[currentChainId] = this.chain.computeVaultAddress(credential.keyHash);\n\n for (const chain of supportedChains) {\n if (addresses[chain.wormholeChainId]) continue;\n const addr = this.getVaultAddressForChain(chain.wormholeChainId, credential.keyHash);\n if (addr) {\n addresses[chain.wormholeChainId] = addr;\n }\n }\n\n return addresses;\n }\n\n /**\n * Get a combined portfolio view across multiple chains.\n *\n * Returns vault address + balances per chain, suitable for a dashboard or\n * portfolio summary screen.\n *\n * @example\n * ```typescript\n * const portfolio = await sdk.getMultiChainPortfolio();\n * for (const entry of portfolio) {\n * console.log(`${entry.chainName}: ${entry.tokens.length} tokens`);\n * }\n * ```\n *\n * @param chainIds - Optional array of Wormhole chain IDs. Defaults to all sponsored chains.\n */\n async getMultiChainPortfolio(chainIds?: number[]): Promise<PortfolioBalance[]> {\n const credential = this.passkey.getCredential();\n if (!credential) {\n throw new VeridexError(VeridexErrorCode.NO_CREDENTIAL);\n }\n\n // Default to all sponsored chains plus the current chain\n const ids = chainIds ?? [\n this.chain.getConfig().wormholeChainId,\n ...this.sponsor.getSupportedChains()\n .map(c => c.wormholeChainId)\n .filter(id => id !== this.chain.getConfig().wormholeChainId),\n ];\n\n return this.getMultiChainBalances(ids);\n }\n\n // ========================================================================\n // Receive Address Methods\n // ========================================================================\n\n /**\n * Get receive address information for sharing\n * Use this to generate QR codes or share your vault address\n * \n * @returns ReceiveAddress with address and sharing info\n */\n getReceiveAddress(): ReceiveAddress {\n const vaultAddress = this.getVaultAddress();\n const chainConfig = this.chain.getConfig();\n \n // Create a deep link for wallet apps (EIP-681 format for EVM)\n const deepLink = chainConfig.isEvm \n ? `ethereum:${vaultAddress}@${chainConfig.chainId}`\n : undefined;\n\n // Create copy-friendly text\n const copyText = `${vaultAddress}`;\n\n return {\n address: vaultAddress,\n chainName: chainConfig.name,\n wormholeChainId: chainConfig.wormholeChainId,\n deepLink,\n copyText,\n };\n }\n\n /**\n * Generate receive address with amount (for payment requests)\n * \n * @param amount - Amount to request\n * @param tokenAddress - Token address or 'native'\n * @param tokenDecimals - Token decimals\n * @returns ReceiveAddress with payment request info\n */\n getPaymentRequest(\n amount: bigint,\n tokenAddress: string = 'native',\n tokenDecimals: number = 18\n ): ReceiveAddress {\n const vaultAddress = this.getVaultAddress();\n const chainConfig = this.chain.getConfig();\n \n // Format amount\n const formattedAmount = this.formatUnits(amount, tokenDecimals);\n \n // Create EIP-681 payment request for EVM\n let deepLink: string | undefined;\n if (chainConfig.isEvm) {\n if (isNativeToken(tokenAddress)) {\n deepLink = `ethereum:${vaultAddress}@${chainConfig.chainId}?value=${amount.toString()}`;\n } else {\n // ERC20 transfer\n deepLink = `ethereum:${tokenAddress}@${chainConfig.chainId}/transfer?address=${vaultAddress}&uint256=${amount.toString()}`;\n }\n }\n\n return {\n address: vaultAddress,\n chainName: chainConfig.name,\n wormholeChainId: chainConfig.wormholeChainId,\n deepLink,\n copyText: `${vaultAddress} (${formattedAmount})`,\n };\n }\n\n // ========================================================================\n // Utility Methods\n // ========================================================================\n\n /**\n * Format wei to ether string\n */\n private formatWei(wei: bigint): string {\n // Simple formatter - 18 decimals\n const ether = Number(wei) / 1e18;\n return `${ether.toFixed(6)} ETH`;\n }\n\n /**\n * Format units based on decimals\n */\n private formatUnits(amount: bigint, decimals: number): string {\n const divisor = BigInt(10 ** decimals);\n const whole = amount / divisor;\n const remainder = amount % divisor;\n const remainderStr = remainder.toString().padStart(decimals, '0');\n const trimmed = remainderStr.slice(0, 4).replace(/0+$/, '') || '0';\n return `${whole}.${trimmed}`;\n }\n\n\n async getVaultInfo(targetChainId?: number): Promise<VaultInfo | null> {\n const credential = this.passkey.getCredential();\n if (!credential) {\n throw new VeridexError(VeridexErrorCode.NO_CREDENTIAL);\n }\n\n const chainConfig = this.chain.getConfig();\n const checkChainId = targetChainId ?? chainConfig.wormholeChainId;\n\n if (checkChainId !== chainConfig.wormholeChainId) {\n throw new VeridexError(VeridexErrorCode.UNSUPPORTED_FEATURE, 'Cross-chain vault queries not yet supported. Please create a client for the target chain.');\n }\n\n const vaultAddress = await this.chain.getVaultAddress(credential.keyHash);\n const exists = await this.chain.vaultExists(credential.keyHash);\n\n if (!vaultAddress || !exists) {\n return null;\n }\n\n return {\n address: vaultAddress,\n ownerKeyHash: credential.keyHash,\n chain: chainConfig.name,\n wormholeChainId: chainConfig.wormholeChainId,\n exists,\n };\n }\n\n // ========================================================================\n // Wallet & Identity Methods\n // ========================================================================\n\n /**\n * Get the deterministic vault address for the current credential\n * This computes the address off-chain without requiring the vault to exist\n * \n * @returns The vault address that will be used when vault is created\n */\n getVaultAddress(): string {\n const credential = this.passkey.getCredential();\n if (!credential) {\n throw new VeridexError(VeridexErrorCode.NO_CREDENTIAL);\n }\n\n return this.chain.computeVaultAddress(credential.keyHash);\n }\n\n /**\n * Get the vault address for a specific key hash\n * \n * @param keyHash - The user's key hash\n * @returns The deterministic vault address\n */\n getVaultAddressForKeyHash(keyHash: string): string {\n return this.chain.computeVaultAddress(keyHash);\n }\n\n /**\n * Get the vault address for a specific chain\n * Each EVM chain has its own factory contract, so vault addresses are chain-specific.\n * \n * @param wormholeChainId - The Wormhole chain ID\n * @param keyHash - Optional key hash (defaults to current credential)\n * @returns The deterministic vault address for that chain, or null if chain not supported\n */\n getVaultAddressForChain(wormholeChainId: number, keyHash?: string): string | null {\n const hash = keyHash ?? this.passkey.getCredential()?.keyHash;\n if (!hash) {\n throw new VeridexError(VeridexErrorCode.NO_CREDENTIAL, 'No credential set and no keyHash provided');\n }\n\n const credential = { keyHash: hash } as PasskeyCredential;\n const derived = this.chainDetector.deriveVaultAddress(credential, wormholeChainId);\n return derived?.address ?? null;\n }\n\n /**\n * Get vault balances for a specific chain\n * Unlike getVaultBalances() which uses the hub chain, this fetches for any EVM chain.\n * \n * @param wormholeChainId - The Wormhole chain ID\n * @param includeZeroBalances - Whether to include tokens with 0 balance\n * @returns PortfolioBalance with all token balances for that chain\n */\n async getVaultBalancesForChain(\n wormholeChainId: number,\n includeZeroBalances: boolean = false\n ): Promise<PortfolioBalance> {\n const credential = this.passkey.getCredential();\n if (!credential) {\n throw new VeridexError(VeridexErrorCode.NO_CREDENTIAL);\n }\n\n // Get the correct vault address for this chain\n const vaultAddress = this.getVaultAddressForChain(wormholeChainId, credential.keyHash);\n if (!vaultAddress) {\n throw new VeridexError(VeridexErrorCode.VAULT_NOT_FOUND, `Cannot derive vault address for chain ${wormholeChainId}`);\n }\n\n const chainConfig = this.chainDetector.getChainConfig(wormholeChainId);\n if (!chainConfig) {\n throw new VeridexError(VeridexErrorCode.UNSUPPORTED_FEATURE, `Unknown chain ${wormholeChainId}`);\n }\n\n // Try Wormhole Queries first for faster, attested results\n if (this.queryApiKey) {\n try {\n const tokenList = getAllTokens(wormholeChainId);\n const erc20Tokens = tokenList\n .filter((t) => !isNativeToken(t.address))\n .map((t) => t.address);\n\n const rpcUrl = this.chainRpcUrls?.[wormholeChainId] ?? chainConfig.rpcUrl;\n \n const { queryPortfolio } = await import('../queries/portfolio.js');\n const result = await queryPortfolio(credential.keyHash, this.queryApiKey, {\n network: this.testnet ? 'testnet' : 'mainnet',\n vaultAddresses: { [wormholeChainId]: vaultAddress },\n evmTokenAddresses: { [wormholeChainId]: erc20Tokens },\n rpcUrls: { [wormholeChainId]: rpcUrl },\n maxAge: 60,\n timeout: this.testnet ? 15_000 : 10_000,\n maxAttempts: this.testnet ? 3 : 2,\n });\n\n const chain = result.chains.find((c) => c.wormholeChainId === wormholeChainId);\n if (chain && !chain.error) {\n const byAssetId = new Map(chain.balances.map((b) => [b.assetId.toLowerCase(), b] as const));\n const tokens = tokenList.map((t) => {\n if (isNativeToken(t.address)) {\n return null;\n }\n const found = byAssetId.get(t.address.toLowerCase());\n const amount = found?.amount ?? 0n;\n const formatted = ethers.formatUnits(amount, t.decimals);\n return {\n token: t,\n balance: amount,\n formatted,\n usdValue: found?.usdValue,\n };\n }).filter((t): t is NonNullable<typeof t> => !!t);\n\n // Add native token via RPC\n const native = await this.balance.getNativeBalance(wormholeChainId, vaultAddress);\n const merged = [native, ...tokens];\n\n const filtered = includeZeroBalances ? merged : merged.filter((t) => t.balance > 0n);\n const totalUsdValue = filtered.reduce((sum, t) => sum + (t.usdValue ?? 0), 0);\n\n return {\n wormholeChainId,\n chainName: chainConfig.name,\n address: vaultAddress,\n tokens: filtered,\n totalUsdValue: totalUsdValue || undefined,\n lastUpdated: Date.now(),\n };\n }\n } catch {\n // Fall back to RPC-based balance fetching\n }\n }\n\n // Fallback to RPC-based balance fetching\n return await this.balance.getPortfolioBalance(wormholeChainId, vaultAddress, includeZeroBalances);\n }\n\n /**\n * Get unified identity with addresses across chains\n * \n * @returns UnifiedIdentity containing credential info and chain addresses\n */\n async getUnifiedIdentity(): Promise<UnifiedIdentity> {\n const credential = this.passkey.getCredential();\n if (!credential) {\n throw new VeridexError(VeridexErrorCode.NO_CREDENTIAL);\n }\n\n // Check if we have cached identity\n if (this.unifiedIdentity && this.unifiedIdentity.keyHash === credential.keyHash) {\n return this.unifiedIdentity;\n }\n\n // Try to load from storage first\n const storedIdentity = this.wallet.loadIdentityFromStorage(credential.keyHash);\n if (storedIdentity) {\n this.unifiedIdentity = storedIdentity;\n // Update deployment status from chain\n await this.updateDeploymentStatus();\n return this.unifiedIdentity;\n }\n\n // Build new identity\n const chainConfig = this.chain.getConfig();\n const addresses: ChainAddress[] = [];\n\n // Compute address for current chain\n try {\n const address = this.chain.computeVaultAddress(credential.keyHash);\n const deployed = await this.chain.vaultExists(credential.keyHash);\n \n addresses.push({\n wormholeChainId: chainConfig.wormholeChainId,\n chainName: chainConfig.name,\n address,\n isEvm: chainConfig.isEvm,\n deployed,\n derivationType: 'create2',\n });\n } catch (error) {\n console.warn('Could not compute vault address for current chain:', error);\n }\n\n this.unifiedIdentity = {\n keyHash: credential.keyHash,\n publicKeyX: credential.publicKeyX,\n publicKeyY: credential.publicKeyY,\n credentialId: credential.credentialId,\n addresses,\n createdAt: Date.now(),\n updatedAt: Date.now(),\n };\n\n return this.unifiedIdentity;\n }\n\n /**\n * Get the current chain address from unified identity\n */\n async getCurrentChainAddress(): Promise<ChainAddress | null> {\n const identity = await this.getUnifiedIdentity();\n const chainConfig = this.chain.getConfig();\n \n return identity.addresses.find(\n a => a.wormholeChainId === chainConfig.wormholeChainId\n ) ?? null;\n }\n\n /**\n * Update deployment status for cached identity\n */\n private async updateDeploymentStatus(): Promise<void> {\n if (!this.unifiedIdentity) return;\n\n const chainConfig = this.chain.getConfig();\n const address = this.unifiedIdentity.addresses.find(\n a => a.wormholeChainId === chainConfig.wormholeChainId\n );\n\n if (address) {\n try {\n const deployed = await this.chain.vaultExists(this.unifiedIdentity.keyHash);\n address.deployed = deployed;\n this.unifiedIdentity.updatedAt = Date.now();\n } catch (error) {\n console.warn('Could not update deployment status:', error);\n }\n }\n }\n\n /**\n * Add a chain address to the unified identity\n * Used when configuring multiple chains\n */\n addChainAddress(address: ChainAddress): void {\n if (!this.unifiedIdentity) {\n throw new VeridexError(VeridexErrorCode.NO_CREDENTIAL, 'No identity loaded. Call getUnifiedIdentity() first.');\n }\n\n const existing = this.unifiedIdentity.addresses.findIndex(\n a => a.wormholeChainId === address.wormholeChainId\n );\n\n if (existing >= 0) {\n this.unifiedIdentity.addresses[existing] = address;\n } else {\n this.unifiedIdentity.addresses.push(address);\n }\n\n this.unifiedIdentity.updatedAt = Date.now();\n }\n\n // ========================================================================\n // Vault Creation Methods\n // ========================================================================\n\n /**\n * Create a vault for the current credential\n * \n * @param signer - The signer to pay for gas\n * @returns VaultCreationResult with address and transaction details\n */\n async createVault(signer: any): Promise<VaultCreationResult> {\n const credential = this.passkey.getCredential();\n if (!credential) {\n throw new VeridexError(VeridexErrorCode.NO_CREDENTIAL);\n }\n\n const result = await this.chain.createVault(credential.keyHash, signer);\n\n // Update cached identity if available\n if (this.unifiedIdentity) {\n const chainConfig = this.chain.getConfig();\n const address = this.unifiedIdentity.addresses.find(\n a => a.wormholeChainId === chainConfig.wormholeChainId\n );\n\n if (address) {\n address.deployed = true;\n address.deploymentTxHash = result.transactionHash;\n } else {\n this.unifiedIdentity.addresses.push({\n wormholeChainId: chainConfig.wormholeChainId,\n chainName: chainConfig.name,\n address: result.address,\n isEvm: chainConfig.isEvm,\n deployed: true,\n deploymentTxHash: result.transactionHash,\n derivationType: 'create2',\n });\n }\n\n this.unifiedIdentity.updatedAt = Date.now();\n }\n\n return result;\n }\n\n /**\n * Create a vault with sponsored gas (Veridex pays for gas)\n * \n * Uses the sponsor wallet configured in SDK initialization.\n * If no sponsor is configured, throws an error.\n * \n * @param wormholeChainId - Optional chain ID for multi-chain creation\n * @returns VaultCreationResult with address and transaction details\n */\n async createVaultSponsored(wormholeChainId?: number): Promise<VaultCreationResult> {\n const credential = this.passkey.getCredential();\n if (!credential) {\n throw new VeridexError(VeridexErrorCode.NO_CREDENTIAL);\n }\n\n if (!this.sponsorPrivateKey) {\n throw new VeridexError(VeridexErrorCode.UNSUPPORTED_FEATURE, 'No sponsor wallet configured. Set sponsorPrivateKey in SDK config.');\n }\n\n // Check if chain client supports sponsored creation\n if (!this.chain.createVaultSponsored) {\n throw new VeridexError(VeridexErrorCode.UNSUPPORTED_FEATURE, 'Current chain client does not support sponsored vault creation');\n }\n\n // Get the appropriate RPC URL for the chain\n const chainConfig = this.chain.getConfig();\n const targetChainId = wormholeChainId ?? chainConfig.wormholeChainId;\n const rpcUrl = this.chainRpcUrls?.[targetChainId] ?? chainConfig.rpcUrl;\n\n const result = await this.chain.createVaultSponsored(\n credential.keyHash,\n this.sponsorPrivateKey,\n rpcUrl\n );\n\n // Update cached identity if available\n if (this.unifiedIdentity) {\n const address = this.unifiedIdentity.addresses.find(\n a => a.wormholeChainId === targetChainId\n );\n\n if (address) {\n address.deployed = true;\n address.deploymentTxHash = result.transactionHash;\n } else {\n this.unifiedIdentity.addresses.push({\n wormholeChainId: targetChainId,\n chainName: chainConfig.name,\n address: result.address,\n isEvm: chainConfig.isEvm,\n deployed: true,\n deploymentTxHash: result.transactionHash,\n derivationType: 'create2',\n });\n }\n\n this.unifiedIdentity.updatedAt = Date.now();\n }\n\n return result;\n }\n\n /**\n * Check if sponsored vault creation is available\n */\n hasSponsoredVaultCreation(): boolean {\n return !!this.sponsorPrivateKey && !!this.chain.createVaultSponsored;\n }\n\n /**\n * Ensure vault exists, creating with sponsor if available\n * Falls back to requiring a signer if no sponsor configured\n * \n * @param signer - Optional signer (only required if no sponsor configured)\n * @returns The vault address\n */\n async ensureVaultAuto(signer?: any): Promise<string> {\n const credential = this.passkey.getCredential();\n if (!credential) {\n throw new VeridexError(VeridexErrorCode.NO_CREDENTIAL);\n }\n\n const exists = await this.chain.vaultExists(credential.keyHash);\n if (exists) {\n return this.getVaultAddress();\n }\n\n // Try sponsored creation first\n if (this.hasSponsoredVaultCreation()) {\n const result = await this.createVaultSponsored();\n return result.address;\n }\n\n // Fall back to signer-based creation\n if (!signer) {\n throw new VeridexError(VeridexErrorCode.UNSUPPORTED_FEATURE, 'No sponsor configured and no signer provided for vault creation');\n }\n\n const result = await this.createVault(signer);\n return result.address;\n }\n\n /**\n * Ensure vault exists, creating if necessary\n * \n * @param signer - The signer to pay for gas (only used if creation needed)\n * @returns The vault address\n */\n async ensureVault(signer: any): Promise<string> {\n const credential = this.passkey.getCredential();\n if (!credential) {\n throw new VeridexError(VeridexErrorCode.NO_CREDENTIAL);\n }\n\n const exists = await this.chain.vaultExists(credential.keyHash);\n if (exists) {\n return this.getVaultAddress();\n }\n\n const result = await this.createVault(signer);\n return result.address;\n }\n\n /**\n * Estimate gas for vault creation\n */\n async estimateVaultCreationGas(): Promise<bigint> {\n const credential = this.passkey.getCredential();\n if (!credential) {\n throw new VeridexError(VeridexErrorCode.NO_CREDENTIAL);\n }\n\n return await this.chain.estimateVaultCreationGas(credential.keyHash);\n }\n\n async vaultExists(): Promise<boolean> {\n const credential = this.passkey.getCredential();\n if (!credential) {\n throw new VeridexError(VeridexErrorCode.NO_CREDENTIAL);\n }\n\n return await this.chain.vaultExists(credential.keyHash);\n }\n\n // ========================================================================\n // Sponsored Vault Creation (Gasless)\n // ========================================================================\n\n /**\n * Check if gas sponsorship is configured\n * \n * @returns true if a sponsor is configured (relayer, integrator, or Veridex)\n */\n isSponsorshipAvailable(): boolean {\n return this.sponsor.isConfigured();\n }\n\n /**\n * Get the active sponsorship source\n * \n * Priority order:\n * 1. 'relayer' - Remote relayer service (future primary)\n * 2. 'integrator' - Platform-provided sponsor key\n * 3. 'veridex' - Veridex default sponsor (fallback)\n * 4. 'none' - No sponsorship available\n * \n * @returns The active sponsorship source\n */\n getSponsorshipSource(): 'relayer' | 'integrator' | 'veridex' | 'none' {\n return this.sponsor.getSponsorshipSource();\n }\n\n /**\n * Get supported chains for sponsored vault creation\n * \n * @returns Array of chain configurations\n */\n getSponsoredChains(): ChainDeploymentConfig[] {\n return this.sponsor.getSupportedChains();\n }\n\n /**\n * Create a vault on a specific chain using gas sponsorship\n * User doesn't need to pay gas - Veridex pays\n * \n * @param wormholeChainId - The Wormhole chain ID to create vault on\n * @returns Result with vault address\n */\n async createSponsoredVault(wormholeChainId: number): Promise<SponsoredVaultResult> {\n const credential = this.passkey.getCredential();\n if (!credential) {\n throw new VeridexError(VeridexErrorCode.NO_CREDENTIAL);\n }\n\n if (!this.sponsor.isConfigured()) {\n throw new VeridexError(VeridexErrorCode.UNSUPPORTED_FEATURE, 'Gas sponsorship not configured. Set sponsorPrivateKey in SDK config.');\n }\n\n const result = await this.sponsor.createVaultOnChain(credential.keyHash, wormholeChainId);\n\n // Update cached identity if successful\n if (result.success && result.vaultAddress && this.unifiedIdentity) {\n const existingAddress = this.unifiedIdentity.addresses.find(\n a => a.wormholeChainId === wormholeChainId\n );\n\n if (existingAddress) {\n existingAddress.deployed = true;\n existingAddress.deploymentTxHash = result.transactionHash;\n existingAddress.address = result.vaultAddress;\n } else {\n this.unifiedIdentity.addresses.push({\n wormholeChainId,\n chainName: result.chain,\n address: result.vaultAddress,\n isEvm: true,\n deployed: true,\n deploymentTxHash: result.transactionHash,\n derivationType: 'create2',\n });\n }\n\n this.unifiedIdentity.updatedAt = Date.now();\n }\n\n return result;\n }\n\n /**\n * Create vaults on all supported chains using gas sponsorship\n * User doesn't need to pay gas - Veridex pays\n * \n * @returns Multi-chain result with all vault addresses\n */\n async createSponsoredVaultsOnAllChains(): Promise<MultiChainVaultResult> {\n const credential = this.passkey.getCredential();\n if (!credential) {\n throw new VeridexError(VeridexErrorCode.NO_CREDENTIAL);\n }\n\n if (!this.sponsor.isConfigured()) {\n throw new VeridexError(VeridexErrorCode.UNSUPPORTED_FEATURE, 'Gas sponsorship not configured. Set sponsorPrivateKey in SDK config.');\n }\n\n const result = await this.sponsor.createVaultsOnAllChains(credential.keyHash);\n\n // Update cached identity with all successful vaults\n if (this.unifiedIdentity) {\n for (const vaultResult of result.results) {\n if (vaultResult.success && vaultResult.vaultAddress) {\n const existingAddress = this.unifiedIdentity.addresses.find(\n a => a.wormholeChainId === vaultResult.wormholeChainId\n );\n\n if (existingAddress) {\n existingAddress.deployed = true;\n existingAddress.deploymentTxHash = vaultResult.transactionHash;\n existingAddress.address = vaultResult.vaultAddress;\n } else {\n this.unifiedIdentity.addresses.push({\n wormholeChainId: vaultResult.wormholeChainId,\n chainName: vaultResult.chain,\n address: vaultResult.vaultAddress,\n isEvm: true,\n deployed: true,\n deploymentTxHash: vaultResult.transactionHash,\n derivationType: 'create2',\n });\n }\n }\n }\n\n this.unifiedIdentity.updatedAt = Date.now();\n }\n\n return result;\n }\n\n /**\n * Check if vaults exist on all supported chains\n * \n * @returns Map of chain ID to vault status\n */\n async checkVaultsOnAllChains(): Promise<Record<number, { exists: boolean; address: string }>> {\n const credential = this.passkey.getCredential();\n if (!credential) {\n throw new VeridexError(VeridexErrorCode.NO_CREDENTIAL);\n }\n\n return await this.sponsor.checkVaultsOnAllChains(credential.keyHash);\n }\n\n /**\n * Ensure vaults exist on all chains, creating if necessary (sponsored)\n * \n * @returns Result with all vault addresses\n */\n async ensureSponsoredVaultsOnAllChains(): Promise<MultiChainVaultResult> {\n const credential = this.passkey.getCredential();\n if (!credential) {\n throw new VeridexError(VeridexErrorCode.NO_CREDENTIAL);\n }\n\n // First check which vaults exist\n const existing = await this.checkVaultsOnAllChains();\n \n // Find chains that need vault creation\n const supportedChains = this.sponsor.getSupportedChains();\n const needsCreation = supportedChains.filter(\n chain => !existing[chain.wormholeChainId]?.exists\n );\n\n if (needsCreation.length === 0) {\n // All vaults exist\n const vaultAddresses: Record<number, string> = {};\n const results: SponsoredVaultResult[] = [];\n\n for (const chain of supportedChains) {\n const status = existing[chain.wormholeChainId];\n vaultAddresses[chain.wormholeChainId] = status?.address || '';\n results.push({\n success: true,\n chain: chain.name,\n wormholeChainId: chain.wormholeChainId,\n vaultAddress: status?.address,\n alreadyExists: true,\n });\n }\n\n return {\n keyHash: credential.keyHash,\n results,\n allSuccessful: true,\n vaultAddresses,\n };\n }\n\n // Create missing vaults\n return await this.createSponsoredVaultsOnAllChains();\n }\n\n // ==========================================================================\n // Backup Passkey / Multi-Key Identity Methods (Issue #22)\n // ==========================================================================\n\n /**\n * Get the identity state for the current passkey\n * Returns information about the identity including key count and root status\n * \n * @returns Identity state or null if no credential set\n */\n async getIdentityState(): Promise<IdentityState | null> {\n const credential = this.passkey.getCredential();\n if (!credential) {\n return null;\n }\n\n const evmClient = this.chain as any;\n if (typeof evmClient.getIdentityState !== 'function') {\n throw new VeridexError(VeridexErrorCode.UNSUPPORTED_FEATURE, 'Identity management not supported on this chain client');\n }\n\n return await evmClient.getIdentityState(credential.keyHash);\n }\n\n /**\n * Get all authorized passkeys for the current identity\n * \n * @returns Array of authorized keys with root status, or null if no credential\n */\n async listAuthorizedPasskeys(): Promise<AuthorizedKey[] | null> {\n const credential = this.passkey.getCredential();\n if (!credential) {\n return null;\n }\n\n const evmClient = this.chain as any;\n if (typeof evmClient.getIdentityState !== 'function') {\n throw new VeridexError(VeridexErrorCode.UNSUPPORTED_FEATURE, 'Identity management not supported on this chain client');\n }\n\n // Get the identity for this key\n const state = await evmClient.getIdentityState(credential.keyHash);\n if (!state.identity || state.identity === ethers.ZeroHash) {\n // Key not registered, return just this key as pending\n return [];\n }\n\n // Get all authorized keys for this identity\n const keyHashes: string[] = await evmClient.getAuthorizedKeys(state.identity);\n \n // Map to AuthorizedKey with root status\n return keyHashes.map(keyHash => ({\n keyHash,\n isRoot: keyHash === state.identity,\n }));\n }\n\n /**\n * Check if the current identity has backup passkeys registered\n * Returns false if only one passkey (the root) is registered\n * \n * @returns True if backup passkeys exist, false otherwise\n */\n async hasBackupPasskeys(): Promise<boolean> {\n const state = await this.getIdentityState();\n if (!state || state.keyCount === 0) {\n return false;\n }\n return state.keyCount > 1;\n }\n\n /**\n * Register a backup passkey for the current identity\n * The backup passkey can be used to recover access if the primary is lost\n * \n * @param newCredential The new passkey credential to add as backup\n * @param signer Ethereum signer to pay gas (optional, uses relayer if not provided)\n * @returns Result with transaction hash and sequence for cross-chain sync\n */\n async addBackupPasskey(\n newCredential: PasskeyCredential,\n signer?: any\n ): Promise<AddBackupKeyResult> {\n const credential = this.passkey.getCredential();\n if (!credential) {\n throw new VeridexError(VeridexErrorCode.NO_CREDENTIAL);\n }\n\n const evmClient = this.chain as any;\n if (typeof evmClient.addBackupKey !== 'function') {\n throw new VeridexError(VeridexErrorCode.UNSUPPORTED_FEATURE, 'Backup passkey management not supported on this chain client');\n }\n\n // Get identity state to ensure we're within limits\n const state = await evmClient.getIdentityState(credential.keyHash);\n if (state.keyCount >= state.maxKeys) {\n throw new VeridexError(VeridexErrorCode.UNAUTHORIZED, `Maximum keys (${state.maxKeys}) already registered for this identity`);\n }\n\n // Check if the new key is already authorized\n const isAlreadyAuthorized = await evmClient.isAuthorizedForIdentity(\n state.identity,\n newCredential.keyHash\n );\n if (isAlreadyAuthorized) {\n throw new VeridexError(VeridexErrorCode.INVALID_ACTION, 'This passkey is already authorized for this identity');\n }\n\n if (!state.identity || state.identity === ethers.ZeroHash) {\n throw new VeridexError(VeridexErrorCode.VAULT_NOT_FOUND, 'Identity not registered. Call registerIdentity() first.');\n }\n\n // Nonce for key-management is stored on the *identity* (not necessarily the signing key)\n const nonce = await this.chain.getNonce(state.identity);\n\n // Challenge = abi.encodePacked(\"VERIDEX_ADD_KEY\", identityKeyHash, newKeyHash, nonce)\n const packedChallenge = ethers.solidityPacked(\n ['string', 'bytes32', 'bytes32', 'uint256'],\n ['VERIDEX_ADD_KEY', state.identity, newCredential.keyHash, nonce]\n );\n\n const signature = await this.passkey.sign(ethers.getBytes(packedChallenge));\n\n if (!signer) {\n throw new VeridexError(VeridexErrorCode.INVALID_ACTION, 'Signer required for backup key registration');\n }\n\n // Call Hub contract to add backup key\n const { receipt, sequence } = await evmClient.addBackupKey(\n signature,\n credential.publicKeyX,\n credential.publicKeyY,\n newCredential.publicKeyX,\n newCredential.publicKeyY,\n nonce,\n signer\n );\n\n // Get updated key count\n const updatedState = await evmClient.getIdentityState(credential.keyHash);\n\n return {\n transactionHash: receipt.hash,\n sequence,\n identity: state.identity,\n newKeyHash: newCredential.keyHash,\n keyCount: updatedState.keyCount,\n };\n }\n\n /**\n * Remove a passkey from the current identity\n * Cannot remove the last remaining passkey\n * \n * @param keyToRemove Hash of the passkey to remove\n * @param signer Ethereum signer to pay gas\n * @returns Result with transaction hash and sequence for cross-chain sync\n */\n async removePasskey(\n keyToRemove: string,\n signer: any\n ): Promise<RemoveKeyResult> {\n const credential = this.passkey.getCredential();\n if (!credential) {\n throw new VeridexError(VeridexErrorCode.NO_CREDENTIAL);\n }\n\n const evmClient = this.chain as any;\n if (typeof evmClient.removeKey !== 'function') {\n throw new VeridexError(VeridexErrorCode.UNSUPPORTED_FEATURE, 'Backup passkey management not supported on this chain client');\n }\n\n // Get identity state\n const state = await evmClient.getIdentityState(credential.keyHash);\n if (state.keyCount <= 1) {\n throw new VeridexError(VeridexErrorCode.INVALID_ACTION, 'Cannot remove the last passkey. At least one must remain.');\n }\n\n // Check if the key to remove is actually authorized\n const isAuthorized = await evmClient.isAuthorizedForIdentity(\n state.identity,\n keyToRemove\n );\n if (!isAuthorized) {\n throw new VeridexError(VeridexErrorCode.UNAUTHORIZED, 'The specified passkey is not authorized for this identity');\n }\n\n if (!state.identity || state.identity === ethers.ZeroHash) {\n throw new VeridexError(VeridexErrorCode.VAULT_NOT_FOUND, 'Identity not registered. Call registerIdentity() first.');\n }\n\n // Nonce for key-management is stored on the *identity*\n const nonce = await this.chain.getNonce(state.identity);\n\n // Challenge = abi.encodePacked(\"VERIDEX_REMOVE_KEY\", identityKeyHash, keyToRemove, nonce)\n const packedChallenge = ethers.solidityPacked(\n ['string', 'bytes32', 'bytes32', 'uint256'],\n ['VERIDEX_REMOVE_KEY', state.identity, keyToRemove, nonce]\n );\n\n const signature = await this.passkey.sign(ethers.getBytes(packedChallenge));\n\n // Call Hub contract to remove key\n const { receipt, sequence } = await evmClient.removeKey(\n signature,\n credential.publicKeyX,\n credential.publicKeyY,\n keyToRemove,\n nonce,\n signer\n );\n\n // Get updated key count\n const updatedState = await evmClient.getIdentityState(credential.keyHash);\n\n return {\n transactionHash: receipt.hash,\n sequence,\n identity: state.identity,\n removedKeyHash: keyToRemove,\n keyCount: updatedState.keyCount,\n };\n }\n\n /**\n * Check if a specific passkey is authorized for the current identity\n * \n * @param keyHash Hash of the passkey to check\n * @returns True if authorized, false otherwise\n */\n async isPasskeyAuthorized(keyHash: string): Promise<boolean> {\n const credential = this.passkey.getCredential();\n if (!credential) {\n return false;\n }\n\n const evmClient = this.chain as any;\n if (typeof evmClient.getIdentityState !== 'function') {\n throw new VeridexError(VeridexErrorCode.UNSUPPORTED_FEATURE, 'Identity management not supported on this chain client');\n }\n\n const state = await evmClient.getIdentityState(credential.keyHash);\n if (!state.identity || state.identity === ethers.ZeroHash) {\n return false;\n }\n\n return await evmClient.isAuthorizedForIdentity(state.identity, keyHash);\n }\n\n /**\n * Get the identity hash for the current passkey\n * This is the keyHash of the first/root passkey registered\n * \n * @returns Identity hash or null if no credential/identity\n */\n async getIdentity(): Promise<string | null> {\n const credential = this.passkey.getCredential();\n if (!credential) {\n return null;\n }\n\n const evmClient = this.chain as any;\n if (typeof evmClient.getIdentityForKey !== 'function') {\n // Fallback: return keyHash as identity (single-key mode)\n return credential.keyHash;\n }\n\n const identity = await evmClient.getIdentityForKey(credential.keyHash);\n if (identity === ethers.ZeroHash) {\n // Not registered yet, return current keyHash\n return credential.keyHash;\n }\n\n return identity;\n }\n\n getCredential(): PasskeyCredential | null {\n return this.passkey.getCredential();\n }\n\n setCredential(credential: PasskeyCredential): void {\n this.passkey.setCredential(credential);\n }\n\n hasCredential(): boolean {\n return this.passkey.getCredential() !== null;\n }\n\n clearCredential(): void {\n this.passkey.clearCredential();\n }\n}\n","/**\n * Gas Sponsor Module\n * \n * Handles sponsored (gasless) vault creation for Veridex users.\n * Uses a Veridex-owned wallet to pay gas fees on behalf of users.\n * \n * This is a temporary solution until the full relayer is built.\n * In the future, this will be handled by:\n * - ERC-4337 Account Abstraction with Paymasters\n * - Dedicated Relayer service\n */\n\nimport { ethers } from 'ethers';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface ChainDeploymentConfig {\n name: string;\n chainId: number;\n wormholeChainId: number;\n rpcUrl: string;\n vaultFactory?: string;\n hubAddress?: string;\n isHub?: boolean;\n}\n\nexport interface SponsoredVaultResult {\n success: boolean;\n chain: string;\n wormholeChainId: number;\n vaultAddress?: string;\n transactionHash?: string;\n error?: string;\n alreadyExists?: boolean;\n}\n\nexport interface MultiChainVaultResult {\n keyHash: string;\n results: SponsoredVaultResult[];\n allSuccessful: boolean;\n vaultAddresses: Record<number, string>; // wormholeChainId -> address\n}\n\nexport interface GasSponsorConfig {\n /** \n * Private key for the sponsor wallet (from env or secure storage)\n * This is the fallback when relayer is not available\n */\n sponsorPrivateKey?: string;\n \n /**\n * Integrator-provided sponsor key (for platforms using Veridex SDK)\n * Takes priority over Veridex default sponsorship\n */\n integratorSponsorKey?: string;\n \n /** \n * Relayer API endpoint for remote sponsorship (primary method)\n * When available, this takes priority over local wallet sponsorship\n */\n relayerUrl?: string;\n \n /** API key for relayer service authentication */\n relayerApiKey?: string;\n \n /** @deprecated Use relayerUrl instead */\n sponsorApiUrl?: string;\n /** @deprecated Use relayerApiKey instead */\n sponsorApiKey?: string;\n \n /** Whether to use testnet configurations */\n testnet?: boolean;\n /** Custom RPC URLs by wormhole chain ID */\n customRpcUrls?: Record<number, string>;\n}\n\n/** Sponsorship source type */\nexport type SponsorshipSource = 'relayer' | 'integrator' | 'veridex' | 'none';\n\n// ============================================================================\n// Constants\n// ============================================================================\n\n// Vault Factory ABI (minimal)\nconst VAULT_FACTORY_ABI = [\n 'function createVault(bytes32 ownerKeyHash) external returns (address)',\n 'function getVault(bytes32 ownerKeyHash) external view returns (address)',\n 'function vaultExists(bytes32 ownerKeyHash) external view returns (bool)',\n 'function computeVaultAddress(bytes32 ownerKeyHash) external view returns (address)',\n 'event VaultCreated(address indexed vault, bytes32 indexed ownerKeyHash, address creator)',\n];\n\n// Testnet chain configurations\nconst TESTNET_CHAINS: ChainDeploymentConfig[] = [\n {\n name: 'Base Sepolia',\n chainId: 84532,\n wormholeChainId: 10004,\n rpcUrl: 'https://sepolia.base.org',\n hubAddress: '0x23a39c294891703146c3607e1FEEB5Fe78F7F28d',\n vaultFactory: '0x31e8dc9428575334739754Ab2bdB0E8b9Dc707FD',\n isHub: true,\n },\n {\n name: 'Optimism Sepolia',\n chainId: 11155420,\n wormholeChainId: 10005,\n rpcUrl: 'https://sepolia.optimism.io',\n vaultFactory: '0x347feeaBB5655a7a80b56D8D554DA30BE6c28225',\n },\n {\n name: 'Arbitrum Sepolia',\n chainId: 421614,\n wormholeChainId: 10003,\n rpcUrl: 'https://sepolia-rollup.arbitrum.io/rpc',\n vaultFactory: '0x708eEE22621A64CDF51d98d3e8D97902D7dF52dD',\n },\n];\n\n// Mainnet chain configurations (for future use)\nconst MAINNET_CHAINS: ChainDeploymentConfig[] = [\n // Will be populated when mainnet is ready\n];\n\n// ============================================================================\n// GasSponsor Class\n// ============================================================================\n\n/**\n * Gas Sponsorship with layered fallback:\n * 1. Relayer (primary) - Remote relayer service handles gas\n * 2. Integrator wallet - Platform using SDK provides their own sponsor key\n * 3. Veridex wallet (fallback) - Veridex's default sponsor wallet\n */\nexport class GasSponsor {\n private config: GasSponsorConfig;\n private sponsorWallet?: ethers.Wallet;\n private integratorWallet?: ethers.Wallet;\n private chains: ChainDeploymentConfig[];\n\n constructor(config: GasSponsorConfig = {}) {\n this.config = config;\n this.chains = config.testnet !== false ? TESTNET_CHAINS : MAINNET_CHAINS;\n\n // Initialize integrator wallet if provided (takes priority)\n if (config.integratorSponsorKey) {\n this.integratorWallet = new ethers.Wallet(config.integratorSponsorKey);\n }\n\n // Initialize Veridex sponsor wallet as fallback\n if (config.sponsorPrivateKey) {\n this.sponsorWallet = new ethers.Wallet(config.sponsorPrivateKey);\n }\n }\n\n /**\n * Determine which sponsorship source is available\n * Priority: Relayer > Integrator > Veridex > None\n */\n getSponsorshipSource(): SponsorshipSource {\n // 1. Check relayer first (future primary method)\n if (this.config.relayerUrl || this.config.sponsorApiUrl) {\n return 'relayer';\n }\n \n // 2. Check integrator-provided wallet\n if (this.integratorWallet) {\n return 'integrator';\n }\n \n // 3. Check Veridex fallback wallet\n if (this.sponsorWallet) {\n return 'veridex';\n }\n \n return 'none';\n }\n\n /**\n * Get the active sponsor wallet (integrator takes priority)\n */\n private getActiveWallet(): ethers.Wallet | undefined {\n return this.integratorWallet || this.sponsorWallet;\n }\n\n /**\n * Get supported chains for vault deployment\n */\n getSupportedChains(): ChainDeploymentConfig[] {\n return this.chains.filter(c => c.vaultFactory);\n }\n\n /**\n * Get the hub chain configuration\n */\n getHubChain(): ChainDeploymentConfig | undefined {\n return this.chains.find(c => c.isHub);\n }\n\n /**\n * Check if sponsor is configured (has relayer, integrator key, or Veridex key)\n */\n isConfigured(): boolean {\n return this.getSponsorshipSource() !== 'none';\n }\n\n /**\n * Get sponsor wallet balance on a specific chain\n */\n async getSponsorBalance(wormholeChainId: number): Promise<bigint> {\n const chain = this.chains.find(c => c.wormholeChainId === wormholeChainId);\n const wallet = this.getActiveWallet();\n if (!chain || !wallet) {\n return BigInt(0);\n }\n\n const rpcUrl = this.config.customRpcUrls?.[wormholeChainId] || chain.rpcUrl;\n const provider = new ethers.JsonRpcProvider(rpcUrl);\n return await provider.getBalance(wallet.address);\n }\n\n /**\n * Check if a vault exists for a given key hash on a chain\n */\n async checkVaultExists(\n keyHash: string,\n wormholeChainId: number\n ): Promise<{ exists: boolean; address: string }> {\n const chain = this.chains.find(c => c.wormholeChainId === wormholeChainId);\n if (!chain || !chain.vaultFactory) {\n return { exists: false, address: ethers.ZeroAddress };\n }\n\n const rpcUrl = this.config.customRpcUrls?.[wormholeChainId] || chain.rpcUrl;\n const provider = new ethers.JsonRpcProvider(rpcUrl);\n const factory = new ethers.Contract(chain.vaultFactory, VAULT_FACTORY_ABI, provider);\n\n try {\n const address = await factory.getVault(keyHash);\n const exists = address !== ethers.ZeroAddress;\n return { exists, address };\n } catch (error) {\n console.error(`Error checking vault on ${chain.name}:`, error);\n return { exists: false, address: ethers.ZeroAddress };\n }\n }\n\n /**\n * Get predicted vault address for a key hash on a chain\n */\n async computeVaultAddress(\n keyHash: string,\n wormholeChainId: number\n ): Promise<string | null> {\n const chain = this.chains.find(c => c.wormholeChainId === wormholeChainId);\n if (!chain || !chain.vaultFactory) {\n return null;\n }\n\n const rpcUrl = this.config.customRpcUrls?.[wormholeChainId] || chain.rpcUrl;\n const provider = new ethers.JsonRpcProvider(rpcUrl);\n const factory = new ethers.Contract(chain.vaultFactory, VAULT_FACTORY_ABI, provider);\n\n try {\n return await factory.computeVaultAddress(keyHash);\n } catch (error) {\n console.error(`Error computing vault address on ${chain.name}:`, error);\n return null;\n }\n }\n\n /**\n * Create a vault on a specific chain (sponsored)\n * \n * Sponsorship priority:\n * 1. Relayer API (future - not yet implemented)\n * 2. Integrator wallet (if provided)\n * 3. Veridex sponsor wallet (fallback)\n */\n async createVaultOnChain(\n keyHash: string,\n wormholeChainId: number\n ): Promise<SponsoredVaultResult> {\n const chain = this.chains.find(c => c.wormholeChainId === wormholeChainId);\n \n if (!chain) {\n return {\n success: false,\n chain: 'Unknown',\n wormholeChainId,\n error: `Chain ${wormholeChainId} not found`,\n };\n }\n\n if (!chain.vaultFactory) {\n return {\n success: false,\n chain: chain.name,\n wormholeChainId,\n error: `No vault factory configured for ${chain.name}`,\n };\n }\n\n const source = this.getSponsorshipSource();\n\n // 1. Check if using relayer API (future primary method)\n if (source === 'relayer') {\n const relayerUrl = this.config.relayerUrl || this.config.sponsorApiUrl;\n if (relayerUrl) {\n return await this.createVaultViaRelayer(keyHash, chain, relayerUrl);\n }\n }\n\n // 2. Use local wallet (integrator or Veridex)\n const wallet = this.getActiveWallet();\n if (!wallet) {\n return {\n success: false,\n chain: chain.name,\n wormholeChainId,\n error: 'No sponsor configured. Set VERIDEX_SPONSOR_KEY or provide integratorSponsorKey.',\n };\n }\n\n const sponsorType = source === 'integrator' ? 'Integrator' : 'Veridex';\n\n try {\n const rpcUrl = this.config.customRpcUrls?.[wormholeChainId] || chain.rpcUrl;\n const provider = new ethers.JsonRpcProvider(rpcUrl);\n const signer = wallet.connect(provider);\n const factory = new ethers.Contract(chain.vaultFactory, VAULT_FACTORY_ABI, signer);\n\n // Check if vault already exists\n const existingVault = await factory.getVault(keyHash);\n if (existingVault !== ethers.ZeroAddress) {\n return {\n success: true,\n chain: chain.name,\n wormholeChainId,\n vaultAddress: existingVault,\n alreadyExists: true,\n };\n }\n\n // Check sponsor balance\n const balance = await provider.getBalance(signer.address);\n if (balance < ethers.parseEther('0.001')) {\n return {\n success: false,\n chain: chain.name,\n wormholeChainId,\n error: `Insufficient ${sponsorType} sponsor balance on ${chain.name}`,\n };\n }\n\n // Create vault\n console.log(`[GasSponsor] Creating vault on ${chain.name} (${sponsorType} sponsored)...`);\n const tx = await factory.createVault(keyHash);\n const receipt = await tx.wait();\n\n // Get vault address from event or direct query\n const vaultAddress = await factory.getVault(keyHash);\n\n console.log(`[GasSponsor] OK Vault created on ${chain.name}: ${vaultAddress}`);\n\n return {\n success: true,\n chain: chain.name,\n wormholeChainId,\n vaultAddress,\n transactionHash: receipt.hash,\n };\n } catch (error: any) {\n console.error(`[GasSponsor] Error creating vault on ${chain.name}:`, error);\n return {\n success: false,\n chain: chain.name,\n wormholeChainId,\n error: error.message || 'Unknown error',\n };\n }\n }\n\n /**\n * Create vault via relayer service (future primary method)\n * \n * The relayer handles:\n * - Gas payment on behalf of users\n * - Transaction submission and monitoring\n * - Rate limiting and abuse prevention\n */\n private async createVaultViaRelayer(\n keyHash: string,\n chain: ChainDeploymentConfig,\n relayerUrl: string\n ): Promise<SponsoredVaultResult> {\n try {\n const apiKey = this.config.relayerApiKey || this.config.sponsorApiKey;\n \n const response = await fetch(`${relayerUrl}/create-vault`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n ...(apiKey && {\n 'Authorization': `Bearer ${apiKey}`,\n }),\n },\n body: JSON.stringify({\n keyHash,\n wormholeChainId: chain.wormholeChainId,\n }),\n });\n\n if (!response.ok) {\n const error = await response.text();\n \n // If relayer fails, try fallback to local wallet\n console.warn(`[GasSponsor] Relayer failed, trying local wallet fallback...`);\n const wallet = this.getActiveWallet();\n if (wallet) {\n return await this.createVaultWithWallet(keyHash, chain, wallet);\n }\n \n throw new Error(`Relayer error: ${error}`);\n }\n\n const result = await response.json();\n return {\n success: true,\n chain: chain.name,\n wormholeChainId: chain.wormholeChainId,\n vaultAddress: result.vaultAddress,\n transactionHash: result.transactionHash,\n alreadyExists: result.alreadyExists,\n };\n } catch (error: any) {\n // Fallback to local wallet if relayer fails\n console.warn(`[GasSponsor] Relayer unavailable: ${error.message}`);\n const wallet = this.getActiveWallet();\n if (wallet) {\n console.log(`[GasSponsor] Falling back to local wallet sponsorship...`);\n return await this.createVaultWithWallet(keyHash, chain, wallet);\n }\n \n return {\n success: false,\n chain: chain.name,\n wormholeChainId: chain.wormholeChainId,\n error: error.message || 'Relayer request failed and no fallback available',\n };\n }\n }\n\n /**\n * Create vault with a specific wallet (internal helper)\n */\n private async createVaultWithWallet(\n keyHash: string,\n chain: ChainDeploymentConfig,\n wallet: ethers.Wallet\n ): Promise<SponsoredVaultResult> {\n if (!chain.vaultFactory) {\n return {\n success: false,\n chain: chain.name,\n wormholeChainId: chain.wormholeChainId,\n error: `No vault factory for ${chain.name}`,\n };\n }\n\n try {\n const rpcUrl = this.config.customRpcUrls?.[chain.wormholeChainId] || chain.rpcUrl;\n const provider = new ethers.JsonRpcProvider(rpcUrl);\n const signer = wallet.connect(provider);\n const factory = new ethers.Contract(chain.vaultFactory, VAULT_FACTORY_ABI, signer);\n\n // Check if vault already exists\n const existingVault = await factory.getVault(keyHash);\n if (existingVault !== ethers.ZeroAddress) {\n return {\n success: true,\n chain: chain.name,\n wormholeChainId: chain.wormholeChainId,\n vaultAddress: existingVault,\n alreadyExists: true,\n };\n }\n\n // Check balance\n const balance = await provider.getBalance(signer.address);\n if (balance < ethers.parseEther('0.001')) {\n return {\n success: false,\n chain: chain.name,\n wormholeChainId: chain.wormholeChainId,\n error: `Insufficient sponsor balance on ${chain.name}`,\n };\n }\n\n // Create vault\n const tx = await factory.createVault(keyHash);\n const receipt = await tx.wait();\n const vaultAddress = await factory.getVault(keyHash);\n\n return {\n success: true,\n chain: chain.name,\n wormholeChainId: chain.wormholeChainId,\n vaultAddress,\n transactionHash: receipt.hash,\n };\n } catch (error: any) {\n return {\n success: false,\n chain: chain.name,\n wormholeChainId: chain.wormholeChainId,\n error: error.message || 'Wallet creation failed',\n };\n }\n }\n\n /**\n * Create vaults on all supported chains (sponsored)\n */\n async createVaultsOnAllChains(keyHash: string): Promise<MultiChainVaultResult> {\n const supportedChains = this.getSupportedChains();\n const results: SponsoredVaultResult[] = [];\n const vaultAddresses: Record<number, string> = {};\n\n console.log(`[GasSponsor] Creating vaults on ${supportedChains.length} chains...`);\n\n // Create vaults in parallel (or sequentially for rate limiting)\n for (const chain of supportedChains) {\n const result = await this.createVaultOnChain(keyHash, chain.wormholeChainId);\n results.push(result);\n\n if (result.success && result.vaultAddress) {\n vaultAddresses[chain.wormholeChainId] = result.vaultAddress;\n }\n }\n\n const allSuccessful = results.every(r => r.success);\n\n return {\n keyHash,\n results,\n allSuccessful,\n vaultAddresses,\n };\n }\n\n /**\n * Check vault status on all chains\n */\n async checkVaultsOnAllChains(keyHash: string): Promise<Record<number, { exists: boolean; address: string }>> {\n const supportedChains = this.getSupportedChains();\n const results: Record<number, { exists: boolean; address: string }> = {};\n\n for (const chain of supportedChains) {\n results[chain.wormholeChainId] = await this.checkVaultExists(keyHash, chain.wormholeChainId);\n }\n\n return results;\n }\n}\n\n// ============================================================================\n// Factory Function\n// ============================================================================\n\n/**\n * Create a GasSponsor instance\n * \n * @example\n * ```ts\n * // With environment variable\n * const sponsor = createGasSponsor({\n * sponsorPrivateKey: process.env.VERIDEX_SPONSOR_KEY,\n * testnet: true,\n * });\n * \n * // Create vaults for a user\n * const result = await sponsor.createVaultsOnAllChains(userKeyHash);\n * ```\n */\nexport function createGasSponsor(config: GasSponsorConfig = {}): GasSponsor {\n return new GasSponsor(config);\n}\n\n// ============================================================================\n// Convenience Functions\n// ============================================================================\n\n/**\n * Quick check if gas sponsorship is available\n */\nexport function isSponsorshipAvailable(): boolean {\n return !!(\n typeof process !== 'undefined' &&\n (process.env?.VERIDEX_SPONSOR_KEY || process.env?.NEXT_PUBLIC_SPONSOR_API_URL)\n );\n}\n\n/**\n * Get chain configurations for display\n */\nexport function getSupportedChainConfigs(testnet: boolean = true): ChainDeploymentConfig[] {\n return (testnet ? TESTNET_CHAINS : MAINNET_CHAINS).filter(c => c.vaultFactory);\n}\n","/**\n * Veridex Protocol SDK - Simplified Initialization\n * \n * Factory functions for easy SDK creation with minimal configuration.\n * \n * @example\n * ```typescript\n * import { createSDK } from '@veridex/sdk';\n * \n * // Simplest usage - testnet by default\n * const sdk = await createSDK('base');\n * \n * // Register passkey and start using\n * await sdk.passkey.register('user@example.com', 'My Wallet');\n * const vault = await sdk.getVaultAddress();\n * ```\n */\n\nimport { VeridexSDK } from './core/VeridexSDK.js';\nimport { EVMClient } from './chains/evm/EVMClient.js';\nimport { AvalancheClient } from './chains/avalanche/AvalancheClient.js';\nimport { SolanaClient } from './chains/solana/SolanaClient.js';\nimport { AptosClient } from './chains/aptos/AptosClient.js';\nimport { SuiClient } from './chains/sui/SuiClient.js';\nimport { StarknetClient } from './chains/starknet/StarknetClient.js';\nimport { StacksClient } from './chains/stacks/StacksClient.js';\nimport {\n CHAIN_PRESETS,\n getChainConfig,\n getChainPreset,\n isHubChain,\n type ChainName,\n type NetworkType,\n} from './presets.js';\nimport { getEffectivePrimaryHub, isMultiHubEnabled } from './featureFlags.js';\nimport type { ChainClient } from './core/types.js';\n\n// ============================================================================\n// Simple Configuration Interface\n// ============================================================================\n\n/**\n * Simplified SDK configuration\n * Only specify what you need - everything else has sensible defaults\n */\nexport interface SimpleSDKConfig {\n /**\n * Network to connect to\n * @default 'testnet'\n */\n network?: NetworkType;\n\n /**\n * Custom RPC URL (optional - defaults to public endpoints)\n */\n rpcUrl?: string;\n\n /**\n * Relayer URL for gasless transactions (optional)\n */\n relayerUrl?: string;\n\n /**\n * Relayer API key (optional)\n */\n relayerApiKey?: string;\n\n /**\n * Sponsor private key for gasless vault creation (optional)\n * If not provided, users pay their own gas\n */\n sponsorPrivateKey?: string;\n\n /**\n * Integrator sponsor key (optional)\n * Allows platforms to pay for their users' transactions\n */\n integratorSponsorKey?: string;\n\n /**\n * Additional RPC URLs for multi-chain operations\n * Maps chain name to RPC URL\n */\n rpcUrls?: Partial<Record<ChainName, string>>;\n}\n\n/**\n * Session-specific configuration\n */\nexport interface SessionConfig {\n /**\n * Chain to use for sessions\n */\n chain: ChainName;\n\n /**\n * Network to connect to\n * @default 'testnet'\n */\n network?: NetworkType;\n\n /**\n * Session duration in seconds\n * @default 3600 (1 hour)\n */\n duration?: number;\n\n /**\n * Maximum value per transaction\n * @default BigInt(1e18) (1 token)\n */\n maxValue?: bigint;\n\n /**\n * Require user verification for session creation\n * @default true\n */\n requireUV?: boolean;\n}\n\n// ============================================================================\n// Chain Client Factory\n// ============================================================================\n\n/**\n * Create the appropriate chain client based on chain type.\n *\n * Exposed as a public API so integrators can instantiate chain clients\n * independently of the full VeridexSDK constructor (e.g. for testing\n * or for dynamic multi-chain client access).\n */\nexport function createChainClient(\n chain: ChainName,\n network: NetworkType,\n customRpcUrl?: string\n): ChainClient {\n const preset = getChainPreset(chain);\n const config = preset[network];\n const rpcUrl = customRpcUrl || config.rpcUrl;\n\n const requireString = (value: string | undefined, label: string): string => {\n if (!value) {\n throw new Error(`Missing ${label} for chain \"${chain}\" on network \"${network}\"`);\n }\n return value;\n };\n\n // Avalanche gets its own client with ACP-204 + ICM + Chainlink support\n if ((chain as string) === 'avalanche') {\n return new AvalancheClient({\n chainId: config.chainId,\n wormholeChainId: config.wormholeChainId,\n rpcUrl,\n hubContractAddress: requireString(config.contracts.hub, 'hub contract address'),\n wormholeCoreBridge: requireString(config.contracts.wormholeCoreBridge, 'Wormhole core bridge address'),\n vaultFactory: config.contracts.vaultFactory,\n vaultImplementation: config.contracts.vaultImplementation,\n tokenBridge: config.contracts.tokenBridge,\n name: config.name,\n explorerUrl: config.explorerUrl,\n p256VerifierAddress: (config.contracts as any).p256Verifier,\n icmSpokeAddress: (config.contracts as any).icmSpoke,\n chainlinkAvaxUsdFeed: (config.contracts as any).chainlinkAvaxUsd,\n chainlinkUsdcUsdFeed: (config.contracts as any).chainlinkUsdcUsd,\n chainlinkUsdtUsdFeed: (config.contracts as any).chainlinkUsdtUsd,\n });\n }\n\n switch (preset.type) {\n case 'evm':\n return new EVMClient({\n chainId: config.chainId,\n wormholeChainId: config.wormholeChainId,\n rpcUrl,\n hubContractAddress: requireString(config.contracts.hub, 'hub contract address'),\n wormholeCoreBridge: requireString(config.contracts.wormholeCoreBridge, 'Wormhole core bridge address'),\n vaultFactory: config.contracts.vaultFactory,\n vaultImplementation: config.contracts.vaultImplementation,\n tokenBridge: config.contracts.tokenBridge,\n name: config.name,\n explorerUrl: config.explorerUrl,\n });\n\n case 'solana':\n return new SolanaClient({\n rpcUrl,\n programId: requireString(config.contracts.hub, 'programId'),\n wormholeCoreBridge: requireString(config.contracts.wormholeCoreBridge, 'Wormhole core bridge address'),\n tokenBridge: requireString(config.contracts.tokenBridge, 'token bridge address'),\n wormholeChainId: config.wormholeChainId,\n network: network === 'testnet' ? 'devnet' : 'mainnet',\n });\n\n case 'aptos':\n return new AptosClient({\n rpcUrl,\n moduleAddress: requireString(config.contracts.hub, 'moduleAddress'),\n wormholeCoreBridge: requireString(config.contracts.wormholeCoreBridge, 'Wormhole core bridge address'),\n tokenBridge: requireString(config.contracts.tokenBridge, 'token bridge address'),\n wormholeChainId: config.wormholeChainId,\n network: network,\n });\n\n case 'sui':\n return new SuiClient({\n rpcUrl,\n packageId: requireString(config.contracts.hub, 'packageId'),\n wormholeCoreBridge: requireString(config.contracts.wormholeCoreBridge, 'Wormhole core bridge address'),\n wormholeChainId: config.wormholeChainId,\n network: network,\n });\n\n case 'starknet':\n return new StarknetClient({\n rpcUrl,\n spokeContractAddress: config.contracts.hub,\n bridgeContractAddress: config.contracts.wormholeCoreBridge,\n wormholeChainId: config.wormholeChainId,\n network: network === 'testnet' ? 'sepolia' : 'mainnet',\n });\n\n case 'stacks':\n return new StacksClient({\n rpcUrl,\n spokeContractAddress: config.contracts.hub || undefined,\n wormholeChainId: config.wormholeChainId,\n network: network,\n });\n\n case 'near':\n case 'cosmos':\n throw new Error(`Chain type \"${preset.type}\" is not yet supported. Coming soon!`);\n\n default:\n throw new Error(`Unknown chain type: ${preset.type}`);\n }\n}\n\n// ============================================================================\n// SDK Factory Functions\n// ============================================================================\n\n/**\n * Create a Veridex SDK instance with minimal configuration\n * \n * @param chain - Chain name (e.g., 'base', 'optimism', 'solana')\n * @param config - Optional configuration overrides\n * @returns Configured VeridexSDK instance\n * \n * @example\n * ```typescript\n * // Simplest usage - testnet by default\n * const sdk = await createSDK('base');\n * \n * // Use mainnet\n * const mainnetSdk = await createSDK('base', { network: 'mainnet' });\n * \n * // With custom RPC\n * const customSdk = await createSDK('base', { \n * rpcUrl: 'https://my-rpc.example.com' \n * });\n * \n * // With relayer for gasless transactions\n * const gaslessSdk = await createSDK('base', {\n * relayerUrl: 'https://relayer.veridex.network',\n * relayerApiKey: 'your-api-key',\n * });\n * ```\n */\nexport function createSDK(\n chain: ChainName,\n config: SimpleSDKConfig = {}\n): VeridexSDK {\n const network = config.network ?? 'testnet';\n\n // Validate chain exists\n if (!CHAIN_PRESETS[chain]) {\n const supportedChains = Object.keys(CHAIN_PRESETS).join(', ');\n throw new Error(\n `Unknown chain: \"${chain}\". Supported chains: ${supportedChains}`\n );\n }\n\n // Create chain client\n const chainClient = createChainClient(chain, network, config.rpcUrl);\n\n // Build RPC URLs map for multi-chain operations\n const chainRpcUrls: Record<number, string> = {};\n if (config.rpcUrls) {\n for (const [chainName, rpcUrl] of Object.entries(config.rpcUrls)) {\n if (rpcUrl && CHAIN_PRESETS[chainName as ChainName]) {\n const chainConfig = getChainConfig(chainName as ChainName, network);\n chainRpcUrls[chainConfig.wormholeChainId] = rpcUrl;\n }\n }\n }\n\n // Create SDK\n return new VeridexSDK({\n chain: chainClient,\n testnet: network === 'testnet',\n relayerUrl: config.relayerUrl,\n relayerApiKey: config.relayerApiKey,\n sponsorPrivateKey: config.sponsorPrivateKey,\n integratorSponsorKey: config.integratorSponsorKey,\n chainRpcUrls: Object.keys(chainRpcUrls).length > 0 ? chainRpcUrls : undefined,\n });\n}\n\n/**\n * Create SDK for the default hub chain.\n * \n * When multi-hub is disabled, always creates SDK for Base.\n * When enabled, uses the configured primary hub chain.\n * \n * @param config - Optional configuration\n * @returns SDK configured for the primary hub chain\n * \n * @example\n * ```typescript\n * const sdk = createHubSDK();\n * await sdk.passkey.register('user', 'My Wallet');\n * ```\n */\nexport function createHubSDK(config: SimpleSDKConfig = {}): VeridexSDK {\n const hubChain = getEffectivePrimaryHub();\n return createSDK(hubChain, config);\n}\n\n/**\n * Create SDK for testnet (convenience function)\n * \n * @param chain - Chain name\n * @param config - Optional configuration (network is forced to testnet)\n * @returns SDK configured for testnet\n */\nexport function createTestnetSDK(\n chain: ChainName = 'base',\n config: Omit<SimpleSDKConfig, 'network'> = {}\n): VeridexSDK {\n return createSDK(chain, { ...config, network: 'testnet' });\n}\n\n/**\n * Create SDK for mainnet (convenience function)\n * \n * @param chain - Chain name\n * @param config - Optional configuration (network is forced to mainnet)\n * @returns SDK configured for mainnet\n */\nexport function createMainnetSDK(\n chain: ChainName = 'base',\n config: Omit<SimpleSDKConfig, 'network'> = {}\n): VeridexSDK {\n return createSDK(chain, { ...config, network: 'mainnet' });\n}\n\n// ============================================================================\n// Session Factory (for Session Keys)\n// ============================================================================\n\n/**\n * Create a session-enabled SDK\n * \n * @param chain - Chain name\n * @param config - Session configuration\n * @returns SDK configured for session key usage\n * \n * @example\n * ```typescript\n * import { createSessionSDK, SessionManager } from '@veridex/sdk';\n * \n * const sdk = createSessionSDK('base');\n * const sessionManager = new SessionManager({ sdk });\n * \n * // Create a session (one passkey auth)\n * const session = await sessionManager.createSession({\n * duration: 3600,\n * maxValue: BigInt(1e18),\n * });\n * \n * // Execute multiple transactions without prompts\n * await sessionManager.executeWithSession(params, session);\n * ```\n */\nexport function createSessionSDK(\n chain: ChainName = 'base',\n config: SimpleSDKConfig = {}\n): VeridexSDK {\n // Sessions require hub chain with session key support\n if (!isHubChain(chain)) {\n const hubChain = getEffectivePrimaryHub();\n console.warn(\n `Chain \"${chain}\" is not an active hub chain. ` +\n `Consider using \"${hubChain}\" for full session capabilities.` +\n (isMultiHubEnabled() ? '' : ' Enable multi-hub to use other hub-capable chains.')\n );\n }\n\n return createSDK(chain, config);\n}\n\n// ============================================================================\n// Enterprise Factory\n// ============================================================================\n\n/**\n * Enterprise SDK configuration — extends SimpleSDKConfig with required sponsor/relayer keys.\n */\nexport interface EnterpriseSDKConfig extends SimpleSDKConfig {\n /**\n * Sponsor private key for gasless vault creation (required for batch ops)\n */\n sponsorPrivateKey: string;\n\n /**\n * Relayer URL (required for enterprise)\n */\n relayerUrl: string;\n\n /**\n * Relayer API key (required for enterprise)\n */\n relayerApiKey: string;\n}\n\n/**\n * Create an SDK pre-configured for enterprise / integrator back-end use.\n *\n * This factory requires `sponsorPrivateKey`, `relayerUrl`, and `relayerApiKey`\n * — features that enterprise environments always need.\n *\n * @param chain - Chain name (e.g., 'base')\n * @param config - Enterprise-specific configuration\n * @returns VeridexSDK ready for enterprise operations\n *\n * @example\n * ```typescript\n * import { createEnterpriseSDK, EnterpriseManager } from '@veridex/sdk';\n *\n * const sdk = createEnterpriseSDK('base', {\n * sponsorPrivateKey: process.env.SPONSOR_KEY!,\n * relayerUrl: 'https://relayer.veridex.network',\n * relayerApiKey: process.env.RELAYER_KEY!,\n * });\n *\n * const enterprise = new EnterpriseManager({ sdk });\n * ```\n */\nexport function createEnterpriseSDK(\n chain: ChainName,\n config: EnterpriseSDKConfig,\n): VeridexSDK {\n return createSDK(chain, config);\n}\n\n// ============================================================================\n// Type Exports\n// ============================================================================\n\nexport type { ChainName, NetworkType } from './presets.js';\nexport {\n CHAIN_NAMES,\n CHAIN_PRESETS,\n getChainConfig,\n getChainPreset,\n getSupportedChains,\n getHubChains,\n isChainSupported,\n isHubChain,\n getDefaultHub,\n} from './presets.js';\n\n// Feature Flags\nexport {\n getFeatureFlags,\n setFeatureFlags,\n resetFeatureFlags,\n isMultiHubEnabled,\n getEffectivePrimaryHub,\n} from './featureFlags.js';\nexport type { FeatureFlags } from './featureFlags.js';\n","/**\n * Veridex Protocol SDK - Browser Capabilities Detection\n *\n * Detects WebAuthn and passkey capabilities of the current browser/platform.\n * Used to drive UI branching (ROR vs Auth Portal fallback, conditional UI,\n * PRF availability, backup-state awareness, hybrid transport support).\n *\n * @example\n * ```typescript\n * import { detectCapabilities } from '@veridex/sdk';\n *\n * const caps = await detectCapabilities();\n * if (caps.relatedOrigins) {\n * // Direct cross-domain passkey usage\n * } else {\n * // Auth Portal popup/redirect fallback\n * }\n *\n * if (caps.prf) {\n * // Can use PRF extension for recovery vault encryption\n * }\n * ```\n */\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Complete browser capability report for passkey-related features.\n */\nexport interface BrowserCapabilities {\n /** Basic WebAuthn support (navigator.credentials + PublicKeyCredential) */\n webauthn: boolean;\n\n /** Platform authenticator available (Touch ID, Face ID, Windows Hello) */\n platformAuthenticator: boolean;\n\n /** Related Origin Requests (WebAuthn L3) — cross-domain passkey use */\n relatedOrigins: boolean;\n\n /** Conditional UI / autofill-assisted passkey selection */\n conditionalMediation: boolean;\n\n /** Hybrid transport (phone as authenticator via QR/BLE) */\n hybridTransport: boolean;\n\n /** PRF extension (pseudo-random function for key wrapping) */\n prf: boolean;\n\n /** User-verifying platform authenticator (biometric bound) */\n userVerification: boolean;\n\n /** Whether passkeys on this device are backed up / synced to cloud */\n backupEligible: boolean | null;\n\n /** Detected platform / ecosystem */\n platform: PlatformHint;\n\n /** Raw getClientCapabilities result (if available) */\n rawCapabilities: Record<string, boolean> | null;\n}\n\n/**\n * Platform hint for ecosystem-specific guidance.\n */\nexport type PlatformHint =\n | 'apple' // iCloud Keychain\n | 'google' // Google Password Manager\n | 'windows' // Windows Hello\n | 'android' // Android (could be Google PM or third-party)\n | 'linux'\n | 'unknown';\n\n/**\n * Recommendation for the best authentication strategy on this browser.\n */\nexport interface AuthStrategy {\n /** Primary method to attempt */\n primary: 'ror' | 'conditional' | 'portal-popup' | 'portal-redirect';\n /** Fallback if primary fails */\n fallback: 'portal-popup' | 'portal-redirect' | 'none';\n /** Whether hybrid transport is available as an additional option */\n hybridAvailable: boolean;\n /** Human-readable explanation */\n reason: string;\n}\n\n// ============================================================================\n// Platform Detection\n// ============================================================================\n\n/**\n * Detect the current platform/ecosystem from user agent and platform strings.\n */\nexport function detectPlatform(): PlatformHint {\n if (typeof navigator === 'undefined') return 'unknown';\n\n const ua = navigator.userAgent.toLowerCase();\n const platform = (navigator.platform || '').toLowerCase();\n\n if (/iphone|ipad|ipod|macintosh|macos/.test(ua) || /mac/.test(platform)) {\n return 'apple';\n }\n if (/android/.test(ua)) {\n return 'android';\n }\n if (/windows/.test(ua) || /win/.test(platform)) {\n return 'windows';\n }\n if (/cros/.test(ua)) {\n return 'google'; // ChromeOS uses Google Password Manager\n }\n if (/linux/.test(ua) || /linux/.test(platform)) {\n return 'linux';\n }\n\n return 'unknown';\n}\n\n// ============================================================================\n// Capability Detection\n// ============================================================================\n\n/**\n * Detect all browser capabilities related to passkeys and WebAuthn.\n *\n * This performs multiple async checks in parallel for efficiency.\n * Safe to call on any browser — returns sensible defaults for unsupported features.\n */\nexport async function detectCapabilities(): Promise<BrowserCapabilities> {\n // Quick bail for non-browser environments\n if (typeof window === 'undefined' || typeof navigator === 'undefined') {\n return {\n webauthn: false,\n platformAuthenticator: false,\n relatedOrigins: false,\n conditionalMediation: false,\n hybridTransport: false,\n prf: false,\n userVerification: false,\n backupEligible: null,\n platform: 'unknown',\n rawCapabilities: null,\n };\n }\n\n const hasWebAuthn = !!(window.PublicKeyCredential);\n if (!hasWebAuthn) {\n return {\n webauthn: false,\n platformAuthenticator: false,\n relatedOrigins: false,\n conditionalMediation: false,\n hybridTransport: false,\n prf: false,\n userVerification: false,\n backupEligible: null,\n platform: detectPlatform(),\n rawCapabilities: null,\n };\n }\n\n // Run independent checks in parallel\n const [\n platformAuth,\n conditionalUI,\n clientCaps,\n ] = await Promise.all([\n detectPlatformAuthenticator(),\n detectConditionalMediation(),\n detectClientCapabilities(),\n ]);\n\n const platform = detectPlatform();\n\n return {\n webauthn: true,\n platformAuthenticator: platformAuth,\n relatedOrigins: clientCaps?.relatedOrigins ?? false,\n conditionalMediation: conditionalUI,\n hybridTransport: clientCaps?.hybridTransport ?? false,\n prf: clientCaps?.prf ?? false,\n userVerification: platformAuth, // UV requires platform authenticator\n backupEligible: inferBackupEligibility(platform),\n platform,\n rawCapabilities: clientCaps?.raw ?? null,\n };\n}\n\n/**\n * Get the recommended authentication strategy based on detected capabilities.\n */\nexport async function getAuthStrategy(): Promise<AuthStrategy> {\n const caps = await detectCapabilities();\n\n if (caps.relatedOrigins) {\n return {\n primary: 'ror',\n fallback: 'portal-popup',\n hybridAvailable: caps.hybridTransport,\n reason: 'Browser supports Related Origin Requests — direct cross-domain passkey use.',\n };\n }\n\n if (caps.conditionalMediation) {\n return {\n primary: 'conditional',\n fallback: 'portal-popup',\n hybridAvailable: caps.hybridTransport,\n reason: 'Browser supports conditional UI — passkey autofill available, with portal fallback.',\n };\n }\n\n // No ROR or conditional UI — use portal\n if (caps.webauthn && caps.platformAuthenticator) {\n return {\n primary: 'portal-popup',\n fallback: 'portal-redirect',\n hybridAvailable: caps.hybridTransport,\n reason: 'Browser lacks ROR/conditional UI — using Auth Portal popup flow.',\n };\n }\n\n return {\n primary: 'portal-redirect',\n fallback: 'none',\n hybridAvailable: false,\n reason: 'Limited WebAuthn support — using Auth Portal redirect flow.',\n };\n}\n\n// ============================================================================\n// Internal Detection Helpers\n// ============================================================================\n\nasync function detectPlatformAuthenticator(): Promise<boolean> {\n try {\n return await PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable();\n } catch {\n return false;\n }\n}\n\nasync function detectConditionalMediation(): Promise<boolean> {\n try {\n if ('isConditionalMediationAvailable' in PublicKeyCredential) {\n const isAvailable = (PublicKeyCredential as unknown as {\n isConditionalMediationAvailable: () => Promise<boolean>;\n }).isConditionalMediationAvailable;\n return await isAvailable();\n }\n } catch {\n // Not supported\n }\n return false;\n}\n\ninterface ClientCapabilities {\n relatedOrigins: boolean;\n hybridTransport: boolean;\n prf: boolean;\n raw: Record<string, boolean>;\n}\n\nasync function detectClientCapabilities(): Promise<ClientCapabilities | null> {\n try {\n if ('getClientCapabilities' in PublicKeyCredential) {\n const getCapabilities = (PublicKeyCredential as unknown as {\n getClientCapabilities: () => Promise<Record<string, boolean>>;\n }).getClientCapabilities;\n const capabilities = await getCapabilities();\n\n return {\n relatedOrigins: capabilities?.['relatedOrigins'] === true,\n hybridTransport: capabilities?.['hybridTransport'] === true,\n prf: capabilities?.['prf'] === true,\n raw: capabilities ?? {},\n };\n }\n } catch {\n // getClientCapabilities not supported\n }\n return null;\n}\n\n/**\n * Infer backup eligibility based on platform.\n * Returns null if we can't determine (backup state is only available\n * from the authenticator response during registration/authentication).\n */\nfunction inferBackupEligibility(platform: PlatformHint): boolean | null {\n switch (platform) {\n case 'apple':\n return true; // iCloud Keychain syncs passkeys\n case 'google':\n case 'android':\n return true; // Google Password Manager syncs passkeys\n case 'windows':\n return true; // Windows Hello supports passkey backup (Windows 11+)\n case 'linux':\n return false; // No native passkey sync on Linux\n default:\n return null;\n }\n}\n","/**\n * Veridex Protocol SDK - Credential Manager\n *\n * First-class credential inventory management: list, rename, track usage,\n * detect device/platform hints, revoke, and add-backup flows.\n *\n * This module sits on top of PasskeyManager and provides the account-management\n * layer that PasskeyManager's low-level credential storage doesn't cover.\n *\n * @example\n * ```typescript\n * import { CredentialManager } from '@veridex/sdk';\n *\n * const manager = new CredentialManager({ relayerUrl: '...' });\n *\n * // List all credentials with metadata\n * const credentials = manager.listCredentials();\n *\n * // Rename a credential\n * manager.renameCredential(credentialId, 'MacBook Pro');\n *\n * // Check which credential was used most recently\n * const recent = manager.getMostRecentCredential();\n * ```\n */\n\nimport type { PasskeyCredential } from './PasskeyManager.js';\nimport { detectPlatform, type PlatformHint } from './BrowserCapabilities.js';\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Extended credential metadata stored alongside the base PasskeyCredential.\n */\nexport interface CredentialMetadata {\n /** User-assigned display name (e.g., \"MacBook Pro\", \"iPhone 15\") */\n displayName: string;\n\n /** When this credential was first registered (ISO 8601) */\n createdAt: string;\n\n /** When this credential was last used for authentication (ISO 8601) */\n lastUsedAt: string | null;\n\n /** Number of times this credential has been used */\n useCount: number;\n\n /** Platform/ecosystem hint from registration context */\n platformHint: PlatformHint;\n\n /** User agent string at registration time (for device identification) */\n registrationUserAgent: string;\n\n /** Whether the authenticator indicated backup eligibility */\n backupEligible: boolean | null;\n\n /** Whether the authenticator indicated the credential is currently backed up */\n backupState: boolean | null;\n\n /** Whether this is the root (first) credential for the identity */\n isRoot: boolean;\n\n /** Credential status */\n status: 'active' | 'revoked';\n}\n\n/**\n * A credential entry combining the base credential with metadata.\n */\nexport interface ManagedCredential {\n /** Base passkey credential (credentialId, publicKey, keyHash) */\n credential: PasskeyCredential;\n\n /** Extended metadata */\n metadata: CredentialMetadata;\n}\n\n/**\n * Options for adding a credential to the inventory.\n */\nexport interface AddCredentialOptions {\n /** Display name for this credential */\n displayName?: string;\n\n /** Whether this is the root credential */\n isRoot?: boolean;\n\n /** Backup eligibility from authenticator response */\n backupEligible?: boolean;\n\n /** Backup state from authenticator response */\n backupState?: boolean;\n}\n\nexport interface CredentialManagerConfig {\n /** localStorage key for credential metadata */\n storageKey?: string;\n\n /** Relayer URL for remote credential metadata sync */\n relayerUrl?: string;\n}\n\n// ============================================================================\n// Constants\n// ============================================================================\n\nconst DEFAULT_STORAGE_KEY = 'veridex_credential_metadata';\n\n// ============================================================================\n// CredentialManager Class\n// ============================================================================\n\nexport class CredentialManager {\n private config: Required<CredentialManagerConfig>;\n\n constructor(config: CredentialManagerConfig = {}) {\n this.config = {\n storageKey: config.storageKey ?? DEFAULT_STORAGE_KEY,\n relayerUrl: config.relayerUrl ?? '',\n };\n }\n\n // ========================================================================\n // Credential Inventory\n // ========================================================================\n\n /**\n * List all credentials with their metadata.\n * Merges base credentials (from PasskeyManager storage) with metadata.\n */\n listCredentials(): ManagedCredential[] {\n const metadataMap = this.loadMetadataMap();\n const baseCredentials = this.loadBaseCredentials();\n\n return baseCredentials.map(credential => {\n const metadata = metadataMap[credential.credentialId];\n return {\n credential,\n metadata: metadata ?? this.createDefaultMetadata(credential.credentialId),\n };\n });\n }\n\n /**\n * Get a single credential by ID with metadata.\n */\n getCredential(credentialId: string): ManagedCredential | null {\n const all = this.listCredentials();\n return all.find(c => c.credential.credentialId === credentialId) ?? null;\n }\n\n /**\n * Get the most recently used credential.\n */\n getMostRecentCredential(): ManagedCredential | null {\n const all = this.listCredentials();\n if (all.length === 0) return null;\n\n return all.reduce((latest, current) => {\n const latestTime = latest.metadata.lastUsedAt ? new Date(latest.metadata.lastUsedAt).getTime() : 0;\n const currentTime = current.metadata.lastUsedAt ? new Date(current.metadata.lastUsedAt).getTime() : 0;\n return currentTime > latestTime ? current : latest;\n });\n }\n\n /**\n * Get the root (first) credential for the identity.\n */\n getRootCredential(): ManagedCredential | null {\n const all = this.listCredentials();\n return all.find(c => c.metadata.isRoot) ?? null;\n }\n\n /**\n * Get count of active credentials.\n */\n getActiveCount(): number {\n return this.listCredentials().filter(c => c.metadata.status === 'active').length;\n }\n\n // ========================================================================\n // Credential Lifecycle\n // ========================================================================\n\n /**\n * Add a newly registered credential to the inventory with metadata.\n * Call this after PasskeyManager.register() to track the credential.\n */\n addCredential(credential: PasskeyCredential, options: AddCredentialOptions = {}): ManagedCredential {\n const now = new Date().toISOString();\n const existingCredentials = this.listCredentials();\n const isFirst = existingCredentials.length === 0;\n\n const metadata: CredentialMetadata = {\n displayName: options.displayName ?? this.generateDisplayName(),\n createdAt: now,\n lastUsedAt: now,\n useCount: 0,\n platformHint: detectPlatform(),\n registrationUserAgent: typeof navigator !== 'undefined' ? navigator.userAgent : '',\n backupEligible: options.backupEligible ?? null,\n backupState: options.backupState ?? null,\n isRoot: options.isRoot ?? isFirst,\n status: 'active',\n };\n\n this.saveMetadata(credential.credentialId, metadata);\n\n return { credential, metadata };\n }\n\n /**\n * Record that a credential was used for authentication.\n */\n recordUsage(credentialId: string): void {\n const metadataMap = this.loadMetadataMap();\n const metadata = metadataMap[credentialId];\n if (!metadata) return;\n\n metadata.lastUsedAt = new Date().toISOString();\n metadata.useCount += 1;\n this.saveMetadataMap(metadataMap);\n }\n\n /**\n * Rename a credential's display name.\n */\n renameCredential(credentialId: string, displayName: string): boolean {\n const metadataMap = this.loadMetadataMap();\n const metadata = metadataMap[credentialId];\n if (!metadata) return false;\n\n metadata.displayName = displayName;\n this.saveMetadataMap(metadataMap);\n return true;\n }\n\n /**\n * Mark a credential as revoked (local metadata only).\n * Actual on-chain revocation happens through VeridexHub.removeKey().\n */\n markRevoked(credentialId: string): boolean {\n const metadataMap = this.loadMetadataMap();\n const metadata = metadataMap[credentialId];\n if (!metadata) return false;\n\n if (metadata.isRoot) {\n throw new Error('Cannot revoke the root credential. Use identity migration instead.');\n }\n\n metadata.status = 'revoked';\n this.saveMetadataMap(metadataMap);\n return true;\n }\n\n /**\n * Update backup state flags (call after authenticator response provides these).\n */\n updateBackupState(credentialId: string, backupEligible: boolean, backupState: boolean): void {\n const metadataMap = this.loadMetadataMap();\n const metadata = metadataMap[credentialId];\n if (!metadata) return;\n\n metadata.backupEligible = backupEligible;\n metadata.backupState = backupState;\n this.saveMetadataMap(metadataMap);\n }\n\n /**\n * Remove a credential's metadata from local storage.\n * Does NOT remove the base credential from PasskeyManager storage.\n */\n removeMetadata(credentialId: string): void {\n const metadataMap = this.loadMetadataMap();\n delete metadataMap[credentialId];\n this.saveMetadataMap(metadataMap);\n }\n\n // ========================================================================\n // Remote Metadata Sync\n // ========================================================================\n\n /**\n * Sync credential metadata to the relayer for cross-device availability.\n * Only syncs public metadata (display name, platform, timestamps), never keys.\n */\n async syncToRelayer(credentialId: string): Promise<boolean> {\n if (!this.config.relayerUrl) return false;\n\n const managed = this.getCredential(credentialId);\n if (!managed) return false;\n\n try {\n const response = await fetch(`${this.config.relayerUrl}/api/v1/credential/metadata`, {\n method: 'PUT',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n keyHash: managed.credential.keyHash,\n credentialId: managed.credential.credentialId,\n displayName: managed.metadata.displayName,\n platformHint: managed.metadata.platformHint,\n backupEligible: managed.metadata.backupEligible,\n backupState: managed.metadata.backupState,\n isRoot: managed.metadata.isRoot,\n status: managed.metadata.status,\n }),\n });\n\n return response.ok;\n } catch {\n return false;\n }\n }\n\n /**\n * Fetch credential metadata from the relayer (for cross-device restore).\n */\n async fetchFromRelayer(keyHash: string): Promise<ManagedCredential[] | null> {\n if (!this.config.relayerUrl) return null;\n\n try {\n const response = await fetch(\n `${this.config.relayerUrl}/api/v1/credential/metadata?keyHash=${encodeURIComponent(keyHash)}`\n );\n\n if (!response.ok) return null;\n\n const data = await response.json();\n if (!Array.isArray(data.credentials)) return null;\n\n return data.credentials.map((item: Record<string, unknown>) => ({\n credential: {\n credentialId: item.credentialId as string,\n publicKeyX: BigInt(item.publicKeyX as string),\n publicKeyY: BigInt(item.publicKeyY as string),\n keyHash: item.keyHash as string,\n },\n metadata: {\n displayName: (item.displayName as string) || 'Unknown Device',\n createdAt: (item.createdAt as string) || new Date().toISOString(),\n lastUsedAt: (item.lastUsedAt as string) || null,\n useCount: (item.useCount as number) || 0,\n platformHint: (item.platformHint as PlatformHint) || 'unknown',\n registrationUserAgent: '',\n backupEligible: (item.backupEligible as boolean) ?? null,\n backupState: (item.backupState as boolean) ?? null,\n isRoot: (item.isRoot as boolean) ?? false,\n status: (item.status as 'active' | 'revoked') ?? 'active',\n },\n }));\n } catch {\n return null;\n }\n }\n\n // ========================================================================\n // Migration Helpers\n // ========================================================================\n\n /**\n * Get a summary suitable for migration/device-addition flows.\n * Returns what the user should see when deciding to add another device.\n */\n getMigrationSummary(): {\n totalCredentials: number;\n activeCredentials: number;\n platforms: PlatformHint[];\n hasBackup: boolean;\n rootDevice: string | null;\n } {\n const all = this.listCredentials();\n const active = all.filter(c => c.metadata.status === 'active');\n const root = all.find(c => c.metadata.isRoot);\n\n return {\n totalCredentials: all.length,\n activeCredentials: active.length,\n platforms: [...new Set(active.map(c => c.metadata.platformHint))],\n hasBackup: active.some(c => c.metadata.backupState === true),\n rootDevice: root?.metadata.displayName ?? null,\n };\n }\n\n // ========================================================================\n // Internal Storage\n // ========================================================================\n\n private loadMetadataMap(): Record<string, CredentialMetadata> {\n if (typeof window === 'undefined') return {};\n\n try {\n const stored = localStorage.getItem(this.config.storageKey);\n if (!stored) return {};\n return JSON.parse(stored);\n } catch {\n return {};\n }\n }\n\n private saveMetadataMap(map: Record<string, CredentialMetadata>): void {\n if (typeof window === 'undefined') return;\n localStorage.setItem(this.config.storageKey, JSON.stringify(map));\n }\n\n private saveMetadata(credentialId: string, metadata: CredentialMetadata): void {\n const map = this.loadMetadataMap();\n map[credentialId] = metadata;\n this.saveMetadataMap(map);\n }\n\n private loadBaseCredentials(): PasskeyCredential[] {\n if (typeof window === 'undefined') return [];\n\n try {\n const stored = localStorage.getItem('veridex_credentials');\n if (!stored) return [];\n const data = JSON.parse(stored);\n if (!Array.isArray(data)) return [];\n\n return data.map((item: Record<string, unknown>) => ({\n credentialId: item.credentialId as string,\n publicKeyX: BigInt(item.publicKeyX as string),\n publicKeyY: BigInt(item.publicKeyY as string),\n keyHash: item.keyHash as string,\n }));\n } catch {\n return [];\n }\n }\n\n private generateDisplayName(): string {\n const platform = detectPlatform();\n\n const platformNames: Record<PlatformHint, string> = {\n apple: 'Apple Device',\n google: 'Chrome OS',\n android: 'Android Device',\n windows: 'Windows PC',\n linux: 'Linux Device',\n unknown: 'Unknown Device',\n };\n\n const baseName = platformNames[platform];\n const existing = this.listCredentials().filter(\n c => c.metadata.displayName.startsWith(baseName)\n );\n\n if (existing.length === 0) return baseName;\n return `${baseName} (${existing.length + 1})`;\n }\n\n private createDefaultMetadata(_credentialId: string): CredentialMetadata {\n return {\n displayName: this.generateDisplayName(),\n createdAt: new Date().toISOString(),\n lastUsedAt: null,\n useCount: 0,\n platformHint: detectPlatform(),\n registrationUserAgent: typeof navigator !== 'undefined' ? navigator.userAgent : '',\n backupEligible: false,\n backupState: false,\n isRoot: this.listCredentials().length === 0,\n status: 'active',\n };\n }\n}\n","/**\n * Veridex Protocol SDK - Cross-Origin Authentication\n * \n * Enables passkey sharing across different domains using WebAuthn Related Origin Requests.\n * \n * There are two approaches for cross-domain passkey usage:\n * \n * 1. **Related Origin Requests (Recommended)** - W3C Standard\n * - Host a `.well-known/webauthn` file at veridex.network\n * - Third-party apps use rpId: 'veridex.network' directly\n * - Requires browser support for Related Origin Requests\n * - No popup needed, seamless UX\n * \n * 2. **Auth Portal Flow (Fallback)** - Popup/Redirect Pattern\n * - User is redirected to auth.veridex.network\n * - Signs with their passkey at veridex.network\n * - Returns a session token to the third-party app\n * - Works on all browsers, but requires popup/redirect\n * \n * @example Related Origins (Recommended)\n * ```typescript\n * import { createCrossOriginAuth } from '@veridex/sdk';\n * \n * const auth = createCrossOriginAuth();\n * \n * // Check if browser supports Related Origin Requests\n * if (await auth.supportsRelatedOrigins()) {\n * // Direct passkey usage with veridex.network rpId\n * const credential = await auth.authenticate();\n * } else {\n * // Fallback to Auth Portal\n * const session = await auth.authenticateViaPortal();\n * }\n * ```\n * \n * @example Auth Portal Flow\n * ```typescript\n * const auth = createCrossOriginAuth({\n * authPortalUrl: 'https://auth.veridex.network',\n * mode: 'popup', // or 'redirect'\n * });\n * \n * const session = await auth.connectWithVeridex();\n * // session contains: { address, sessionKey, expiresAt }\n * ```\n */\n\nimport { PasskeyManager, type PasskeyCredential, type WebAuthnSignature } from './PasskeyManager.js';\n\n// ============================================================================\n// Constants\n// ============================================================================\n\n// Re-export VERIDEX_RP_ID from PasskeyManager for consistency\nimport { VERIDEX_RP_ID } from './PasskeyManager.js';\nexport { VERIDEX_RP_ID };\n\n/** Default auth portal URL */\nexport const DEFAULT_AUTH_PORTAL_URL = 'https://auth.veridex.network';\n\n/** Default relayer API URL for server-side session tokens */\nexport const DEFAULT_RELAYER_URL = 'https://amused-kameko-veridex-demo-37453117.koyeb.app/api/v1';\n\n/** Message types for postMessage communication */\nexport const AUTH_MESSAGE_TYPES = {\n AUTH_REQUEST: 'VERIDEX_AUTH_REQUEST',\n AUTH_RESPONSE: 'VERIDEX_AUTH_RESPONSE',\n AUTH_ERROR: 'VERIDEX_AUTH_ERROR',\n} as const;\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface CrossOriginAuthConfig {\n /** The Veridex RP ID (defaults to veridex.network) */\n rpId?: string;\n\n /** Auth portal URL for popup/redirect flow */\n authPortalUrl?: string;\n\n /** Relayer API URL for server-side session tokens */\n relayerUrl?: string;\n\n /** Authentication mode: popup or redirect */\n mode?: 'popup' | 'redirect';\n\n /** Popup window features */\n popupFeatures?: string;\n\n /** Timeout for auth operations (ms) */\n timeout?: number;\n\n /** Callback URL for redirect mode */\n redirectUri?: string;\n}\n\nexport interface CrossOriginSession {\n /** User's vault address */\n address: string;\n\n /** Session key public key (for signing transactions) */\n sessionPublicKey: string;\n\n /** Session key (encrypted, stored on client) */\n encryptedSessionKey?: string;\n\n /** When the session expires */\n expiresAt: number;\n\n /** Proof of passkey ownership */\n signature: WebAuthnSignature;\n\n /** The credential used */\n credential: PasskeyCredential;\n\n /** Server-validated session token ID (from relayer) */\n serverSessionId?: string;\n\n /** Relayer-issued challenge binding for server session creation */\n serverChallengeId?: string;\n}\n\n/** Server-side session token returned by the relayer */\nexport interface ServerSessionToken {\n id: string;\n keyHash: string;\n appOrigin: string;\n permissions: string[];\n expiresAt: number;\n createdAt: number;\n}\n\ninterface ServerSessionChallenge {\n id: string;\n value: string;\n expiresAt: number;\n}\n\nexport interface AuthPortalMessage {\n type: typeof AUTH_MESSAGE_TYPES[keyof typeof AUTH_MESSAGE_TYPES];\n payload: CrossOriginSession | { error: string; code: string };\n origin: string;\n}\n\n// ============================================================================\n// CrossOriginAuth Class\n// ============================================================================\n\n/**\n * Manages cross-origin passkey authentication for third-party apps.\n * \n * Third-party developers can use this to enable Veridex passkey authentication\n * in their own applications without users having to create new passkeys.\n */\nexport class CrossOriginAuth {\n private config: Required<CrossOriginAuthConfig>;\n\n constructor(config: CrossOriginAuthConfig = {}) {\n this.config = {\n rpId: config.rpId ?? VERIDEX_RP_ID,\n authPortalUrl: config.authPortalUrl ?? DEFAULT_AUTH_PORTAL_URL,\n relayerUrl: config.relayerUrl ?? DEFAULT_RELAYER_URL,\n mode: config.mode ?? 'popup',\n popupFeatures: config.popupFeatures ?? 'width=500,height=600,left=100,top=100',\n timeout: config.timeout ?? 120000, // 2 minutes\n redirectUri: config.redirectUri ?? (typeof window !== 'undefined' ? window.location.href : ''),\n };\n }\n\n // ========================================================================\n // Browser Capability Detection\n // ========================================================================\n\n /**\n * Check if the browser supports Related Origin Requests.\n * This is a WebAuthn Level 3 feature that allows using passkeys across different domains.\n */\n async supportsRelatedOrigins(): Promise<boolean> {\n if (typeof window === 'undefined' || !window.PublicKeyCredential) {\n return false;\n }\n\n // Check for getClientCapabilities (WebAuthn L3)\n if ('getClientCapabilities' in PublicKeyCredential) {\n try {\n const getCapabilities = (PublicKeyCredential as unknown as { getClientCapabilities: () => Promise<{ relatedOrigins?: boolean }> }).getClientCapabilities;\n const capabilities = await getCapabilities();\n return capabilities?.relatedOrigins === true;\n } catch {\n return false;\n }\n }\n\n return false;\n }\n\n /**\n * Check if WebAuthn is supported at all.\n */\n isSupported(): boolean {\n return PasskeyManager.isSupported();\n }\n\n // ========================================================================\n // Related Origin Requests (Direct Method)\n // ========================================================================\n\n /**\n * Authenticate using Related Origin Requests.\n * This allows using a passkey registered at veridex.network from any origin\n * listed in the /.well-known/webauthn file.\n * \n * @throws If browser doesn't support Related Origin Requests\n * @throws If the current origin isn't listed in veridex.network's well-known file\n */\n async authenticate(challenge?: Uint8Array): Promise<{\n credential: PasskeyCredential;\n signature: WebAuthnSignature;\n }> {\n // Create PasskeyManager with veridex.network as rpId\n const manager = new PasskeyManager({\n rpId: this.config.rpId,\n rpName: 'Veridex Protocol',\n });\n\n // Use discoverable credential flow (passkey autofill)\n return manager.authenticate(challenge);\n }\n\n /**\n * Register a new passkey with veridex.network as the RP.\n * This should only be called from veridex.network origins.\n */\n async register(username: string, displayName: string): Promise<PasskeyCredential> {\n const manager = new PasskeyManager({\n rpId: this.config.rpId,\n rpName: 'Veridex Protocol',\n });\n\n return manager.register(username, displayName);\n }\n\n // ========================================================================\n // Auth Portal Flow (Popup/Redirect)\n // ========================================================================\n\n /**\n * Authenticate via the Veridex Auth Portal.\n * Opens a popup or redirects to auth.veridex.network where the user\n * signs with their passkey, then returns a session to the calling app.\n */\n async connectWithVeridex(options?: {\n sessionChallengeId?: string;\n sessionChallenge?: string;\n }): Promise<CrossOriginSession> {\n if (this.config.mode === 'popup') {\n return this.authenticateViaPopup(options);\n } else {\n return this.initiateRedirectAuth(options);\n }\n }\n\n /**\n * Popup-based authentication flow.\n */\n private async authenticateViaPopup(options?: {\n sessionChallengeId?: string;\n sessionChallenge?: string;\n }): Promise<CrossOriginSession> {\n return new Promise((resolve, reject) => {\n const state = this.generateState();\n const authUrl = new URL('/auth', this.config.authPortalUrl);\n authUrl.searchParams.set('state', state);\n authUrl.searchParams.set('origin', window.location.origin);\n authUrl.searchParams.set('callback', 'postMessage');\n if (options?.sessionChallengeId) {\n authUrl.searchParams.set('challenge_id', options.sessionChallengeId);\n }\n if (options?.sessionChallenge) {\n authUrl.searchParams.set('challenge', options.sessionChallenge);\n }\n\n // Open popup\n const popup = window.open(\n authUrl.toString(),\n 'veridex-auth',\n this.config.popupFeatures\n );\n\n if (!popup) {\n reject(new Error('Failed to open auth popup. Please allow popups for this site.'));\n return;\n }\n\n // Set timeout\n const timeoutId = setTimeout(() => {\n popup.close();\n window.removeEventListener('message', messageHandler);\n reject(new Error('Authentication timed out'));\n }, this.config.timeout);\n\n // Listen for response\n const messageHandler = (event: MessageEvent<AuthPortalMessage>) => {\n // Validate origin\n if (!event.origin.includes('veridex.network')) {\n return;\n }\n\n const { type, payload } = event.data;\n\n if (type === AUTH_MESSAGE_TYPES.AUTH_RESPONSE) {\n clearTimeout(timeoutId);\n window.removeEventListener('message', messageHandler);\n popup.close();\n resolve(payload as CrossOriginSession);\n } else if (type === AUTH_MESSAGE_TYPES.AUTH_ERROR) {\n clearTimeout(timeoutId);\n window.removeEventListener('message', messageHandler);\n popup.close();\n const error = payload as { error: string; code: string };\n reject(new Error(error.error));\n }\n };\n\n window.addEventListener('message', messageHandler);\n });\n }\n\n /**\n * Redirect-based authentication flow.\n * Stores state in sessionStorage and redirects to auth portal.\n */\n private async initiateRedirectAuth(options?: {\n sessionChallengeId?: string;\n sessionChallenge?: string;\n }): Promise<CrossOriginSession> {\n const state = this.generateState();\n\n // Store state for verification after redirect\n sessionStorage.setItem('veridex_auth_state', state);\n sessionStorage.setItem('veridex_auth_redirect', this.config.redirectUri);\n\n const authUrl = new URL('/auth', this.config.authPortalUrl);\n authUrl.searchParams.set('state', state);\n authUrl.searchParams.set('redirect_uri', this.config.redirectUri);\n authUrl.searchParams.set('origin', window.location.origin);\n if (options?.sessionChallengeId) {\n authUrl.searchParams.set('challenge_id', options.sessionChallengeId);\n }\n if (options?.sessionChallenge) {\n authUrl.searchParams.set('challenge', options.sessionChallenge);\n }\n\n // Redirect - this will not resolve, page navigates away\n window.location.href = authUrl.toString();\n\n // This promise never resolves as page navigates\n return new Promise(() => { });\n }\n\n /**\n * Complete redirect-based authentication.\n * Call this on your callback page to extract the session from URL params.\n */\n completeRedirectAuth(): CrossOriginSession | null {\n const params = new URLSearchParams(window.location.search);\n const session = params.get('session');\n const state = params.get('state');\n const error = params.get('error');\n\n // Verify state\n const storedState = sessionStorage.getItem('veridex_auth_state');\n if (state !== storedState) {\n throw new Error('Invalid auth state - possible CSRF attack');\n }\n\n // Clean up\n sessionStorage.removeItem('veridex_auth_state');\n sessionStorage.removeItem('veridex_auth_redirect');\n\n // Clear URL params\n window.history.replaceState({}, '', window.location.pathname);\n\n if (error) {\n throw new Error(error);\n }\n\n if (!session) {\n return null;\n }\n\n return JSON.parse(atob(session)) as CrossOriginSession;\n }\n\n // ========================================================================\n // Utility Methods\n // ========================================================================\n\n /**\n * Generate a random state string for CSRF protection.\n */\n private generateState(): string {\n const array = new Uint8Array(32);\n crypto.getRandomValues(array);\n return Array.from(array, b => b.toString(16).padStart(2, '0')).join('');\n }\n\n private decodeBase64Url(value: string): Uint8Array {\n const base64 = value.replace(/-/g, '+').replace(/_/g, '/');\n const padded = base64 + '='.repeat((4 - (base64.length % 4)) % 4);\n const binary = atob(padded);\n const bytes = new Uint8Array(binary.length);\n\n for (let index = 0; index < binary.length; index++) {\n bytes[index] = binary.charCodeAt(index);\n }\n\n return bytes;\n }\n\n private async requestServerSessionChallenge(options?: {\n keyHash?: string;\n sessionPublicKey?: string;\n permissions?: string[];\n expiresInMs?: number;\n }): Promise<ServerSessionChallenge> {\n const response = await fetch(`${this.config.relayerUrl}/session/challenge`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n keyHash: options?.keyHash,\n appOrigin: typeof window !== 'undefined' ? window.location.origin : '',\n sessionPublicKey: options?.sessionPublicKey ?? '',\n permissions: options?.permissions ?? ['read', 'transfer'],\n expiresInMs: options?.expiresInMs ?? 3600000,\n }),\n });\n\n if (!response.ok) {\n const data = await response.json().catch(() => ({ error: 'Unknown error' }));\n throw new Error(data.error || `Failed to issue server session challenge: ${response.status}`);\n }\n\n const data = await response.json();\n return data.challenge as ServerSessionChallenge;\n }\n\n /**\n * Get the RP ID being used.\n */\n getRpId(): string {\n return this.config.rpId;\n }\n\n /**\n * Get the auth portal URL.\n */\n getAuthPortalUrl(): string {\n return this.config.authPortalUrl;\n }\n\n // ========================================================================\n // Server-Side Session Tokens (ADR-0018)\n // ========================================================================\n\n /**\n * Create a server-validated session token via the relayer.\n * Call this after authenticating (via ROR or auth portal) to get a\n * server-side session that the relayer can verify on subsequent requests.\n */\n async createServerSession(session: CrossOriginSession): Promise<ServerSessionToken> {\n const keyHash = session.credential?.keyHash;\n if (!keyHash) {\n throw new Error('Session must include credential with keyHash');\n }\n if (!session.serverChallengeId) {\n throw new Error('Session must include a relayer-issued serverChallengeId');\n }\n\n const response = await fetch(`${this.config.relayerUrl}/session/create`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n keyHash,\n appOrigin: typeof window !== 'undefined' ? window.location.origin : '',\n sessionPublicKey: session.sessionPublicKey || '',\n challengeId: session.serverChallengeId,\n signature: session.signature,\n }),\n });\n\n if (!response.ok) {\n const data = await response.json().catch(() => ({ error: 'Unknown error' }));\n throw new Error(data.error || `Failed to create server session: ${response.status}`);\n }\n\n const data = await response.json();\n return data.session as ServerSessionToken;\n }\n\n /**\n * Validate an existing server session token.\n * Returns the session details if valid, null if expired/revoked.\n */\n async validateServerSession(sessionId: string): Promise<ServerSessionToken | null> {\n const response = await fetch(`${this.config.relayerUrl}/session/${encodeURIComponent(sessionId)}`);\n\n if (!response.ok) {\n return null;\n }\n\n const data = await response.json();\n if (!data.valid) {\n return null;\n }\n\n return data.session as ServerSessionToken;\n }\n\n /**\n * Revoke a server session token.\n */\n async revokeServerSession(sessionId: string): Promise<boolean> {\n const response = await fetch(`${this.config.relayerUrl}/session/${encodeURIComponent(sessionId)}`, {\n method: 'DELETE',\n });\n return response.ok;\n }\n\n /**\n * Full authentication flow: authenticate + create server session.\n * Automatically detects ROR support and falls back to auth portal.\n */\n async authenticateAndCreateSession(options?: {\n permissions?: string[];\n expiresInMs?: number;\n }): Promise<{ session: CrossOriginSession; serverSession: ServerSessionToken }> {\n let session: CrossOriginSession;\n\n if (await this.supportsRelatedOrigins()) {\n const bootstrap = await this.authenticate();\n const challenge = await this.requestServerSessionChallenge({\n keyHash: bootstrap.credential.keyHash,\n sessionPublicKey: '',\n permissions: options?.permissions,\n expiresInMs: options?.expiresInMs,\n });\n const result = await this.authenticate(this.decodeBase64Url(challenge.value));\n session = {\n address: '',\n sessionPublicKey: '',\n expiresAt: Date.now() + (options?.expiresInMs ?? 3600000),\n signature: result.signature,\n credential: result.credential,\n serverChallengeId: challenge.id,\n };\n } else {\n const bootstrap = await this.connectWithVeridex();\n const challenge = await this.requestServerSessionChallenge({\n keyHash: bootstrap.credential.keyHash,\n sessionPublicKey: bootstrap.sessionPublicKey,\n permissions: options?.permissions,\n expiresInMs: options?.expiresInMs,\n });\n session = await this.connectWithVeridex({\n sessionChallengeId: challenge.id,\n sessionChallenge: challenge.value,\n });\n session.serverChallengeId = challenge.id;\n }\n\n const serverSession = await this.createServerSession(session);\n session.serverSessionId = serverSession.id;\n\n return { session, serverSession };\n }\n}\n\n// ============================================================================\n// Factory Function\n// ============================================================================\n\n/**\n * Create a CrossOriginAuth instance for third-party app integration.\n * \n * @example\n * ```typescript\n * const auth = createCrossOriginAuth();\n * \n * // Check for Related Origin support\n * if (await auth.supportsRelatedOrigins()) {\n * const { credential, signature } = await auth.authenticate();\n * } else {\n * const session = await auth.connectWithVeridex();\n * }\n * ```\n */\nexport function createCrossOriginAuth(config?: CrossOriginAuthConfig): CrossOriginAuth {\n return new CrossOriginAuth(config);\n}\n\n// ============================================================================\n// Auth Portal Helper (for veridex.network auth page)\n// ============================================================================\n\n/**\n * Helper for the auth portal page to send results back to the calling app.\n * Only used on auth.veridex.network, not in third-party apps.\n */\nexport function sendAuthResponse(\n session: CrossOriginSession,\n targetOrigin: string\n): void {\n if (window.opener) {\n // Popup mode\n window.opener.postMessage({\n type: AUTH_MESSAGE_TYPES.AUTH_RESPONSE,\n payload: session,\n origin: window.location.origin,\n }, targetOrigin);\n } else {\n // Redirect mode - encode session in URL\n const redirectUri = new URLSearchParams(window.location.search).get('redirect_uri');\n const state = new URLSearchParams(window.location.search).get('state');\n\n if (redirectUri) {\n const url = new URL(redirectUri);\n url.searchParams.set('session', btoa(JSON.stringify(session)));\n url.searchParams.set('state', state || '');\n window.location.href = url.toString();\n }\n }\n}\n\n/**\n * Helper for the auth portal to send an error back to the calling app.\n */\nexport function sendAuthError(\n error: string,\n code: string,\n targetOrigin: string\n): void {\n if (window.opener) {\n window.opener.postMessage({\n type: AUTH_MESSAGE_TYPES.AUTH_ERROR,\n payload: { error, code },\n origin: window.location.origin,\n }, targetOrigin);\n } else {\n const redirectUri = new URLSearchParams(window.location.search).get('redirect_uri');\n const state = new URLSearchParams(window.location.search).get('state');\n\n if (redirectUri) {\n const url = new URL(redirectUri);\n url.searchParams.set('error', error);\n url.searchParams.set('error_code', code);\n url.searchParams.set('state', state || '');\n window.location.href = url.toString();\n }\n }\n}\n","/**\n * Veridex Protocol SDK — Injected Wallet Adapter\n *\n * Provides a standardized adapter for browser-injected EIP-1193 wallets\n * (MetaMask, Rabby, Coinbase Wallet, etc.). Used as the on-chain signer\n * for Veridex SDK operations that require a funded EOA for gas payment.\n *\n * Capabilities beyond basic connect:\n * - EIP-1193 event forwarding (accountsChanged, chainChanged, disconnect)\n * - Connection state tracking\n * - Clean disconnect with listener teardown\n * - Static availability detection\n *\n * ADR-0040 compliance: This adapter never touches passkey material.\n * It only provides an ethers.Signer for on-chain transaction submission.\n *\n * @module InjectedWalletAdapter\n */\n\nimport { ethers } from 'ethers';\n\ntype Eip1193Provider = {\n request(args: { method: string; params?: unknown[] | object }): Promise<unknown>;\n on?(event: string, handler: (...args: unknown[]) => void): void;\n removeListener?(event: string, handler: (...args: unknown[]) => void): void;\n};\n\ntype WindowWithEthereum = Window & {\n ethereum?: Eip1193Provider;\n};\n\nexport interface InjectedWalletConnection {\n provider: ethers.BrowserProvider;\n signer: ethers.JsonRpcSigner;\n address: string;\n chainId: number;\n}\n\nexport type WalletEvent =\n | { type: 'accountsChanged'; accounts: string[] }\n | { type: 'chainChanged'; chainId: number }\n | { type: 'disconnect'; error?: unknown };\n\nexport type WalletEventCallback = (event: WalletEvent) => void;\n\nexport interface InjectedWalletAdapterConfig {\n expectedChainId?: number;\n autoSwitchChain?: boolean;\n}\n\nexport class InjectedWalletAdapter {\n private readonly config: InjectedWalletAdapterConfig;\n private eventCallbacks: WalletEventCallback[] = [];\n private ethereum: Eip1193Provider | null = null;\n private boundAccountsChanged: ((accounts: unknown) => void) | null = null;\n private boundChainChanged: ((chainId: unknown) => void) | null = null;\n private boundDisconnect: ((error: unknown) => void) | null = null;\n private connection: InjectedWalletConnection | null = null;\n\n constructor(config: InjectedWalletAdapterConfig = {}) {\n this.config = {\n autoSwitchChain: config.autoSwitchChain ?? true,\n expectedChainId: config.expectedChainId,\n };\n }\n\n private getEthereum(): Eip1193Provider {\n if (typeof window === 'undefined') {\n throw new Error('Injected wallet access is only available in the browser.');\n }\n\n const { ethereum } = window as WindowWithEthereum;\n if (!ethereum) {\n throw new Error('No injected EIP-1193 wallet found.');\n }\n\n return ethereum;\n }\n\n isAvailable(): boolean {\n if (typeof window === 'undefined') {\n return false;\n }\n\n return Boolean((window as WindowWithEthereum).ethereum);\n }\n\n /** Returns the current active connection, or null. */\n getConnection(): InjectedWalletConnection | null {\n return this.connection;\n }\n\n async connect(expectedChainId = this.config.expectedChainId): Promise<InjectedWalletConnection> {\n const ethereum = this.getEthereum();\n this.ethereum = ethereum;\n const provider = new ethers.BrowserProvider(ethereum);\n\n await ethereum.request({ method: 'eth_requestAccounts' });\n\n if (expectedChainId && this.config.autoSwitchChain) {\n await this.switchChain(expectedChainId);\n }\n\n const signer = await provider.getSigner();\n const address = await signer.getAddress();\n const network = await provider.getNetwork();\n\n this.connection = {\n provider,\n signer,\n address,\n chainId: Number(network.chainId),\n };\n\n // Start listening for wallet events\n this.attachEventListeners(ethereum);\n\n return this.connection;\n }\n\n /** Disconnect: clears local state and removes event listeners. */\n disconnect(): void {\n this.detachEventListeners();\n this.connection = null;\n this.ethereum = null;\n this.emit({ type: 'disconnect' });\n }\n\n async switchChain(chainId: number): Promise<void> {\n const ethereum = this.getEthereum();\n await ethereum.request({\n method: 'wallet_switchEthereumChain',\n params: [{ chainId: `0x${chainId.toString(16)}` }],\n });\n }\n\n async getCurrentChainId(): Promise<number> {\n const provider = new ethers.BrowserProvider(this.getEthereum());\n const network = await provider.getNetwork();\n return Number(network.chainId);\n }\n\n // ========================================================================\n // Event system\n // ========================================================================\n\n /** Subscribe to wallet events (accountsChanged, chainChanged, disconnect). */\n on(callback: WalletEventCallback): () => void {\n this.eventCallbacks.push(callback);\n return () => {\n this.eventCallbacks = this.eventCallbacks.filter(cb => cb !== callback);\n };\n }\n\n private emit(event: WalletEvent): void {\n for (const cb of this.eventCallbacks) {\n try { cb(event); } catch { /* consumer error — swallow */ }\n }\n }\n\n private attachEventListeners(ethereum: Eip1193Provider): void {\n if (!ethereum.on) return;\n\n this.boundAccountsChanged = (accounts: unknown) => {\n const accts = accounts as string[];\n this.emit({ type: 'accountsChanged', accounts: accts });\n // If accounts empty, the user disconnected inside the wallet\n if (accts.length === 0) {\n this.connection = null;\n }\n };\n\n this.boundChainChanged = (chainId: unknown) => {\n const id = typeof chainId === 'string' ? parseInt(chainId, 16) : Number(chainId);\n if (this.connection) {\n this.connection.chainId = id;\n }\n this.emit({ type: 'chainChanged', chainId: id });\n };\n\n this.boundDisconnect = (error: unknown) => {\n this.connection = null;\n this.emit({ type: 'disconnect', error });\n };\n\n ethereum.on('accountsChanged', this.boundAccountsChanged);\n ethereum.on('chainChanged', this.boundChainChanged);\n ethereum.on('disconnect', this.boundDisconnect);\n }\n\n private detachEventListeners(): void {\n const ethereum = this.ethereum;\n if (!ethereum?.removeListener) return;\n\n if (this.boundAccountsChanged) {\n ethereum.removeListener('accountsChanged', this.boundAccountsChanged);\n }\n if (this.boundChainChanged) {\n ethereum.removeListener('chainChanged', this.boundChainChanged);\n }\n if (this.boundDisconnect) {\n ethereum.removeListener('disconnect', this.boundDisconnect);\n }\n\n this.boundAccountsChanged = null;\n this.boundChainChanged = null;\n this.boundDisconnect = null;\n }\n}\n\nexport function createInjectedWalletAdapter(config?: InjectedWalletAdapterConfig): InjectedWalletAdapter {\n return new InjectedWalletAdapter(config);\n}","/**\n * Veridex Protocol SDK - Session Manager\n * \n * Manages ephemeral session keys for fast, native L1-speed transactions\n * after initial biometric authentication.\n * \n * Key Features:\n * - One-time Passkey auth to create session\n * - Instant software-backed signing for subsequent transactions\n * - Query-based validation on Spokes (no VAA wait)\n * - ~400ms transactions after initial setup\n * - Secure encrypted storage (AES-GCM)\n * - Auto-refresh before expiry\n * - Per-session value limits\n */\n\nimport { ethers } from 'ethers';\nimport type {\n SessionKey,\n SessionConfig,\n SessionSignature,\n SessionManagerConfig,\n SessionStorage,\n SessionEvent,\n SessionEventCallback,\n ActionParams,\n SessionSignedAction,\n} from './types.js';\nimport { SessionError, SessionErrorCode } from './types.js';\nimport {\n generateSecp256k1KeyPair,\n computeSessionKeyHash,\n signWithSessionKey,\n hashAction,\n validateSessionConfig,\n DEFAULT_SESSION_DURATION,\n DEFAULT_REFRESH_BUFFER,\n} from './crypto.js';\nimport { createSessionStorage } from './storage.js';\nimport type { PasskeyCredential } from '../core/PasskeyManager.js';\nimport type { RegisterSessionParams, RevokeSessionParams } from '../types.js';\n\n// ============================================================================\n// Hub Client Interface\n// ============================================================================\n\n/**\n * Interface for Hub contract interactions\n * \n * This should be implemented by chain clients (e.g., EVMHubClientAdapter).\n */\ninterface HubClient {\n /**\n * Register a session on the Hub\n * \n * @param params Registration parameters with Passkey signature\n * @returns Promise that resolves when registration completes\n */\n registerSession(params: RegisterSessionParams): Promise<void>;\n \n /**\n * Revoke a session on the Hub\n * \n * @param params Revocation parameters with Passkey signature\n * @returns Promise that resolves when revocation completes\n */\n revokeSession(params: RevokeSessionParams): Promise<void>;\n\n /**\n * Revoke all sessions for an identity on the Hub (emergency wipe).\n * \n * @param params WebAuthn-signed revocation covering all sessions.\n * @returns Number of sessions revoked.\n */\n revokeAllSessions?(params: RevokeSessionParams): Promise<number>;\n}\n\n// ============================================================================\n// Session Manager Class\n// ============================================================================\n\n/**\n * Manages session key lifecycle and signing operations\n * \n * Usage:\n * ```typescript\n * const manager = new SessionManager(credential, hubClient, passkeySign, config);\n * \n * // Create session (requires biometric)\n * const session = await manager.createSession();\n * \n * // Sign actions instantly (no biometric)\n * const signature = await manager.signWithSession(action);\n * \n * // Revoke session (requires biometric)\n * await manager.revokeSession();\n * ```\n */\nclass SessionManager {\n private currentSession: SessionKey | null = null;\n private storage: SessionStorage;\n private config: Required<SessionConfig>;\n private refreshTimer: NodeJS.Timeout | null = null;\n private eventCallbacks: SessionEventCallback[] = [];\n private debug: boolean;\n \n /**\n * @param credential User's Passkey credential (for Hub interaction)\n * @param hubClient Hub client for on-chain session operations\n * @param passkeySign Function to sign challenges with Passkey\n * @param config Session configuration\n * @param managerConfig SessionManager configuration\n */\n constructor(\n private credential: PasskeyCredential,\n private hubClient: HubClient,\n private passkeySign: (challenge: Uint8Array) => Promise<any>,\n config: Partial<SessionConfig>,\n managerConfig?: SessionManagerConfig\n ) {\n // Validate and set configuration\n this.config = {\n duration: config.duration ?? DEFAULT_SESSION_DURATION,\n maxValue: config.maxValue ?? 0n,\n autoRefresh: config.autoRefresh ?? true,\n refreshBuffer: config.refreshBuffer ?? DEFAULT_REFRESH_BUFFER,\n chainScopes: config.chainScopes ?? [],\n };\n \n validateSessionConfig(this.config);\n \n this.debug = managerConfig?.debug ?? false;\n \n // Initialize storage\n this.storage = managerConfig?.encryptionKey\n ? createSessionStorage(credential.credentialId)\n : createSessionStorage(\n credential.credentialId,\n managerConfig?.storageBackend\n );\n }\n \n // ========================================================================\n // Session Lifecycle\n // ========================================================================\n \n /**\n * Create a new session (requires biometric authentication)\n * \n * Steps:\n * 1. Generate ephemeral secp256k1 key pair\n * 2. Sign session registration with Passkey\n * 3. Register session on Hub contract\n * 4. Store session securely (encrypted)\n * 5. Start auto-refresh timer (if enabled)\n * \n * @returns Created session key\n * @throws SessionError if registration fails\n */\n async createSession(): Promise<SessionKey> {\n try {\n this.log('Creating new session...');\n \n // 1. Generate ephemeral key pair\n const keyPair = generateSecp256k1KeyPair();\n const keyHash = computeSessionKeyHash(keyPair.publicKey);\n \n this.log('Generated session key:', keyHash);\n \n // 2. Prepare challenge for Passkey signing\n const challenge = ethers.solidityPacked(\n ['string', 'bytes32', 'uint256', 'uint256'],\n ['registerSession', keyHash, this.config.duration, this.config.maxValue]\n );\n \n this.log('Challenge prepared, requesting Passkey signature...');\n \n // 3. Sign with Passkey (this triggers biometric prompt)\n const signature = await this.passkeySign(ethers.getBytes(challenge));\n \n this.log('Passkey signature obtained, registering on Hub...');\n \n // 4. Register session on Hub\n const registerParams: RegisterSessionParams = {\n signature,\n publicKeyX: this.credential.publicKeyX,\n publicKeyY: this.credential.publicKeyY,\n sessionKeyHash: keyHash,\n duration: this.config.duration,\n maxValue: this.config.maxValue,\n requireUV: true,\n };\n \n await this.hubClient.registerSession(registerParams);\n \n this.log('Session registered on Hub');\n \n // 5. Create session object\n const expiry = Date.now() + this.config.duration * 1000;\n \n this.currentSession = {\n publicKey: keyPair.publicKey,\n privateKey: keyPair.privateKey,\n keyHash,\n expiry,\n maxValue: this.config.maxValue,\n chainScopes: this.config.chainScopes,\n userKeyHash: this.credential.keyHash,\n };\n \n // 6. Store securely\n await this.storage.save(this.currentSession);\n \n this.log('Session stored securely');\n \n // 7. Start auto-refresh\n if (this.config.autoRefresh) {\n this.scheduleRefresh();\n }\n \n // 8. Emit event\n this.emit({ type: 'session-created', session: this.currentSession });\n \n return this.currentSession;\n \n } catch (error) {\n const sessionError = error instanceof SessionError\n ? error\n : new SessionError(\n 'Failed to create session',\n SessionErrorCode.REGISTRATION_FAILED,\n error\n );\n \n this.emit({ type: 'session-error', error: sessionError });\n throw sessionError;\n }\n }\n \n /**\n * Load existing session from storage\n * \n * @returns Loaded session or null if no valid session exists\n */\n async loadSession(): Promise<SessionKey | null> {\n try {\n this.log('Loading session from storage...');\n \n const session = await this.storage.load();\n \n if (!session) {\n this.log('No session found in storage');\n return null;\n }\n \n // Verify session is not expired\n if (session.expiry <= Date.now()) {\n this.log('Session expired, clearing...');\n await this.storage.clear();\n return null;\n }\n \n this.currentSession = session;\n this.log('Session loaded:', session.keyHash);\n \n // Start auto-refresh if enabled\n if (this.config.autoRefresh) {\n this.scheduleRefresh();\n }\n \n this.emit({ type: 'session-loaded', session });\n \n return session;\n \n } catch (error) {\n this.log('Failed to load session:', error);\n await this.storage.clear();\n return null;\n }\n }\n \n /**\n * Revoke the current session (requires biometric authentication)\n * \n * @throws SessionError if no active session or revocation fails\n */\n async revokeSession(): Promise<void> {\n if (!this.currentSession) {\n throw new SessionError(\n 'No active session to revoke',\n SessionErrorCode.NO_ACTIVE_SESSION\n );\n }\n \n try {\n this.log('Revoking session:', this.currentSession.keyHash);\n \n // 1. Prepare challenge for revocation\n const challenge = ethers.solidityPacked(\n ['string', 'bytes32'],\n ['revokeSession', this.currentSession.keyHash]\n );\n \n // 2. Sign with Passkey (biometric prompt)\n const signature = await this.passkeySign(ethers.getBytes(challenge));\n \n this.log('Passkey signature obtained, revoking on Hub...');\n \n // 3. Revoke on Hub\n const revokeParams: RevokeSessionParams = {\n signature,\n publicKeyX: this.credential.publicKeyX,\n publicKeyY: this.credential.publicKeyY,\n sessionKeyHash: this.currentSession.keyHash,\n requireUV: true,\n };\n \n await this.hubClient.revokeSession(revokeParams);\n \n this.log('Session revoked on Hub');\n \n // 4. Clear local storage\n await this.storage.clear();\n \n // 5. Cancel refresh timer\n if (this.refreshTimer) {\n clearTimeout(this.refreshTimer);\n this.refreshTimer = null;\n }\n \n const revokedKeyHash = this.currentSession.keyHash;\n this.currentSession = null;\n \n // 6. Emit event\n this.emit({ type: 'session-revoked', keyHash: revokedKeyHash });\n \n this.log('Session revoked successfully');\n \n } catch (error) {\n const sessionError = error instanceof SessionError\n ? error\n : new SessionError(\n 'Failed to revoke session',\n SessionErrorCode.REVOCATION_FAILED,\n error\n );\n \n this.emit({ type: 'session-error', error: sessionError });\n throw sessionError;\n }\n }\n\n /**\n * Revoke **all** sessions for this identity (emergency wipe).\n *\n * Requires a WebAuthn biometric prompt. If the Hub client does not\n * support batch revocation the method falls back to revoking the\n * local session only and throws so the caller knows the on-chain\n * wipe did not happen.\n */\n async revokeAllSessions(): Promise<number> {\n if (!this.hubClient.revokeAllSessions) {\n // If the current session is active, revoke it individually\n if (this.currentSession) {\n await this.revokeSession();\n }\n throw new SessionError(\n 'Hub client does not support batch session revocation. Only the local session was revoked.',\n SessionErrorCode.BATCH_REVOCATION_FAILED,\n );\n }\n\n try {\n this.log('Revoking ALL sessions...');\n\n // Build a challenge that is clearly distinct from single-revoke\n const challenge = ethers.solidityPacked(\n ['string'],\n ['revokeAllSessions'],\n );\n\n const signature = await this.passkeySign(ethers.getBytes(challenge));\n\n this.log('Passkey signature obtained, batch revoking on Hub...');\n\n const revokeParams: RevokeSessionParams = {\n signature,\n publicKeyX: this.credential.publicKeyX,\n publicKeyY: this.credential.publicKeyY,\n sessionKeyHash: ethers.ZeroHash, // sentinel: revoke all\n requireUV: true,\n };\n\n const count = await this.hubClient.revokeAllSessions(revokeParams);\n\n // Clear local state\n await this.storage.clear();\n if (this.refreshTimer) {\n clearTimeout(this.refreshTimer);\n this.refreshTimer = null;\n }\n this.currentSession = null;\n\n this.emit({ type: 'all-sessions-revoked', count });\n this.log(`All sessions revoked (${count} on-chain)`);\n return count;\n\n } catch (error) {\n if (error instanceof SessionError) throw error;\n const sessionError = new SessionError(\n 'Failed to revoke all sessions',\n SessionErrorCode.BATCH_REVOCATION_FAILED,\n error,\n );\n this.emit({ type: 'session-error', error: sessionError });\n throw sessionError;\n }\n }\n \n // ========================================================================\n // Session Signing\n // ========================================================================\n \n /**\n * Sign an action with the session key (instant, no biometric)\n * \n * @param action Action parameters to sign\n * @returns Session signature\n * @throws SessionError if no active session, expired, or value exceeds limit\n */\n async signWithSession(action: ActionParams): Promise<SessionSignature> {\n if (!this.currentSession) {\n throw new SessionError(\n 'No active session available',\n SessionErrorCode.NO_ACTIVE_SESSION\n );\n }\n \n const now = Date.now();\n if (now >= this.currentSession.expiry) {\n this.emit({ type: 'session-expired', keyHash: this.currentSession.keyHash });\n throw new SessionError(\n 'Session has expired',\n SessionErrorCode.SESSION_EXPIRED\n );\n }\n \n if (this.currentSession.maxValue > 0n && action.value > this.currentSession.maxValue) {\n throw new SessionError(\n `Transaction value (${action.value}) exceeds session limit (${this.currentSession.maxValue})`,\n SessionErrorCode.VALUE_EXCEEDS_LIMIT,\n { value: action.value, limit: this.currentSession.maxValue }\n );\n }\n \n if (\n this.currentSession.chainScopes.length > 0 &&\n !this.currentSession.chainScopes.includes(action.targetChain)\n ) {\n throw new SessionError(\n `Chain ${action.targetChain} not in session scope`,\n SessionErrorCode.CHAIN_NOT_ALLOWED,\n { chain: action.targetChain, allowedChains: this.currentSession.chainScopes }\n );\n }\n \n this.log('Signing action with session key...');\n \n const messageHash = hashAction(action);\n const { signature } = signWithSessionKey(\n this.currentSession.privateKey,\n messageHash\n );\n \n const sessionSignature: SessionSignature = {\n signature,\n sessionKeyHash: this.currentSession.keyHash,\n userKeyHash: this.currentSession.userKeyHash,\n timestamp: now,\n nonce: action.nonce,\n };\n \n this.log('Action signed successfully');\n \n return sessionSignature;\n }\n \n /**\n * Sign an action and prepare for submission\n * \n * @param action Action parameters\n * @returns Session-signed action ready for submission\n */\n async signAction(action: ActionParams): Promise<SessionSignedAction> {\n const signature = await this.signWithSession(action);\n \n return {\n action,\n signature,\n readyToSubmit: true,\n };\n }\n \n // ========================================================================\n // Session State\n // ========================================================================\n \n /**\n * Check if a session is currently active\n * \n * @returns True if an active, non-expired session exists\n */\n isActive(): boolean {\n if (!this.currentSession) {\n return false;\n }\n return Date.now() < this.currentSession.expiry;\n }\n \n /**\n * Get current session information (if active)\n * \n * @returns Current session or null\n */\n getSession(): SessionKey | null {\n if (!this.isActive()) {\n return null;\n }\n return this.currentSession;\n }\n \n /**\n * Get time remaining until session expiry (in seconds)\n * \n * @returns Seconds until expiry, or 0 if no active session\n */\n getTimeRemaining(): number {\n if (!this.currentSession) {\n return 0;\n }\n const remaining = Math.floor((this.currentSession.expiry - Date.now()) / 1000);\n return Math.max(0, remaining);\n }\n \n // ========================================================================\n // Auto-Refresh\n // ========================================================================\n \n /**\n * Schedule automatic session refresh\n */\n private scheduleRefresh(): void {\n if (!this.currentSession || !this.config.autoRefresh) {\n return;\n }\n \n if (this.refreshTimer) {\n clearTimeout(this.refreshTimer);\n }\n \n const timeUntilRefresh = this.currentSession.expiry - Date.now() - (this.config.refreshBuffer * 1000);\n \n if (timeUntilRefresh <= 0) {\n this.log('Session expiring soon, refreshing now...');\n this.refreshSession().catch(error => {\n this.log('Auto-refresh failed:', error);\n this.emit({ type: 'session-error', error });\n });\n return;\n }\n \n this.log(`Scheduling refresh in ${Math.floor(timeUntilRefresh / 1000)}s`);\n \n this.refreshTimer = setTimeout(() => {\n this.refreshSession().catch(error => {\n this.log('Auto-refresh failed:', error);\n this.emit({ type: 'session-error', error });\n });\n }, timeUntilRefresh);\n }\n \n /**\n * Refresh the current session (creates a new session)\n * \n * @returns New session key\n */\n async refreshSession(): Promise<SessionKey> {\n this.log('Refreshing session...');\n const newSession = await this.createSession();\n this.emit({ type: 'session-refreshed', session: newSession });\n return newSession;\n }\n \n // ========================================================================\n // Event Handling\n // ========================================================================\n \n /**\n * Register an event callback\n */\n on(callback: SessionEventCallback): void {\n this.eventCallbacks.push(callback);\n }\n \n /**\n * Unregister an event callback\n */\n off(callback: SessionEventCallback): void {\n this.eventCallbacks = this.eventCallbacks.filter(cb => cb !== callback);\n }\n \n /**\n * Emit a session event\n */\n private emit(event: SessionEvent): void {\n for (const callback of this.eventCallbacks) {\n try {\n callback(event);\n } catch (error) {\n console.error('Session event callback error:', error);\n }\n }\n }\n \n // ========================================================================\n // Utilities\n // ========================================================================\n \n /**\n * Log debug message (if debug enabled)\n */\n private log(...args: any[]): void {\n if (this.debug) {\n console.log('[SessionManager]', ...args);\n }\n }\n \n /**\n * Cleanup resources\n */\n dispose(): void {\n if (this.refreshTimer) {\n clearTimeout(this.refreshTimer);\n this.refreshTimer = null;\n }\n this.eventCallbacks = [];\n this.currentSession = null;\n }\n}\n\n// ============================================================================\n// Exports\n// ============================================================================\n\nexport { SessionManager };\nexport type { HubClient };\nexport * from './types.js';\nexport * from './crypto.js';\nexport * from './storage.js';","/**\n * Veridex Protocol SDK - Session Key Management Types\n * \n * Type definitions for ephemeral session keys that enable\n * native L1-speed transactions after initial biometric auth.\n */\n\n// ============================================================================\n// Core Session Types\n// ============================================================================\n\n/**\n * Ephemeral session key for fast software-backed signing\n * \n * Security model:\n * - Private key encrypted at rest (AES-GCM)\n * - Max 24-hour duration enforced on-chain\n * - Value limits prevent unlimited spending\n * - Chain scopes restrict cross-chain usage\n */\nexport interface SessionKey {\n /** Public key of the session (secp256k1) */\n publicKey: Uint8Array;\n \n /** Private key (MUST be encrypted before storage) */\n privateKey: Uint8Array;\n \n /** Keccak256 hash of public key (on-chain identifier) */\n keyHash: string;\n \n /** Unix timestamp when session expires (milliseconds) */\n expiry: number;\n \n /** Maximum transaction value allowed (in token's base units) */\n maxValue: bigint;\n \n /** Wormhole chain IDs where this session is valid */\n chainScopes: number[];\n \n /** User's Passkey key hash (binds session to user) */\n userKeyHash: string;\n}\n\n/**\n * Configuration for session creation and lifecycle\n */\nexport interface SessionConfig {\n /** Session duration in seconds (default: 3600 = 1 hour, max: 86400 = 24 hours) */\n duration: number;\n \n /** Maximum transaction value in base units (0 = unlimited, but NOT RECOMMENDED) */\n maxValue: bigint;\n \n /** Auto-refresh session before expiry (default: true) */\n autoRefresh: boolean;\n \n /** Refresh buffer time in seconds (refresh this many seconds before expiry, default: 300 = 5 min) */\n refreshBuffer?: number;\n \n /** Chain scopes - which Wormhole chain IDs can use this session (empty = all chains) */\n chainScopes?: number[];\n}\n\n/**\n * Signature produced by signing with a session key\n * \n * This is a lightweight software signature (secp256k1) that can be\n * validated on-chain via CCQ to Hub's isSessionActive() state.\n */\nexport interface SessionSignature {\n /** ECDSA signature (r, s, v) from session private key */\n signature: Uint8Array;\n \n /** Session key hash (links signature to registered session) */\n sessionKeyHash: string;\n \n /** User's Passkey key hash (for Hub state query) */\n userKeyHash: string;\n \n /** Timestamp when signature was created (for replay prevention) */\n timestamp: number;\n \n /** Optional nonce for additional replay protection */\n nonce?: number;\n}\n\n/**\n * Configuration for SessionManager initialization\n */\nexport interface SessionManagerConfig {\n /** Default session configuration */\n defaultSessionConfig: SessionConfig;\n \n /** Storage backend ('indexeddb' or 'localstorage', default: 'indexeddb') */\n storageBackend?: 'indexeddb' | 'localstorage';\n \n /** Enable debug logging */\n debug?: boolean;\n \n /** Custom encryption key derivation (for testing only) */\n encryptionKey?: CryptoKey;\n}\n\n// ============================================================================\n// Session Lifecycle Events\n// ============================================================================\n\n/**\n * Events emitted during session lifecycle\n */\nexport type SessionEvent = \n | { type: 'session-created'; session: SessionKey }\n | { type: 'session-loaded'; session: SessionKey }\n | { type: 'session-expired'; keyHash: string }\n | { type: 'session-refreshed'; session: SessionKey }\n | { type: 'session-revoked'; keyHash: string }\n | { type: 'all-sessions-revoked'; count: number }\n | { type: 'session-error'; error: Error };\n\nexport type SessionEventCallback = (event: SessionEvent) => void;\n\n// ============================================================================\n// Storage Interface\n// ============================================================================\n\n/**\n * Interface for session storage implementations\n * \n * Implementations MUST:\n * - Encrypt private keys before storage\n * - Use secure key derivation (e.g., PBKDF2 or similar)\n * - Provide atomic read/write/delete operations\n */\nexport interface SessionStorage {\n /**\n * Save a session (private key will be encrypted)\n */\n save(session: SessionKey): Promise<void>;\n \n /**\n * Load the active session (private key will be decrypted)\n */\n load(): Promise<SessionKey | null>;\n \n /**\n * Clear all stored sessions\n */\n clear(): Promise<void>;\n \n /**\n * Check if a session exists\n */\n exists(): Promise<boolean>;\n}\n\n// ============================================================================\n// Action Signing Types\n// ============================================================================\n\n/**\n * Parameters for an action to be signed with a session key\n */\nexport interface ActionParams {\n /** Action type (transfer, execute, bridge, etc.) */\n action: string;\n \n /** Target chain (Wormhole chain ID) */\n targetChain: number;\n \n /** Transaction value in base units */\n value: bigint;\n \n /** Action-specific payload */\n payload: Uint8Array;\n \n /** Nonce for replay prevention */\n nonce: number;\n \n /** Optional deadline timestamp */\n deadline?: number;\n}\n\n/**\n * Result of session-signed action\n */\nexport interface SessionSignedAction {\n /** Original action parameters */\n action: ActionParams;\n \n /** Session signature */\n signature: SessionSignature;\n \n /** Ready to submit to relayer or on-chain */\n readyToSubmit: boolean;\n}\n\n// ============================================================================\n// Error Types\n// ============================================================================\n\nexport class SessionError extends Error {\n constructor(\n message: string,\n public code: SessionErrorCode,\n public details?: unknown\n ) {\n super(message);\n this.name = 'SessionError';\n }\n}\n\nexport enum SessionErrorCode {\n NO_ACTIVE_SESSION = 'NO_ACTIVE_SESSION',\n SESSION_EXPIRED = 'SESSION_EXPIRED',\n VALUE_EXCEEDS_LIMIT = 'VALUE_EXCEEDS_LIMIT',\n CHAIN_NOT_ALLOWED = 'CHAIN_NOT_ALLOWED',\n STORAGE_ERROR = 'STORAGE_ERROR',\n ENCRYPTION_ERROR = 'ENCRYPTION_ERROR',\n INVALID_CONFIG = 'INVALID_CONFIG',\n REGISTRATION_FAILED = 'REGISTRATION_FAILED',\n REVOCATION_FAILED = 'REVOCATION_FAILED',\n BATCH_REVOCATION_FAILED = 'BATCH_REVOCATION_FAILED',\n}\n","/**\n * Veridex Protocol SDK - Session Cryptography Utilities\n * \n * Provides cryptographic operations for session key management:\n * - secp256k1 key generation (NOT secp256r1 - sessions are software-backed)\n * - ECDSA signing with session keys\n * - Key hash derivation (keccak256)\n * - Secure random generation\n */\n\nimport { ethers } from 'ethers';\nimport { SessionError, SessionErrorCode } from './types.js';\n\n// ============================================================================\n// Constants\n// ============================================================================\n\n/** Maximum session duration enforced on-chain (24 hours) */\nexport const MAX_SESSION_DURATION = 86400; // 24 hours in seconds\n\n/** Minimum session duration (60 seconds) */\nexport const MIN_SESSION_DURATION = 60;\n\n/** Default session duration (1 hour) */\nexport const DEFAULT_SESSION_DURATION = 3600;\n\n/** Default refresh buffer (5 minutes before expiry) */\nexport const DEFAULT_REFRESH_BUFFER = 300;\n\n// ============================================================================\n// Key Generation\n// ============================================================================\n\n/**\n * Key pair for secp256k1 session keys\n */\nexport interface KeyPair {\n publicKey: Uint8Array;\n privateKey: Uint8Array;\n address: string; // Ethereum-style address for verification\n}\n\n/**\n * Generate a new secp256k1 key pair for session key\n * \n * Security:\n * - Uses cryptographically secure random (ethers.Wallet.createRandom)\n * - Returns uncompressed public key (65 bytes)\n * - Private key is 32 bytes\n * \n * @returns KeyPair with public/private keys and derived address\n */\nexport function generateSecp256k1KeyPair(): KeyPair {\n try {\n // Use ethers.js for secure key generation\n const wallet = ethers.Wallet.createRandom();\n \n // Extract raw private key (32 bytes)\n const privateKey = ethers.getBytes(wallet.privateKey);\n \n // ethers v6 returns COMPRESSED public key (33 bytes).\n // We need UNCOMPRESSED (65 bytes: 0x04 || x || y).\n // Use SigningKey to derive the uncompressed form.\n const signingKey = new ethers.SigningKey(wallet.privateKey);\n const publicKey = ethers.getBytes(signingKey.publicKey);\n \n return {\n publicKey,\n privateKey,\n address: wallet.address,\n };\n } catch (error) {\n throw new SessionError(\n 'Failed to generate secp256k1 key pair',\n SessionErrorCode.ENCRYPTION_ERROR,\n error\n );\n }\n}\n\n/**\n * Compute keccak256 hash of public key (session key identifier)\n * \n * This hash is used as the on-chain identifier for the session.\n * It matches the Solidity keccak256(publicKey) computation.\n * \n * @param publicKey Uncompressed public key (65 bytes)\n * @returns Hex string of keccak256 hash (0x...)\n */\nexport function computeSessionKeyHash(publicKey: Uint8Array): string {\n if (publicKey.length !== 65 || publicKey[0] !== 0x04) {\n throw new SessionError(\n 'Invalid public key format (expected 65-byte uncompressed key)',\n SessionErrorCode.INVALID_CONFIG\n );\n }\n \n // Hash the full uncompressed public key (including 0x04 prefix)\n return ethers.keccak256(publicKey);\n}\n\n// ============================================================================\n// Signing\n// ============================================================================\n\n/**\n * Sign a message hash with a session key (secp256k1 ECDSA)\n * \n * @param privateKey Session private key (32 bytes)\n * @param messageHash Message hash to sign (32 bytes)\n * @returns Signature with r, s, v components\n */\nexport function signWithSessionKey(\n privateKey: Uint8Array,\n messageHash: Uint8Array | string\n): { r: string; s: string; v: number; signature: Uint8Array } {\n try {\n if (privateKey.length !== 32) {\n throw new SessionError(\n 'Invalid private key length (expected 32 bytes)',\n SessionErrorCode.ENCRYPTION_ERROR\n );\n }\n \n // Create signing key from private key\n const signingKey = new ethers.SigningKey(privateKey);\n \n // Ensure message hash is bytes\n const hashBytes = typeof messageHash === 'string' \n ? ethers.getBytes(messageHash)\n : messageHash;\n \n if (hashBytes.length !== 32) {\n throw new SessionError(\n 'Invalid message hash length (expected 32 bytes)',\n SessionErrorCode.INVALID_CONFIG\n );\n }\n \n // Sign the hash\n const sig = signingKey.sign(hashBytes);\n \n // Extract r, s, v\n const r = sig.r;\n const s = sig.s;\n const v = sig.v;\n \n // Combine into 65-byte signature (r + s + v)\n const signature = ethers.getBytes(sig.serialized);\n \n return { r, s, v, signature };\n } catch (error) {\n throw new SessionError(\n 'Failed to sign with session key',\n SessionErrorCode.ENCRYPTION_ERROR,\n error\n );\n }\n}\n\n/**\n * Hash an action for signing\n * \n * Creates a deterministic hash of action parameters that can be\n * signed with a session key and verified on-chain.\n * \n * Hash format: keccak256(abi.encodePacked(\n * action, targetChain, value, keccak256(payload), nonce, deadline\n * ))\n * \n * @param params Action parameters\n * @returns Message hash (32 bytes)\n */\nexport function hashAction(params: {\n action: string;\n targetChain: number;\n value: bigint;\n payload: Uint8Array;\n nonce: number;\n deadline?: number;\n}): Uint8Array {\n try {\n // Hash the payload first\n const payloadHash = ethers.keccak256(params.payload);\n \n // Encode packed (matches Solidity abi.encodePacked)\n const encoded = ethers.solidityPacked(\n ['string', 'uint256', 'uint256', 'bytes32', 'uint256', 'uint256'],\n [\n params.action,\n params.targetChain,\n params.value,\n payloadHash,\n params.nonce,\n params.deadline ?? 0,\n ]\n );\n \n // Return keccak256 hash\n return ethers.getBytes(ethers.keccak256(encoded));\n } catch (error) {\n throw new SessionError(\n 'Failed to hash action',\n SessionErrorCode.INVALID_CONFIG,\n error\n );\n }\n}\n\n/**\n * Verify a session key signature\n * \n * Used for testing and client-side validation before submission.\n * On-chain verification is handled by Spoke contracts via CCQ.\n * \n * @param messageHash Message that was signed\n * @param signature Signature to verify\n * @param expectedPublicKey Expected public key of signer\n * @returns True if signature is valid\n */\nexport function verifySessionSignature(\n messageHash: Uint8Array | string,\n signature: Uint8Array,\n expectedPublicKey: Uint8Array\n): boolean {\n try {\n if (signature.length !== 65) {\n return false;\n }\n \n // Ensure hash is bytes\n const hashBytes = typeof messageHash === 'string'\n ? ethers.getBytes(messageHash)\n : messageHash;\n \n // Recover public key from signature\n const recovered = ethers.SigningKey.recoverPublicKey(\n hashBytes,\n ethers.hexlify(signature)\n );\n \n // Compare with expected public key\n const recoveredBytes = ethers.getBytes(recovered);\n \n if (recoveredBytes.length !== expectedPublicKey.length) {\n return false;\n }\n \n // Constant-time comparison\n return recoveredBytes.every((byte, i) => byte === expectedPublicKey[i]);\n } catch {\n return false;\n }\n}\n\n// ============================================================================\n// Encryption Key Derivation\n// ============================================================================\n\n/**\n * Derive an AES-GCM encryption key for session storage\n * \n * Uses PBKDF2 to derive a key from a user-specific seed.\n * The seed should be derived from the user's Passkey credential ID.\n * \n * Security considerations:\n * - Uses 100,000 iterations (OWASP minimum)\n * - Salt is derived from credential ID (unique per user)\n * - Key is bound to specific browser/device via extractable: false\n * \n * @param credentialId User's Passkey credential ID (unique identifier)\n * @returns AES-GCM encryption key\n */\nexport async function deriveEncryptionKey(credentialId: string): Promise<CryptoKey> {\n try {\n // Use credential ID as password material\n const passwordBytes = ethers.toUtf8Bytes(credentialId);\n \n // Import as key material\n const keyMaterial = await crypto.subtle.importKey(\n 'raw',\n passwordBytes as BufferSource,\n 'PBKDF2',\n false,\n ['deriveKey']\n );\n \n // Derive salt from credential ID (deterministic but unique per user)\n const saltBytes = ethers.getBytes(ethers.keccak256(passwordBytes));\n \n // Derive AES-GCM key\n const key = await crypto.subtle.deriveKey(\n {\n name: 'PBKDF2',\n salt: saltBytes as BufferSource,\n iterations: 100000, // OWASP minimum\n hash: 'SHA-256',\n },\n keyMaterial,\n {\n name: 'AES-GCM',\n length: 256,\n },\n false, // Not extractable (stays in browser)\n ['encrypt', 'decrypt']\n );\n \n return key;\n } catch (error) {\n throw new SessionError(\n 'Failed to derive encryption key',\n SessionErrorCode.ENCRYPTION_ERROR,\n error\n );\n }\n}\n\n/**\n * Generate a random initialization vector (IV) for AES-GCM\n * \n * @returns 12-byte IV (standard for AES-GCM)\n */\nexport function generateIv(): Uint8Array {\n return crypto.getRandomValues(new Uint8Array(12));\n}\n\n/**\n * Encrypt data with AES-GCM\n * \n * @param data Data to encrypt\n * @param key AES-GCM encryption key\n * @returns Encrypted data with IV prepended\n */\nexport async function encrypt(data: Uint8Array, key: CryptoKey): Promise<Uint8Array> {\n try {\n const iv = generateIv();\n \n const encrypted = await crypto.subtle.encrypt(\n {\n name: 'AES-GCM',\n iv: iv as BufferSource,\n },\n key,\n data as BufferSource\n );\n \n // Prepend IV to encrypted data (IV is not secret)\n const result = new Uint8Array(iv.length + encrypted.byteLength);\n result.set(iv, 0);\n result.set(new Uint8Array(encrypted), iv.length);\n \n return result;\n } catch (error) {\n throw new SessionError(\n 'Encryption failed',\n SessionErrorCode.ENCRYPTION_ERROR,\n error\n );\n }\n}\n\n/**\n * Decrypt data with AES-GCM\n * \n * @param encryptedData Data with IV prepended\n * @param key AES-GCM encryption key\n * @returns Decrypted data\n */\nexport async function decrypt(encryptedData: Uint8Array, key: CryptoKey): Promise<Uint8Array> {\n try {\n if (encryptedData.length < 12) {\n throw new Error('Invalid encrypted data (too short)');\n }\n \n // Extract IV (first 12 bytes)\n const iv = encryptedData.slice(0, 12);\n \n // Extract encrypted data (remaining bytes)\n const ciphertext = encryptedData.slice(12);\n \n const decrypted = await crypto.subtle.decrypt(\n {\n name: 'AES-GCM',\n iv,\n },\n key,\n ciphertext\n );\n \n return new Uint8Array(decrypted);\n } catch (error) {\n throw new SessionError(\n 'Decryption failed',\n SessionErrorCode.ENCRYPTION_ERROR,\n error\n );\n }\n}\n\n// ============================================================================\n// Validation\n// ============================================================================\n\n/**\n * Validate session configuration\n * \n * @param config Session configuration to validate\n * @throws SessionError if configuration is invalid\n */\nexport function validateSessionConfig(config: {\n duration: number;\n maxValue: bigint;\n}): void {\n if (config.duration < MIN_SESSION_DURATION) {\n throw new SessionError(\n `Session duration too short (minimum: ${MIN_SESSION_DURATION}s)`,\n SessionErrorCode.INVALID_CONFIG\n );\n }\n \n if (config.duration > MAX_SESSION_DURATION) {\n throw new SessionError(\n `Session duration too long (maximum: ${MAX_SESSION_DURATION}s = 24 hours)`,\n SessionErrorCode.INVALID_CONFIG\n );\n }\n \n if (config.maxValue < 0n) {\n throw new SessionError(\n 'Session maxValue cannot be negative',\n SessionErrorCode.INVALID_CONFIG\n );\n }\n}\n","/**\n * Veridex Protocol SDK - Secure Session Storage\n * \n * Provides encrypted storage for session keys using IndexedDB or LocalStorage.\n * Private keys are ALWAYS encrypted at rest using AES-GCM.\n * \n * Security guarantees:\n * - Private keys never stored in plaintext\n * - Encryption keys derived from Passkey credential ID (user-bound)\n * - Keys are non-extractable (remain in browser's crypto subsystem)\n * - Automatic cleanup on revocation or expiry\n */\n\nimport { ethers } from 'ethers';\nimport type { SessionKey, SessionStorage } from './types.js';\nimport { SessionError, SessionErrorCode } from './types.js';\nimport { encrypt, decrypt, deriveEncryptionKey } from './crypto.js';\n\n// ============================================================================\n// IndexedDB Session Storage (Preferred)\n// ============================================================================\n\n/** IndexedDB database name */\nconst DB_NAME = 'veridex-sessions';\n\n/** IndexedDB version */\nconst DB_VERSION = 1;\n\n/** Object store name */\nconst STORE_NAME = 'sessions';\n\n/**\n * IndexedDB-based session storage with encryption\n * \n * Preferred storage backend because:\n * - Larger storage quota (~50MB vs ~10MB)\n * - Structured storage (no serialization overhead)\n * - Better performance for binary data\n * - Non-blocking async API\n */\nexport class IndexedDBSessionStorage implements SessionStorage {\n private db: IDBDatabase | null = null;\n private encryptionKey: CryptoKey | null = null;\n private credentialId: string;\n \n /**\n * @param credentialId User's Passkey credential ID (for key derivation)\n */\n constructor(credentialId: string) {\n if (!credentialId) {\n throw new SessionError(\n 'Credential ID required for session storage',\n SessionErrorCode.INVALID_CONFIG\n );\n }\n this.credentialId = credentialId;\n }\n \n /**\n * Initialize database connection\n */\n private async initialize(): Promise<void> {\n if (this.db) return;\n \n return new Promise((resolve, reject) => {\n const request = indexedDB.open(DB_NAME, DB_VERSION);\n \n request.onerror = () => {\n reject(new SessionError(\n 'Failed to open IndexedDB',\n SessionErrorCode.STORAGE_ERROR,\n request.error\n ));\n };\n \n request.onsuccess = () => {\n this.db = request.result;\n resolve();\n };\n \n request.onupgradeneeded = (event) => {\n const db = (event.target as IDBOpenDBRequest).result;\n \n // Create object store if it doesn't exist\n if (!db.objectStoreNames.contains(STORE_NAME)) {\n const store = db.createObjectStore(STORE_NAME, { keyPath: 'keyHash' });\n \n // Create indexes for efficient queries\n store.createIndex('userKeyHash', 'userKeyHash', { unique: false });\n store.createIndex('expiry', 'expiry', { unique: false });\n }\n };\n });\n }\n \n /**\n * Get or derive encryption key\n */\n private async getEncryptionKey(): Promise<CryptoKey> {\n if (this.encryptionKey) {\n return this.encryptionKey;\n }\n \n this.encryptionKey = await deriveEncryptionKey(this.credentialId);\n return this.encryptionKey;\n }\n \n /**\n * Save a session (encrypts private key)\n */\n async save(session: SessionKey): Promise<void> {\n try {\n await this.initialize();\n \n if (!this.db) {\n throw new Error('Database not initialized');\n }\n \n // Get encryption key\n const key = await this.getEncryptionKey();\n \n // Encrypt private key\n const encryptedPrivateKey = await encrypt(session.privateKey, key);\n \n // Prepare storage object (private key encrypted)\n const storageObject = {\n keyHash: session.keyHash,\n publicKey: Array.from(session.publicKey), // Store as array for IndexedDB\n encryptedPrivateKey: Array.from(encryptedPrivateKey),\n expiry: session.expiry,\n maxValue: session.maxValue.toString(), // BigInt as string\n chainScopes: session.chainScopes,\n userKeyHash: session.userKeyHash,\n savedAt: Date.now(),\n };\n \n // Store in IndexedDB\n return new Promise((resolve, reject) => {\n const transaction = this.db!.transaction([STORE_NAME], 'readwrite');\n const store = transaction.objectStore(STORE_NAME);\n const request = store.put(storageObject);\n \n request.onsuccess = () => resolve();\n request.onerror = () => {\n reject(new SessionError(\n 'Failed to save session',\n SessionErrorCode.STORAGE_ERROR,\n request.error\n ));\n };\n });\n } catch (error) {\n if (error instanceof SessionError) {\n throw error;\n }\n throw new SessionError(\n 'Failed to save session',\n SessionErrorCode.STORAGE_ERROR,\n error\n );\n }\n }\n \n /**\n * Load the active session (decrypts private key)\n */\n async load(): Promise<SessionKey | null> {\n try {\n await this.initialize();\n \n if (!this.db) {\n throw new Error('Database not initialized');\n }\n \n // Get all sessions\n const allSessions = await this.getAllSessions();\n \n if (allSessions.length === 0) {\n return null;\n }\n \n // Find the most recent non-expired session\n const now = Date.now();\n const validSessions = allSessions\n .filter(s => s.expiry > now)\n .sort((a, b) => b.savedAt - a.savedAt);\n \n if (validSessions.length === 0) {\n // All sessions expired, clean up\n await this.clear();\n return null;\n }\n \n const stored = validSessions[0];\n \n // Get encryption key\n const key = await this.getEncryptionKey();\n \n // Decrypt private key\n const encryptedPrivateKey = new Uint8Array(stored.encryptedPrivateKey);\n const privateKey = await decrypt(encryptedPrivateKey, key);\n \n // Reconstruct session\n const session: SessionKey = {\n keyHash: stored.keyHash,\n publicKey: new Uint8Array(stored.publicKey),\n privateKey,\n expiry: stored.expiry,\n maxValue: BigInt(stored.maxValue),\n chainScopes: stored.chainScopes,\n userKeyHash: stored.userKeyHash,\n };\n \n return session;\n } catch (error) {\n if (error instanceof SessionError) {\n throw error;\n }\n throw new SessionError(\n 'Failed to load session',\n SessionErrorCode.STORAGE_ERROR,\n error\n );\n }\n }\n \n /**\n * Get all stored sessions (internal helper)\n */\n private async getAllSessions(): Promise<Array<any>> {\n if (!this.db) {\n return [];\n }\n \n return new Promise((resolve, reject) => {\n const transaction = this.db!.transaction([STORE_NAME], 'readonly');\n const store = transaction.objectStore(STORE_NAME);\n const request = store.getAll();\n \n request.onsuccess = () => resolve(request.result || []);\n request.onerror = () => {\n reject(new SessionError(\n 'Failed to get sessions',\n SessionErrorCode.STORAGE_ERROR,\n request.error\n ));\n };\n });\n }\n \n /**\n * Clear all sessions\n */\n async clear(): Promise<void> {\n try {\n await this.initialize();\n \n if (!this.db) {\n return;\n }\n \n return new Promise((resolve, reject) => {\n const transaction = this.db!.transaction([STORE_NAME], 'readwrite');\n const store = transaction.objectStore(STORE_NAME);\n const request = store.clear();\n \n request.onsuccess = () => resolve();\n request.onerror = () => {\n reject(new SessionError(\n 'Failed to clear sessions',\n SessionErrorCode.STORAGE_ERROR,\n request.error\n ));\n };\n });\n } catch (error) {\n if (error instanceof SessionError) {\n throw error;\n }\n throw new SessionError(\n 'Failed to clear sessions',\n SessionErrorCode.STORAGE_ERROR,\n error\n );\n }\n }\n \n /**\n * Check if any session exists\n */\n async exists(): Promise<boolean> {\n try {\n await this.initialize();\n \n if (!this.db) {\n return false;\n }\n \n const sessions = await this.getAllSessions();\n return sessions.length > 0;\n } catch {\n return false;\n }\n }\n \n /**\n * Close database connection\n */\n close(): void {\n if (this.db) {\n this.db.close();\n this.db = null;\n }\n }\n}\n\n// ============================================================================\n// LocalStorage Session Storage (Fallback)\n// ============================================================================\n\n/** LocalStorage key prefix */\nconst STORAGE_KEY_PREFIX = 'veridex-session-';\n\n/**\n * LocalStorage-based session storage with encryption\n * \n * Fallback storage backend when IndexedDB is unavailable.\n * \n * Limitations:\n * - Smaller storage quota (~10MB)\n * - Synchronous API (blocks main thread)\n * - String-based storage (requires serialization)\n */\nexport class LocalStorageSessionStorage implements SessionStorage {\n private encryptionKey: CryptoKey | null = null;\n private credentialId: string;\n private storageKey: string;\n \n /**\n * @param credentialId User's Passkey credential ID (for key derivation)\n */\n constructor(credentialId: string) {\n if (!credentialId) {\n throw new SessionError(\n 'Credential ID required for session storage',\n SessionErrorCode.INVALID_CONFIG\n );\n }\n this.credentialId = credentialId;\n this.storageKey = STORAGE_KEY_PREFIX + ethers.keccak256(ethers.toUtf8Bytes(credentialId));\n }\n \n /**\n * Get or derive encryption key\n */\n private async getEncryptionKey(): Promise<CryptoKey> {\n if (this.encryptionKey) {\n return this.encryptionKey;\n }\n \n this.encryptionKey = await deriveEncryptionKey(this.credentialId);\n return this.encryptionKey;\n }\n \n /**\n * Save a session (encrypts private key)\n */\n async save(session: SessionKey): Promise<void> {\n try {\n // Get encryption key\n const key = await this.getEncryptionKey();\n \n // Encrypt private key\n const encryptedPrivateKey = await encrypt(session.privateKey, key);\n \n // Prepare storage object\n const storageObject = {\n keyHash: session.keyHash,\n publicKey: ethers.hexlify(session.publicKey),\n encryptedPrivateKey: ethers.hexlify(encryptedPrivateKey),\n expiry: session.expiry,\n maxValue: session.maxValue.toString(),\n chainScopes: session.chainScopes,\n userKeyHash: session.userKeyHash,\n savedAt: Date.now(),\n };\n \n // Store as JSON\n localStorage.setItem(this.storageKey, JSON.stringify(storageObject));\n } catch (error) {\n if (error instanceof SessionError) {\n throw error;\n }\n throw new SessionError(\n 'Failed to save session',\n SessionErrorCode.STORAGE_ERROR,\n error\n );\n }\n }\n \n /**\n * Load the active session (decrypts private key)\n */\n async load(): Promise<SessionKey | null> {\n try {\n const data = localStorage.getItem(this.storageKey);\n \n if (!data) {\n return null;\n }\n \n const stored = JSON.parse(data);\n \n // Check if expired\n if (stored.expiry <= Date.now()) {\n await this.clear();\n return null;\n }\n \n // Get encryption key\n const key = await this.getEncryptionKey();\n \n // Decrypt private key\n const encryptedPrivateKey = ethers.getBytes(stored.encryptedPrivateKey);\n const privateKey = await decrypt(encryptedPrivateKey, key);\n \n // Reconstruct session\n const session: SessionKey = {\n keyHash: stored.keyHash,\n publicKey: ethers.getBytes(stored.publicKey),\n privateKey,\n expiry: stored.expiry,\n maxValue: BigInt(stored.maxValue),\n chainScopes: stored.chainScopes,\n userKeyHash: stored.userKeyHash,\n };\n \n return session;\n } catch (error) {\n // Clear corrupted data\n await this.clear();\n \n if (error instanceof SessionError) {\n throw error;\n }\n throw new SessionError(\n 'Failed to load session',\n SessionErrorCode.STORAGE_ERROR,\n error\n );\n }\n }\n \n /**\n * Clear all sessions\n */\n async clear(): Promise<void> {\n try {\n localStorage.removeItem(this.storageKey);\n } catch (error) {\n throw new SessionError(\n 'Failed to clear sessions',\n SessionErrorCode.STORAGE_ERROR,\n error\n );\n }\n }\n \n /**\n * Check if any session exists\n */\n async exists(): Promise<boolean> {\n try {\n return localStorage.getItem(this.storageKey) !== null;\n } catch {\n return false;\n }\n }\n}\n\n// ============================================================================\n// Storage Factory\n// ============================================================================\n\n/**\n * Create appropriate session storage based on environment\n * \n * @param credentialId User's Passkey credential ID\n * @param preferredBackend Preferred storage backend ('indexeddb' or 'localstorage')\n * @returns Session storage implementation\n */\nexport function createSessionStorage(\n credentialId: string,\n preferredBackend?: 'indexeddb' | 'localstorage'\n): SessionStorage {\n // Check if running in browser\n if (typeof window === 'undefined') {\n throw new SessionError(\n 'Session storage requires browser environment',\n SessionErrorCode.STORAGE_ERROR\n );\n }\n \n // Try IndexedDB first (if not explicitly requesting localStorage)\n if (preferredBackend !== 'localstorage' && typeof indexedDB !== 'undefined') {\n try {\n return new IndexedDBSessionStorage(credentialId);\n } catch (error) {\n console.warn('IndexedDB unavailable, falling back to LocalStorage:', error);\n }\n }\n \n // Fallback to LocalStorage\n if (typeof localStorage !== 'undefined') {\n console.warn(\n '[Veridex SDK] Security advisory: IndexedDB is unavailable; falling back to LocalStorage for session storage. ' +\n 'Both backends encrypt session keys with AES-GCM, but IndexedDB is recommended for production use.',\n );\n return new LocalStorageSessionStorage(credentialId);\n }\n \n throw new SessionError(\n 'No storage backend available (requires IndexedDB or LocalStorage)',\n SessionErrorCode.STORAGE_ERROR\n );\n}\n","/**\n * Veridex Solana Program Error Codes\n *\n * Error code constants for parsing and handling Veridex program errors.\n * These codes map directly to the Anchor error enum variants in the\n * Solana program.\n *\n * @packageDocumentation\n */\n\n// ============================================================================\n// Error Code Ranges\n// ============================================================================\n\n/**\n * Error code range boundaries.\n * Use these to categorize errors programmatically.\n */\nexport const ERROR_RANGES = {\n /** Core protocol errors (paused, unauthorized, limits, etc.) */\n CORE: { min: 6000, max: 6099 },\n /** Query execution errors */\n QUERY_EXECUTION: { min: 6100, max: 6149 },\n /** ABI decoding errors */\n ABI: { min: 6150, max: 6199 },\n /** Query parsing/validation errors */\n QUERY_PARSING: { min: 6200, max: 6299 },\n} as const;\n\n// ============================================================================\n// Core Protocol Error Codes (6000-6099)\n// ============================================================================\n\nexport const VERIDEX_ERRORS = {\n // Core Protocol Errors\n /** Protocol is globally paused */\n PROTOCOL_PAUSED: 6000,\n /** Vault is paused */\n VAULT_PAUSED: 6001,\n /** VAA already processed (replay protection) */\n VAA_ALREADY_PROCESSED: 6002,\n /** Invalid emitter chain */\n INVALID_EMITTER_CHAIN: 6003,\n /** Invalid emitter address */\n INVALID_EMITTER: 6004,\n /** Invalid owner */\n INVALID_OWNER: 6005,\n /** Invalid target chain */\n INVALID_TARGET_CHAIN: 6006,\n /** Invalid payload version */\n INVALID_PAYLOAD_VERSION: 6007,\n /** Invalid action payload */\n INVALID_ACTION_PAYLOAD: 6008,\n /** Invalid action type */\n INVALID_ACTION_TYPE: 6009,\n /** Daily limit exceeded */\n DAILY_LIMIT_EXCEEDED: 6010,\n /** Insufficient funds */\n INSUFFICIENT_FUNDS: 6011,\n /** Unauthorized */\n UNAUTHORIZED: 6012,\n /** Invalid VAA */\n INVALID_VAA: 6013,\n /** Token bridge not configured */\n TOKEN_BRIDGE_NOT_CONFIGURED: 6014,\n /** Invalid bridge parameters */\n INVALID_BRIDGE_PARAMS: 6015,\n\n // Query Execution Errors (6100-6149)\n /** Invalid query response format */\n INVALID_QUERY_RESPONSE: 6100,\n /** Query response expired (> 60 seconds old) */\n QUERY_EXPIRED: 6101,\n /** Query signature verification failed */\n QUERY_INVALID: 6102,\n /** Query result doesn't match expected state */\n QUERY_MISMATCH: 6103,\n /** Query block time is in the future */\n QUERY_FUTURE_BLOCK: 6104,\n /** Invalid nonce in query response */\n INVALID_QUERY_NONCE: 6105,\n /** Secp256k1 verification instruction missing */\n SECP256K1_INSTRUCTION_MISSING: 6106,\n /** Invalid secp256k1 instruction format */\n INVALID_SECP256K1_INSTRUCTION: 6107,\n /** Insufficient Guardian signatures on query */\n INSUFFICIENT_SIGNATURES: 6108,\n /** Chain ID mismatch in query response */\n CHAIN_ID_MISMATCH: 6109,\n /** Query result not found */\n QUERY_RESULT_NOT_FOUND: 6110,\n\n // ABI Decoding Errors (6150-6199)\n /** ABI decoding: insufficient data */\n ABI_INSUFFICIENT_DATA: 6150,\n /** ABI decoding: value overflow */\n ABI_OVERFLOW: 6151,\n /** ABI decoding: invalid encoding */\n ABI_INVALID_ENCODING: 6152,\n /** ABI decoding: general failure */\n ABI_DECODING_FAILED: 6153,\n\n // Query Parsing Errors (6200-6299)\n /** Invalid query response format (parsing) */\n QUERY_PARSE_INVALID_RESPONSE: 6200,\n /** Invalid query version */\n QUERY_PARSE_INVALID_VERSION: 6201,\n /** Unsupported query type */\n QUERY_PARSE_UNSUPPORTED_TYPE: 6202,\n /** Query response is stale (parsing) */\n QUERY_PARSE_STALE: 6203,\n /** Query block time is in the future (parsing) */\n QUERY_PARSE_FUTURE_BLOCK: 6204,\n /** Invalid Hub state data */\n QUERY_PARSE_INVALID_HUB_STATE: 6205,\n /** Invalid nonce (parsing) */\n QUERY_PARSE_INVALID_NONCE: 6206,\n /** Query result doesn't match expected (parsing) */\n QUERY_PARSE_MISMATCH: 6207,\n /** Secp256k1 instruction not found (parsing) */\n QUERY_PARSE_SECP256K1_MISSING: 6208,\n /** Invalid Secp256k1 instruction (parsing) */\n QUERY_PARSE_INVALID_SECP256K1: 6209,\n /** Insufficient Guardian signatures (parsing) */\n QUERY_PARSE_INSUFFICIENT_SIGS: 6210,\n /** Invalid Guardian signature (parsing) */\n QUERY_PARSE_INVALID_GUARDIAN_SIG: 6211,\n /** Chain ID mismatch (parsing) */\n QUERY_PARSE_CHAIN_ID_MISMATCH: 6212,\n /** Guardian index out of range */\n QUERY_PARSE_GUARDIAN_INDEX_OOB: 6213,\n /** Non-increasing Guardian index */\n QUERY_PARSE_NON_INCREASING_INDEX: 6214,\n /** Query signature verification failed (parsing) */\n QUERY_PARSE_INVALID_SIGNATURE: 6215,\n /** ABI decoding failed (parsing) */\n QUERY_PARSE_ABI_FAILED: 6216,\n} as const;\n\nexport type VeridexErrorCode = (typeof VERIDEX_ERRORS)[keyof typeof VERIDEX_ERRORS];\n\n// ============================================================================\n// Error Messages\n// ============================================================================\n\n/**\n * Human-readable error messages for each error code.\n */\nexport const ERROR_MESSAGES: Record<VeridexErrorCode, string> = {\n // Core Protocol Errors\n [VERIDEX_ERRORS.PROTOCOL_PAUSED]: \"Protocol is paused\",\n [VERIDEX_ERRORS.VAULT_PAUSED]: \"Vault is paused\",\n [VERIDEX_ERRORS.VAA_ALREADY_PROCESSED]:\n \"This transaction has already been processed\",\n [VERIDEX_ERRORS.INVALID_EMITTER_CHAIN]: \"Invalid emitter chain\",\n [VERIDEX_ERRORS.INVALID_EMITTER]: \"Invalid emitter address\",\n [VERIDEX_ERRORS.INVALID_OWNER]: \"Invalid owner\",\n [VERIDEX_ERRORS.INVALID_TARGET_CHAIN]: \"Invalid target chain\",\n [VERIDEX_ERRORS.INVALID_PAYLOAD_VERSION]: \"Unsupported payload version\",\n [VERIDEX_ERRORS.INVALID_ACTION_PAYLOAD]: \"Invalid action payload\",\n [VERIDEX_ERRORS.INVALID_ACTION_TYPE]: \"Unknown action type\",\n [VERIDEX_ERRORS.DAILY_LIMIT_EXCEEDED]: \"Daily spending limit exceeded\",\n [VERIDEX_ERRORS.INSUFFICIENT_FUNDS]: \"Insufficient funds in vault\",\n [VERIDEX_ERRORS.UNAUTHORIZED]: \"Unauthorized\",\n [VERIDEX_ERRORS.INVALID_VAA]: \"Invalid VAA\",\n [VERIDEX_ERRORS.TOKEN_BRIDGE_NOT_CONFIGURED]: \"Token bridge not configured\",\n [VERIDEX_ERRORS.INVALID_BRIDGE_PARAMS]: \"Invalid bridge parameters\",\n\n // Query Execution Errors\n [VERIDEX_ERRORS.INVALID_QUERY_RESPONSE]: \"Invalid query response format\",\n [VERIDEX_ERRORS.QUERY_EXPIRED]:\n \"Query has expired. Please refresh and try again.\",\n [VERIDEX_ERRORS.QUERY_INVALID]: \"Query signature verification failed\",\n [VERIDEX_ERRORS.QUERY_MISMATCH]: \"Query result does not match expected state\",\n [VERIDEX_ERRORS.QUERY_FUTURE_BLOCK]:\n \"Query block time is in the future. Possible clock skew.\",\n [VERIDEX_ERRORS.INVALID_QUERY_NONCE]: \"Invalid nonce in query response\",\n [VERIDEX_ERRORS.SECP256K1_INSTRUCTION_MISSING]:\n \"Secp256k1 verification instruction missing\",\n [VERIDEX_ERRORS.INVALID_SECP256K1_INSTRUCTION]:\n \"Invalid secp256k1 instruction format\",\n [VERIDEX_ERRORS.INSUFFICIENT_SIGNATURES]:\n \"Insufficient Guardian signatures on query\",\n [VERIDEX_ERRORS.CHAIN_ID_MISMATCH]: \"Chain ID mismatch in query response\",\n [VERIDEX_ERRORS.QUERY_RESULT_NOT_FOUND]: \"Query result not found\",\n\n // ABI Decoding Errors\n [VERIDEX_ERRORS.ABI_INSUFFICIENT_DATA]: \"ABI decoding failed: insufficient data\",\n [VERIDEX_ERRORS.ABI_OVERFLOW]: \"ABI decoding failed: value overflow\",\n [VERIDEX_ERRORS.ABI_INVALID_ENCODING]: \"ABI decoding failed: invalid encoding\",\n [VERIDEX_ERRORS.ABI_DECODING_FAILED]: \"Failed to decode data from Hub\",\n\n // Query Parsing Errors\n [VERIDEX_ERRORS.QUERY_PARSE_INVALID_RESPONSE]: \"Invalid query response format\",\n [VERIDEX_ERRORS.QUERY_PARSE_INVALID_VERSION]: \"Invalid query version\",\n [VERIDEX_ERRORS.QUERY_PARSE_UNSUPPORTED_TYPE]: \"Unsupported query type\",\n [VERIDEX_ERRORS.QUERY_PARSE_STALE]: \"Query response is stale\",\n [VERIDEX_ERRORS.QUERY_PARSE_FUTURE_BLOCK]: \"Query block time is in the future\",\n [VERIDEX_ERRORS.QUERY_PARSE_INVALID_HUB_STATE]: \"Invalid Hub state data\",\n [VERIDEX_ERRORS.QUERY_PARSE_INVALID_NONCE]: \"Invalid nonce in query\",\n [VERIDEX_ERRORS.QUERY_PARSE_MISMATCH]: \"Query result mismatch\",\n [VERIDEX_ERRORS.QUERY_PARSE_SECP256K1_MISSING]: \"Secp256k1 instruction not found\",\n [VERIDEX_ERRORS.QUERY_PARSE_INVALID_SECP256K1]: \"Invalid Secp256k1 instruction\",\n [VERIDEX_ERRORS.QUERY_PARSE_INSUFFICIENT_SIGS]:\n \"Insufficient Guardian signatures\",\n [VERIDEX_ERRORS.QUERY_PARSE_INVALID_GUARDIAN_SIG]: \"Invalid Guardian signature\",\n [VERIDEX_ERRORS.QUERY_PARSE_CHAIN_ID_MISMATCH]: \"Chain ID mismatch\",\n [VERIDEX_ERRORS.QUERY_PARSE_GUARDIAN_INDEX_OOB]: \"Guardian index out of range\",\n [VERIDEX_ERRORS.QUERY_PARSE_NON_INCREASING_INDEX]:\n \"Non-increasing Guardian index\",\n [VERIDEX_ERRORS.QUERY_PARSE_INVALID_SIGNATURE]:\n \"Query signature verification failed\",\n [VERIDEX_ERRORS.QUERY_PARSE_ABI_FAILED]: \"ABI decoding failed\",\n};\n\n// ============================================================================\n// Helper Functions\n// ============================================================================\n\n/**\n * Check if an error code is in the core protocol range.\n */\nexport function isCoreError(code: number): boolean {\n return code >= ERROR_RANGES.CORE.min && code <= ERROR_RANGES.CORE.max;\n}\n\n/**\n * Check if an error code is a query execution error.\n */\nexport function isQueryExecutionError(code: number): boolean {\n return (\n code >= ERROR_RANGES.QUERY_EXECUTION.min &&\n code <= ERROR_RANGES.QUERY_EXECUTION.max\n );\n}\n\n/**\n * Check if an error code is an ABI decoding error.\n */\nexport function isAbiError(code: number): boolean {\n return code >= ERROR_RANGES.ABI.min && code <= ERROR_RANGES.ABI.max;\n}\n\n/**\n * Check if an error code is a query parsing error.\n */\nexport function isQueryParsingError(code: number): boolean {\n return (\n code >= ERROR_RANGES.QUERY_PARSING.min &&\n code <= ERROR_RANGES.QUERY_PARSING.max\n );\n}\n\n/**\n * Check if an error is related to query operations (execution or parsing).\n */\nexport function isQueryError(code: number): boolean {\n return isQueryExecutionError(code) || isQueryParsingError(code);\n}\n\n/**\n * Get the error category as a human-readable string.\n */\nexport function getErrorCategory(code: number): string {\n if (isCoreError(code)) return \"Core Protocol\";\n if (isQueryExecutionError(code)) return \"Query Execution\";\n if (isAbiError(code)) return \"ABI Decoding\";\n if (isQueryParsingError(code)) return \"Query Parsing\";\n return \"Unknown\";\n}\n\n/**\n * Get the human-readable message for an error code.\n */\nexport function getErrorMessage(code: number): string {\n return ERROR_MESSAGES[code as VeridexErrorCode] ?? `Unknown error: ${code}`;\n}\n\n/**\n * Parse an Anchor program error to extract the Veridex error code.\n *\n * @param error - The error object from a failed transaction\n * @returns The error code if found, undefined otherwise\n */\nexport function parseVeridexError(error: unknown): VeridexErrorCode | undefined {\n if (!error || typeof error !== \"object\") return undefined;\n\n // Handle Anchor ProgramError\n const anchorError = error as {\n code?: number;\n error?: { errorCode?: { code?: string; number?: number } };\n };\n\n // Try direct code property\n if (typeof anchorError.code === \"number\") {\n if (anchorError.code in ERROR_MESSAGES) {\n return anchorError.code as VeridexErrorCode;\n }\n }\n\n // Try Anchor v0.30+ error format\n if (anchorError.error?.errorCode?.number !== undefined) {\n const code = anchorError.error.errorCode.number;\n if (code in ERROR_MESSAGES) {\n return code as VeridexErrorCode;\n }\n }\n\n return undefined;\n}\n\n/**\n * Check if the error is a retryable error (e.g., expired query can be refreshed).\n */\nexport function isRetryableError(code: number): boolean {\n const retryableCodes: number[] = [\n VERIDEX_ERRORS.QUERY_EXPIRED,\n VERIDEX_ERRORS.QUERY_PARSE_STALE,\n VERIDEX_ERRORS.QUERY_FUTURE_BLOCK,\n VERIDEX_ERRORS.QUERY_PARSE_FUTURE_BLOCK,\n VERIDEX_ERRORS.QUERY_MISMATCH,\n VERIDEX_ERRORS.QUERY_PARSE_MISMATCH,\n ];\n return retryableCodes.includes(code);\n}\n\n/**\n * Suggested user action for common errors.\n */\nexport function getSuggestedAction(code: number): string {\n switch (code) {\n case VERIDEX_ERRORS.QUERY_EXPIRED:\n case VERIDEX_ERRORS.QUERY_PARSE_STALE:\n return \"The query data has expired. Please refresh and try again.\";\n case VERIDEX_ERRORS.QUERY_FUTURE_BLOCK:\n case VERIDEX_ERRORS.QUERY_PARSE_FUTURE_BLOCK:\n return \"Clock synchronization issue detected. Please wait a moment and retry.\";\n case VERIDEX_ERRORS.INSUFFICIENT_FUNDS:\n return \"Add more funds to your vault before attempting this operation.\";\n case VERIDEX_ERRORS.DAILY_LIMIT_EXCEEDED:\n return \"Daily spending limit exceeded. Wait until tomorrow or increase your limit.\";\n case VERIDEX_ERRORS.PROTOCOL_PAUSED:\n return \"The protocol is temporarily paused. Please try again later.\";\n case VERIDEX_ERRORS.VAULT_PAUSED:\n return \"Your vault is paused. Contact support if this is unexpected.\";\n case VERIDEX_ERRORS.INSUFFICIENT_SIGNATURES:\n case VERIDEX_ERRORS.QUERY_PARSE_INSUFFICIENT_SIGS:\n return \"Waiting for Guardian consensus. Please try again in a few seconds.\";\n default:\n return \"An error occurred. Please try again or contact support.\";\n }\n}\n","/**\n * Veridex Protocol SDK — Enterprise Manager\n *\n * Bundles the operations that enterprise / integrator back-ends need:\n * - Batch vault creation across chains\n * - Admin spending limit management for multiple vaults\n * - Server-side signing helpers (non-WebAuthn path)\n * - Pre-built webhook-style event subscription\n *\n * All features delegate to existing SDK primitives — this is an\n * orchestration layer, not a divergent code path.\n */\n\nimport type { VeridexSDK } from './VeridexSDK.js';\nimport type { MultiChainVaultResult, ChainDeploymentConfig } from './GasSponsor.js';\nimport type { SpendingLimits } from './SpendingLimits.types.js';\nimport type { PortfolioBalance } from './BalanceManager.js';\nimport type { TransferParams, TransferResult } from './types.js';\nimport type { BalanceChangeCallback, BalanceErrorCallback, BalanceWatcherOptions, Unsubscribe } from './BalanceWatcher.js';\nimport { BalanceWatcher } from './BalanceWatcher.js';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface EnterpriseManagerConfig {\n /**\n * The VeridexSDK instance (typically created via `createSDK` or\n * `createEnterpriseSDK` with a sponsor key).\n */\n sdk: VeridexSDK;\n /**\n * Maximum concurrent operations for batch methods (default: 3).\n */\n maxConcurrency?: number;\n}\n\nexport interface BatchVaultRequest {\n /** Key hashes to create vaults for */\n keyHashes: string[];\n /** Optional: specific chain IDs to create vaults on (defaults to all sponsored chains) */\n chainIds?: number[];\n /** Maximum concurrent vault creations (overrides config default) */\n maxConcurrency?: number;\n}\n\nexport interface BatchVaultResult {\n total: number;\n succeeded: number;\n failed: number;\n results: Array<{\n keyHash: string;\n result: MultiChainVaultResult | null;\n error?: string;\n }>;\n}\n\nexport interface BatchTransferRequest {\n /** Transfers to execute */\n transfers: TransferParams[];\n /** Signer to pay for gas */\n signer: any;\n /** Maximum concurrent transfers (overrides config default) */\n maxConcurrency?: number;\n}\n\nexport interface BatchTransferResult {\n total: number;\n succeeded: number;\n failed: number;\n results: Array<{\n params: TransferParams;\n result: TransferResult | null;\n error?: string;\n }>;\n}\n\nexport interface BatchSpendingLimitRequest {\n /** Vault addresses and their new daily limit */\n updates: Array<{\n /** New daily limit in wei/base units (0 = unlimited) */\n newLimit: bigint;\n }>;\n /** Signer to pay for gas */\n signer: any;\n}\n\nexport interface BatchSpendingLimitResult {\n total: number;\n succeeded: number;\n failed: number;\n results: Array<{\n newLimit: bigint;\n result: TransferResult | null;\n error?: string;\n }>;\n}\n\n/** Lifecycle event types for batch operations */\nexport type BatchLifecycleEvent =\n | { type: 'started'; total: number }\n | { type: 'item_started'; index: number; total: number }\n | { type: 'item_completed'; index: number; total: number; success: boolean; error?: string }\n | { type: 'completed'; succeeded: number; failed: number; total: number };\n\n/** Callback for batch operation lifecycle events */\nexport type BatchLifecycleCallback = (event: BatchLifecycleEvent) => void;\n\nexport interface VaultOverview {\n keyHash: string;\n vaultAddress: string;\n wormholeChainId: number;\n exists: boolean;\n balance?: PortfolioBalance;\n limits?: SpendingLimits;\n}\n\n// ============================================================================\n// EnterpriseManager class\n// ============================================================================\n\n/**\n * High-level orchestration for enterprise / integrator use cases.\n *\n * @example\n * ```typescript\n * import { createEnterpriseSDK, EnterpriseManager } from '@veridex/sdk';\n *\n * const sdk = createEnterpriseSDK({\n * sponsorPrivateKey: process.env.SPONSOR_KEY!,\n * relayerUrl: 'https://relayer.veridex.network',\n * relayerApiKey: 'key',\n * });\n *\n * const enterprise = new EnterpriseManager({ sdk });\n *\n * // Batch create vaults for 50 users\n * const result = await enterprise.batchCreateVaults({\n * keyHashes: userKeyHashes,\n * });\n *\n * // Watch all vaults for balance changes\n * const unsub = enterprise.watchVaultBalance(\n * 10004, vaultAddress,\n * (event) => callWebhook(event),\n * );\n * ```\n */\nexport class EnterpriseManager {\n private readonly sdk: VeridexSDK;\n private readonly balanceWatcher: BalanceWatcher;\n private readonly maxConcurrency: number;\n\n constructor(config: EnterpriseManagerConfig) {\n this.sdk = config.sdk;\n this.maxConcurrency = config.maxConcurrency ?? 3;\n\n // Build a balance fetcher that delegates to the SDK's balance manager\n this.balanceWatcher = new BalanceWatcher(\n async (chainId, address) => {\n return this.sdk.balance.getPortfolioBalance(chainId, address, false);\n },\n );\n }\n\n // ========================================================================\n // Concurrency Helper\n // ========================================================================\n\n /**\n * Run tasks with bounded concurrency.\n */\n private async runWithConcurrency<T>(\n tasks: Array<() => Promise<T>>,\n maxConcurrency: number,\n ): Promise<T[]> {\n const results: T[] = new Array(tasks.length);\n let nextIndex = 0;\n\n async function worker() {\n while (nextIndex < tasks.length) {\n const idx = nextIndex++;\n results[idx] = await tasks[idx]();\n }\n }\n\n const workers = Array.from(\n { length: Math.min(maxConcurrency, tasks.length) },\n () => worker(),\n );\n await Promise.all(workers);\n return results;\n }\n\n // ========================================================================\n // Batch Vault Operations\n // ========================================================================\n\n /**\n * Create sponsored vaults for multiple users with concurrency control.\n *\n * Uses the SDK's GasSponsor under the hood. Errors for individual\n * key hashes are captured, not thrown — the batch continues.\n */\n async batchCreateVaults(\n request: BatchVaultRequest,\n onLifecycle?: BatchLifecycleCallback,\n ): Promise<BatchVaultResult> {\n const concurrency = request.maxConcurrency ?? this.maxConcurrency;\n const results: BatchVaultResult['results'] = new Array(request.keyHashes.length);\n\n onLifecycle?.({ type: 'started', total: request.keyHashes.length });\n\n const tasks = request.keyHashes.map((keyHash, index) => async () => {\n onLifecycle?.({ type: 'item_started', index, total: request.keyHashes.length });\n try {\n const result = await this.sdk.sponsor.createVaultsOnAllChains(keyHash);\n results[index] = { keyHash, result };\n onLifecycle?.({ type: 'item_completed', index, total: request.keyHashes.length, success: true });\n } catch (err) {\n const error = err instanceof Error ? err.message : String(err);\n results[index] = { keyHash, result: null, error };\n onLifecycle?.({ type: 'item_completed', index, total: request.keyHashes.length, success: false, error });\n }\n });\n\n await this.runWithConcurrency(tasks, concurrency);\n\n const succeeded = results.filter(r => r.result?.allSuccessful).length;\n const failed = request.keyHashes.length - succeeded;\n onLifecycle?.({ type: 'completed', succeeded, failed, total: request.keyHashes.length });\n\n return {\n total: request.keyHashes.length,\n succeeded,\n failed,\n results,\n };\n }\n\n /**\n * Check vault existence across all sponsored chains for a key hash.\n */\n async checkVaults(keyHash: string): Promise<Record<number, { exists: boolean; address: string }>> {\n return this.sdk.sponsor.checkVaultsOnAllChains(keyHash);\n }\n\n /**\n * List all chains where sponsorship is available.\n */\n getSponsoredChains(): ChainDeploymentConfig[] {\n return this.sdk.sponsor.getSupportedChains();\n }\n\n // ========================================================================\n // Batch Transfers\n // ========================================================================\n\n /**\n * Execute multiple transfers with concurrency control.\n *\n * Each transfer is prepared and executed independently. Errors are\n * captured per-transfer so the batch continues on individual failures.\n *\n * @example\n * ```typescript\n * const result = await enterprise.batchTransfer({\n * transfers: [\n * { targetChain: 10004, token: '0x...', recipient: '0xAlice', amount: 1000000n },\n * { targetChain: 10004, token: '0x...', recipient: '0xBob', amount: 2000000n },\n * ],\n * signer,\n * maxConcurrency: 2,\n * }, (event) => console.log(event.type, event));\n * ```\n */\n async batchTransfer(\n request: BatchTransferRequest,\n onLifecycle?: BatchLifecycleCallback,\n ): Promise<BatchTransferResult> {\n const concurrency = request.maxConcurrency ?? this.maxConcurrency;\n const results: BatchTransferResult['results'] = new Array(request.transfers.length);\n\n onLifecycle?.({ type: 'started', total: request.transfers.length });\n\n const tasks = request.transfers.map((params, index) => async () => {\n onLifecycle?.({ type: 'item_started', index, total: request.transfers.length });\n try {\n const prepared = await this.sdk.prepareTransfer(params);\n const result = await this.sdk.executeTransfer(prepared, request.signer);\n results[index] = { params, result };\n onLifecycle?.({ type: 'item_completed', index, total: request.transfers.length, success: true });\n } catch (err) {\n const error = err instanceof Error ? err.message : String(err);\n results[index] = { params, result: null, error };\n onLifecycle?.({ type: 'item_completed', index, total: request.transfers.length, success: false, error });\n }\n });\n\n await this.runWithConcurrency(tasks, concurrency);\n\n const succeeded = results.filter(r => r.result !== null).length;\n const failed = request.transfers.length - succeeded;\n onLifecycle?.({ type: 'completed', succeeded, failed, total: request.transfers.length });\n\n return {\n total: request.transfers.length,\n succeeded,\n failed,\n results,\n };\n }\n\n // ========================================================================\n // Batch Spending Limits\n // ========================================================================\n\n /**\n * Update daily spending limits for the current vault in sequence.\n *\n * Each limit update requires a passkey signature, so these are executed\n * one-at-a-time (signing cannot be parallelized).\n *\n * @example\n * ```typescript\n * const result = await enterprise.batchSetSpendingLimits({\n * updates: [\n * { newLimit: ethers.parseEther('5.0') },\n * { newLimit: ethers.parseEther('10.0') },\n * ],\n * signer,\n * });\n * ```\n */\n async batchSetSpendingLimits(\n request: BatchSpendingLimitRequest,\n onLifecycle?: BatchLifecycleCallback,\n ): Promise<BatchSpendingLimitResult> {\n const results: BatchSpendingLimitResult['results'] = [];\n\n onLifecycle?.({ type: 'started', total: request.updates.length });\n\n for (let i = 0; i < request.updates.length; i++) {\n const update = request.updates[i];\n onLifecycle?.({ type: 'item_started', index: i, total: request.updates.length });\n try {\n const prepared = await this.sdk.prepareSetDailyLimit(update.newLimit);\n const result = await this.sdk.executeTransfer(prepared, request.signer);\n results.push({ newLimit: update.newLimit, result });\n onLifecycle?.({ type: 'item_completed', index: i, total: request.updates.length, success: true });\n } catch (err) {\n const error = err instanceof Error ? err.message : String(err);\n results.push({ newLimit: update.newLimit, result: null, error });\n onLifecycle?.({ type: 'item_completed', index: i, total: request.updates.length, success: false, error });\n }\n }\n\n const succeeded = results.filter(r => r.result !== null).length;\n const failed = request.updates.length - succeeded;\n onLifecycle?.({ type: 'completed', succeeded, failed, total: request.updates.length });\n\n return {\n total: request.updates.length,\n succeeded,\n failed,\n results,\n };\n }\n\n // ========================================================================\n // Admin Spending Limits\n // ========================================================================\n\n /**\n * Read spending limits for any vault address on the current chain.\n * Useful for admin dashboards that need to inspect user vaults.\n */\n async getSpendingLimitsForVault(\n vaultAddress: string,\n wormholeChainId?: number,\n ): Promise<SpendingLimits> {\n const chainId = wormholeChainId ?? this.sdk.getChainConfig().wormholeChainId;\n const rpcUrl = this.sdk.getChainConfig().rpcUrl;\n return this.sdk.spendingLimits.getSpendingLimits(vaultAddress, chainId, rpcUrl);\n }\n\n /**\n * Read spending limits for multiple vaults in parallel.\n */\n async getSpendingLimitsForVaults(\n vaultAddresses: string[],\n wormholeChainId?: number,\n ): Promise<Map<string, SpendingLimits | Error>> {\n const chainId = wormholeChainId ?? this.sdk.getChainConfig().wormholeChainId;\n const rpcUrl = this.sdk.getChainConfig().rpcUrl;\n\n const entries = await Promise.allSettled(\n vaultAddresses.map(async addr => {\n const limits = await this.sdk.spendingLimits.getSpendingLimits(addr, chainId, rpcUrl);\n return [addr, limits] as const;\n }),\n );\n\n const map = new Map<string, SpendingLimits | Error>();\n for (let i = 0; i < entries.length; i++) {\n const entry = entries[i];\n const addr = vaultAddresses[i];\n if (entry.status === 'fulfilled') {\n map.set(addr, entry.value[1]);\n } else {\n map.set(addr, entry.reason instanceof Error ? entry.reason : new Error(String(entry.reason)));\n }\n }\n return map;\n }\n\n // ========================================================================\n // Balance Watching (Subscription / Webhook-style)\n // ========================================================================\n\n /**\n * Watch a vault's balance for changes.\n *\n * The callback fires whenever the polling interval detects a difference.\n * Returns an unsubscribe function.\n *\n * @example\n * ```typescript\n * const unsub = enterprise.watchVaultBalance(\n * 10004,\n * '0xVaultAddr',\n * (event) => {\n * // Push to webhook, update dashboard, etc.\n * fetch(webhookUrl, { method: 'POST', body: JSON.stringify(event) });\n * },\n * { intervalMs: 10_000 },\n * );\n * ```\n */\n watchVaultBalance(\n wormholeChainId: number,\n address: string,\n onChange: BalanceChangeCallback,\n options?: BalanceWatcherOptions,\n onError?: BalanceErrorCallback,\n ): Unsubscribe {\n return this.balanceWatcher.watch(wormholeChainId, address, onChange, options, onError);\n }\n\n /**\n * Stop all active balance watchers.\n */\n stopAllWatchers(): void {\n this.balanceWatcher.stopAll();\n }\n\n /**\n * Get number of active balance watchers.\n */\n get activeWatcherCount(): number {\n return this.balanceWatcher.activeCount;\n }\n\n // ========================================================================\n // Vault Overview (Dashboard)\n // ========================================================================\n\n /**\n * Get a combined overview for a vault: existence, balances, limits.\n *\n * Useful for rendering an admin dashboard row.\n */\n async getVaultOverview(\n keyHash: string,\n wormholeChainId?: number,\n ): Promise<VaultOverview> {\n const chainId = wormholeChainId ?? this.sdk.getChainConfig().wormholeChainId;\n const chainClient = this.sdk.getChainClient();\n const vaultAddress = chainClient.computeVaultAddress(keyHash);\n const exists = await chainClient.vaultExists(keyHash);\n\n let balance: PortfolioBalance | undefined;\n let limits: SpendingLimits | undefined;\n\n if (exists) {\n try {\n balance = await this.sdk.balance.getPortfolioBalance(chainId, vaultAddress, false);\n } catch { /* swallow — non-critical */ }\n\n try {\n limits = await this.getSpendingLimitsForVault(vaultAddress, chainId);\n } catch { /* swallow — non-critical */ }\n }\n\n return {\n keyHash,\n vaultAddress,\n wormholeChainId: chainId,\n exists,\n balance,\n limits,\n };\n }\n}\n","/**\n * @packageDocumentation\n * @module erc8004/contracts\n * @description\n * Low-level ERC-8004 contract utilities shared across SDK layers.\n * \n * Provides:\n * - Contract instance creation for Identity, Reputation, and Validation registries\n * - Address resolution by chain and network\n * - ABI references\n * \n * This module lives in the core SDK (`@veridex/sdk`) so that both the agent-sdk\n * and relayer can share the same contract interaction utilities.\n * \n * References:\n * - ADR-0029 §SDK Module Structure\n * - ERC8004_IMPLEMENTATION_PLAN.md Phase 1\n */\n\n// ============================================================================\n// Canonical Singleton Addresses (CREATE2 deterministic — same on every chain)\n// ============================================================================\n\n/** Identity Registry — same address on ALL EVM mainnets */\nexport const ERC8004_MAINNET_IDENTITY = '0x8004A169FB4a3325136EB29fA0ceB6D2e539a432';\n\n/** Reputation Registry — same address on ALL EVM mainnets */\nexport const ERC8004_MAINNET_REPUTATION = '0x8004BAa17C55a88189AE136b182e5fdA19dE9b63';\n\n/** Identity Registry — same address on ALL EVM testnets */\nexport const ERC8004_TESTNET_IDENTITY = '0x8004A818BFB912233c491871b3d84c89A494BD9e';\n\n/** Reputation Registry — same address on ALL EVM testnets */\nexport const ERC8004_TESTNET_REPUTATION = '0x8004B663056A597Dffe9eCcC1965A193B7388713';\n\n// Validation Registry addresses not yet published (spec still under active update)\n\n/**\n * Resolve canonical ERC-8004 registry addresses for a given network.\n */\nexport function getERC8004Addresses(testnet: boolean): {\n identityRegistry: string;\n reputationRegistry: string;\n} {\n return {\n identityRegistry: testnet ? ERC8004_TESTNET_IDENTITY : ERC8004_MAINNET_IDENTITY,\n reputationRegistry: testnet ? ERC8004_TESTNET_REPUTATION : ERC8004_MAINNET_REPUTATION,\n };\n}\n\n/**\n * Check if a chain has ERC-8004 singletons deployed.\n */\nexport function isERC8004Chain(chainName: string): boolean {\n return (ERC8004_CHAINS.mainnet as readonly string[]).includes(chainName) ||\n (ERC8004_CHAINS.testnet as readonly string[]).includes(chainName);\n}\n\n/** Chains where ERC-8004 singletons are deployed */\nexport const ERC8004_CHAINS = {\n mainnet: [\n 'ethereum', 'base', 'polygon', 'arbitrum', 'optimism', 'linea', 'megaeth', 'monad',\n ],\n testnet: [\n 'ethereum-sepolia', 'base-sepolia', 'polygon-amoy', 'arbitrum-sepolia',\n 'optimism-sepolia', 'monad-testnet',\n ],\n} as const;\n\n// ============================================================================\n// ABIs — Minimal read-only interfaces for cross-package use\n// ============================================================================\n\n/** Minimal Identity Registry ABI for read operations */\nexport const IDENTITY_REGISTRY_READ_ABI = [\n 'function ownerOf(uint256 tokenId) view returns (address)',\n 'function balanceOf(address owner) view returns (uint256)',\n 'function totalSupply() view returns (uint256)',\n 'function agentURI(uint256 agentId) view returns (string)',\n 'function agentWallet(uint256 agentId) view returns (address)',\n 'function getMetadata(uint256 agentId, string key) view returns (string)',\n] as const;\n\n/** Minimal Reputation Registry ABI for read operations */\nexport const REPUTATION_REGISTRY_READ_ABI = [\n 'function getSummary(uint256 agentId, address[] clientAddresses, string tag1, string tag2) view returns (uint256 count, int128 summaryValue, uint8 summaryValueDecimals)',\n 'function readFeedback(uint256 agentId, address clientAddress, uint256 feedbackIndex) view returns (int128 value, uint8 valueDecimals, string tag1, string tag2, bool isRevoked)',\n 'function getClients(uint256 agentId) view returns (address[])',\n 'function getLastIndex(uint256 agentId, address clientAddress) view returns (uint256)',\n] as const;\n\n/** Full Identity Registry ABI (read + write) */\nexport const IDENTITY_REGISTRY_ABI = [\n // Registration\n 'function register(string agentURI) returns (uint256)',\n 'function register(string agentURI, tuple(string key, string value)[] metadata) returns (uint256)',\n\n // Read — ERC-721 standard\n 'function ownerOf(uint256 tokenId) view returns (address)',\n 'function balanceOf(address owner) view returns (uint256)',\n 'function totalSupply() view returns (uint256)',\n\n // Read — ERC-8004 specific\n 'function agentURI(uint256 agentId) view returns (string)',\n 'function agentWallet(uint256 agentId) view returns (address)',\n 'function getMetadata(uint256 agentId, string key) view returns (string)',\n\n // Write — URI and wallet management\n 'function setAgentURI(uint256 agentId, string newURI)',\n 'function setAgentWallet(uint256 agentId, address wallet, uint256 deadline, bytes signature)',\n 'function unsetAgentWallet(uint256 agentId)',\n 'function setMetadata(uint256 agentId, string key, string value)',\n\n // Events\n 'event Transfer(address indexed from, address indexed to, uint256 indexed tokenId)',\n 'event AgentURIUpdated(uint256 indexed agentId, string newURI)',\n 'event AgentWalletSet(uint256 indexed agentId, address wallet)',\n 'event AgentWalletUnset(uint256 indexed agentId)',\n 'event MetadataUpdated(uint256 indexed agentId, string key, string value)',\n] as const;\n\n/** Full Reputation Registry ABI (read + write) */\nexport const REPUTATION_REGISTRY_ABI = [\n // Write\n 'function giveFeedback(uint256 agentId, int128 value, uint8 valueDecimals, string tag1, string tag2)',\n 'function giveFeedback(uint256 agentId, int128 value, uint8 valueDecimals, string tag1, string tag2, string endpointURI, string feedbackURI, bytes32 feedbackHash)',\n 'function revokeFeedback(uint256 agentId, uint256 feedbackIndex)',\n 'function appendResponse(uint256 agentId, address clientAddress, uint256 feedbackIndex, string responseURI, bytes32 responseHash)',\n\n // Read\n 'function getSummary(uint256 agentId, address[] clientAddresses, string tag1, string tag2) view returns (uint256 count, int128 summaryValue, uint8 summaryValueDecimals)',\n 'function readFeedback(uint256 agentId, address clientAddress, uint256 feedbackIndex) view returns (int128 value, uint8 valueDecimals, string tag1, string tag2, bool isRevoked)',\n 'function getClients(uint256 agentId) view returns (address[])',\n 'function getLastIndex(uint256 agentId, address clientAddress) view returns (uint256)',\n\n // Events\n 'event FeedbackGiven(uint256 indexed agentId, address indexed client, int128 value, uint8 valueDecimals)',\n 'event FeedbackRevoked(uint256 indexed agentId, address indexed client, uint256 feedbackIndex)',\n 'event ResponseAppended(uint256 indexed agentId, address indexed client, uint256 feedbackIndex)',\n] as const;\n\n/** Validation Registry ABI (Phase 3 — spec still under active update) */\nexport const VALIDATION_REGISTRY_ABI = [\n 'function validationRequest(address validatorAddress, uint256 agentId, string requestURI, bytes32 requestHash) returns (bytes32)',\n 'function getValidationStatus(bytes32 requestHash) view returns (address validatorAddress, uint256 agentId, uint8 response, bytes32 responseHash, string tag, uint256 lastUpdate)',\n 'function getSummary(uint256 agentId, address[] validatorAddresses, string tag) view returns (uint256 count, uint256 averageResponse)',\n 'function getAgentValidations(uint256 agentId) view returns (bytes32[])',\n] as const;\n"],"mappings":"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","names":["ethers","DEFAULT_RPC_URLS","ethers","ethers","DEFAULT_CONFIG","ethers","formatAmount","isNativeToken","ethers","ethers","VAULT_ABI","ethers","VeridexErrorCode","ethers","ethers","VAULT_FACTORY_ABI","TESTNET_CHAINS","MAINNET_CHAINS","ethers","result","data","ethers","ethers","ethers","ethers","ethers","ethers","ethers"]}
|
|
1
|
+
{"version":3,"sources":["../src/core/BalanceManager.ts","../src/core/TransactionTracker.ts","../src/core/CrossChainManager.ts","../src/core/RelayerClient.ts","../src/core/ChainDetector.ts","../src/core/TransactionParser.ts","../src/core/TransactionSummary.types.ts","../src/core/SpendingLimitsManager.ts","../src/core/SpendingLimits.types.ts","../src/core/AccountManager.ts","../src/core/RecoveryManager.ts","../src/core/MultisigManager.ts","../src/core/PolicyEnforcement.ts","../src/core/VeridexError.ts","../src/core/BalanceWatcher.ts","../src/core/VeridexSDK.ts","../src/core/GasSponsor.ts","../src/factory.ts","../src/core/BrowserCapabilities.ts","../src/core/CredentialManager.ts","../src/core/CrossOriginAuth.ts","../src/core/InjectedWalletAdapter.ts","../src/sessions/index.ts","../src/sessions/types.ts","../src/sessions/crypto.ts","../src/sessions/storage.ts","../src/constants/errors.ts","../src/core/EnterpriseManager.ts","../src/erc8004/contracts.ts"],"sourcesContent":["/**\n * Veridex Protocol SDK - Balance Manager\n * \n * Manages balance fetching for native tokens and ERC20s across chains\n */\n\nimport { ethers } from 'ethers';\nimport { \n TokenInfo, \n getTokenList, \n getAllTokens, \n isNativeToken, \n NATIVE_TOKEN_ADDRESS \n} from '../constants/tokens.js';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface TokenBalance {\n /** Token information */\n token: TokenInfo;\n /** Raw balance in smallest units */\n balance: bigint;\n /** Formatted balance with decimals */\n formatted: string;\n /** USD value (if price available) */\n usdValue?: number;\n}\n\nexport interface PortfolioBalance {\n /** Wormhole chain ID */\n wormholeChainId: number;\n /** Chain name */\n chainName: string;\n /** Address being queried */\n address: string;\n /** Individual token balances */\n tokens: TokenBalance[];\n /** Total USD value (if prices available) */\n totalUsdValue?: number;\n /** Timestamp of last update */\n lastUpdated: number;\n}\n\nexport interface BalanceManagerConfig {\n /** Whether to cache balances */\n cacheBalances?: boolean;\n /** Cache TTL in milliseconds */\n cacheTtl?: number;\n /** Custom RPC URLs by chain ID */\n customRpcUrls?: Record<number, string>;\n}\n\n// ============================================================================\n// Constants\n// ============================================================================\n\n/**\n * Default RPC URLs for testnet chains\n */\nconst DEFAULT_RPC_URLS: Record<number, string> = {\n 10002: 'https://ethereum-sepolia-rpc.publicnode.com',\n 10003: 'https://sepolia-rollup.arbitrum.io/rpc',\n 10004: 'https://sepolia.base.org',\n 10005: 'https://sepolia.optimism.io',\n};\n\n/**\n * Testnet token prices (USD) for development/testing\n * These are static estimates since testnet tokens have no real value\n */\nconst TESTNET_TOKEN_PRICES: Record<string, number> = {\n ETH: 2500,\n WETH: 2500,\n 'WETH.BASE': 2500, // Wormhole-wrapped Base WETH\n USDC: 1,\n USDT: 1,\n DAI: 1,\n WBTC: 60000,\n LINK: 15,\n UNI: 8,\n};\n\n/**\n * ERC20 ABI for balance checking\n */\nconst ERC20_ABI = [\n 'function balanceOf(address owner) view returns (uint256)',\n 'function decimals() view returns (uint8)',\n 'function symbol() view returns (string)',\n 'function name() view returns (string)',\n];\n\n/**\n * Default cache TTL: 30 seconds\n */\nconst DEFAULT_CACHE_TTL = 30_000;\n\n// ============================================================================\n// Balance Cache\n// ============================================================================\n\ninterface CachedBalance {\n balance: PortfolioBalance;\n expiresAt: number;\n}\n\n// ============================================================================\n// Balance Manager Class\n// ============================================================================\n\nexport class BalanceManager {\n private config: Required<BalanceManagerConfig>;\n private providers: Map<number, ethers.JsonRpcProvider> = new Map();\n private cache: Map<string, CachedBalance> = new Map();\n\n constructor(config: BalanceManagerConfig = {}) {\n this.config = {\n cacheBalances: config.cacheBalances ?? true,\n cacheTtl: config.cacheTtl ?? DEFAULT_CACHE_TTL,\n customRpcUrls: config.customRpcUrls ?? {},\n };\n }\n\n // ========================================================================\n // Public Methods\n // ========================================================================\n\n /**\n * Get balance for a specific token on a chain\n * \n * @param wormholeChainId - The Wormhole chain ID\n * @param address - The address to check balance for\n * @param tokenAddress - Token address or 'native' for native token\n * @returns TokenBalance with raw and formatted amounts\n */\n async getBalance(\n wormholeChainId: number,\n address: string,\n tokenAddress: string\n ): Promise<TokenBalance> {\n const provider = this.getProvider(wormholeChainId);\n const tokenList = getTokenList(wormholeChainId);\n \n if (!tokenList) {\n throw new Error(`Chain ${wormholeChainId} not supported`);\n }\n\n const tokens = getAllTokens(wormholeChainId);\n let tokenInfo = tokens.find(\n t => t.address.toLowerCase() === tokenAddress.toLowerCase()\n );\n\n // Handle native token variations\n if (!tokenInfo && isNativeToken(tokenAddress)) {\n tokenInfo = tokenList.nativeToken;\n }\n\n // If still no token info, create a generic one\n if (!tokenInfo) {\n tokenInfo = await this.fetchTokenInfo(provider, tokenAddress);\n }\n\n const balance = await this.fetchBalance(provider, address, tokenAddress, tokenInfo);\n const formatted = ethers.formatUnits(balance, tokenInfo.decimals);\n // Calculate USD value using testnet prices\n const price = TESTNET_TOKEN_PRICES[tokenInfo.symbol.toUpperCase()];\n const usdValue = price ? parseFloat(formatted) * price : undefined;\n\n return {\n token: tokenInfo,\n balance,\n formatted,\n usdValue,\n };\n }\n\n /**\n * Get all token balances for an address on a chain\n * \n * @param wormholeChainId - The Wormhole chain ID\n * @param address - The address to check balances for\n * @param includeZeroBalances - Whether to include tokens with 0 balance\n * @returns PortfolioBalance with all token balances\n */\n async getPortfolioBalance(\n wormholeChainId: number,\n address: string,\n includeZeroBalances: boolean = false\n ): Promise<PortfolioBalance> {\n // Check cache first\n const cacheKey = `${wormholeChainId}:${address.toLowerCase()}`;\n if (this.config.cacheBalances) {\n const cached = this.cache.get(cacheKey);\n if (cached && cached.expiresAt > Date.now()) {\n return cached.balance;\n }\n }\n\n const tokenList = getTokenList(wormholeChainId);\n if (!tokenList) {\n throw new Error(`Chain ${wormholeChainId} not supported`);\n }\n\n const provider = this.getProvider(wormholeChainId);\n const tokens = getAllTokens(wormholeChainId);\n const balances: TokenBalance[] = [];\n\n // Fetch all balances in parallel\n const balancePromises = tokens.map(async (token) => {\n try {\n const balance = await this.fetchBalance(\n provider,\n address,\n token.address,\n token\n );\n const formatted = ethers.formatUnits(balance, token.decimals);\n // Calculate USD value using testnet prices\n const price = TESTNET_TOKEN_PRICES[token.symbol.toUpperCase()];\n const usdValue = price ? parseFloat(formatted) * price : undefined;\n return { token, balance, formatted, usdValue };\n } catch (error) {\n console.warn(`Failed to fetch ${token.symbol} balance:`, error);\n return { token, balance: 0n, formatted: '0', usdValue: undefined };\n }\n });\n\n const results = await Promise.all(balancePromises);\n\n for (const result of results) {\n if (includeZeroBalances || result.balance > 0n) {\n balances.push(result);\n }\n }\n\n // Calculate total USD value\n const totalUsdValue = balances.reduce((sum, b) => sum + (b.usdValue ?? 0), 0);\n\n const portfolio: PortfolioBalance = {\n wormholeChainId,\n chainName: tokenList.chainName,\n address,\n tokens: balances,\n totalUsdValue: totalUsdValue > 0 ? totalUsdValue : undefined,\n lastUpdated: Date.now(),\n };\n\n // Cache the result\n if (this.config.cacheBalances) {\n this.cache.set(cacheKey, {\n balance: portfolio,\n expiresAt: Date.now() + this.config.cacheTtl,\n });\n }\n\n return portfolio;\n }\n\n /**\n * Get native token balance\n * \n * @param wormholeChainId - The Wormhole chain ID\n * @param address - The address to check\n * @returns TokenBalance for native token\n */\n async getNativeBalance(\n wormholeChainId: number,\n address: string\n ): Promise<TokenBalance> {\n return this.getBalance(wormholeChainId, address, NATIVE_TOKEN_ADDRESS);\n }\n\n /**\n * Get balances across multiple chains for an address\n * \n * @param address - The address to check\n * @param chainIds - Array of Wormhole chain IDs to check\n * @returns Array of PortfolioBalance for each chain\n */\n async getMultiChainBalances(\n address: string,\n chainIds: number[]\n ): Promise<PortfolioBalance[]> {\n const promises = chainIds.map(chainId =>\n this.getPortfolioBalance(chainId, address).catch(error => {\n console.warn(`Failed to fetch balances for chain ${chainId}:`, error);\n return null;\n })\n );\n\n const results = await Promise.all(promises);\n return results.filter((r): r is PortfolioBalance => r !== null);\n }\n\n /**\n * Clear the balance cache\n */\n clearCache(): void {\n this.cache.clear();\n }\n\n /**\n * Invalidate cache for a specific address\n */\n invalidateCache(wormholeChainId: number, address: string): void {\n const cacheKey = `${wormholeChainId}:${address.toLowerCase()}`;\n this.cache.delete(cacheKey);\n }\n\n /**\n * Add or update RPC URL for a chain\n */\n setRpcUrl(wormholeChainId: number, rpcUrl: string): void {\n this.config.customRpcUrls[wormholeChainId] = rpcUrl;\n // Clear existing provider to force recreation\n this.providers.delete(wormholeChainId);\n }\n\n // ========================================================================\n // Private Methods\n // ========================================================================\n\n /**\n * Get or create a provider for a chain\n */\n private getProvider(wormholeChainId: number): ethers.JsonRpcProvider {\n let provider = this.providers.get(wormholeChainId);\n if (provider) {\n return provider;\n }\n\n const rpcUrl = this.config.customRpcUrls[wormholeChainId] ?? \n DEFAULT_RPC_URLS[wormholeChainId];\n \n if (!rpcUrl) {\n throw new Error(`No RPC URL configured for chain ${wormholeChainId}`);\n }\n\n provider = new ethers.JsonRpcProvider(rpcUrl);\n this.providers.set(wormholeChainId, provider);\n return provider;\n }\n\n /**\n * Fetch balance for a token\n */\n private async fetchBalance(\n provider: ethers.JsonRpcProvider,\n address: string,\n tokenAddress: string,\n _tokenInfo: TokenInfo\n ): Promise<bigint> {\n if (isNativeToken(tokenAddress)) {\n return await provider.getBalance(address);\n }\n\n const contract = new ethers.Contract(tokenAddress, ERC20_ABI, provider);\n return await contract.balanceOf(address);\n }\n\n /**\n * Fetch token info from contract\n */\n private async fetchTokenInfo(\n provider: ethers.JsonRpcProvider,\n tokenAddress: string\n ): Promise<TokenInfo> {\n const contract = new ethers.Contract(tokenAddress, ERC20_ABI, provider);\n \n const [symbol, name, decimals] = await Promise.all([\n contract.symbol().catch(() => 'UNKNOWN'),\n contract.name().catch(() => 'Unknown Token'),\n contract.decimals().catch(() => 18),\n ]);\n\n return {\n symbol,\n name,\n address: tokenAddress,\n decimals: Number(decimals),\n isNative: false,\n };\n }\n}\n","/**\n * Veridex Protocol SDK - Transaction Tracker\n * \n * Tracks transaction status from pending to confirmed\n */\n\nimport { ethers } from 'ethers';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport type TransactionStatus = \n | 'pending'\n | 'submitted'\n | 'confirming'\n | 'confirmed'\n | 'failed'\n | 'dropped';\n\nexport interface TransactionState {\n /** Transaction hash */\n hash: string;\n /** Current status */\n status: TransactionStatus;\n /** Wormhole chain ID where transaction was sent */\n wormholeChainId: number;\n /** Block number when confirmed */\n blockNumber?: number;\n /** Number of confirmations */\n confirmations: number;\n /** Required confirmations for finality */\n requiredConfirmations: number;\n /** Gas used (after confirmation) */\n gasUsed?: bigint;\n /** Effective gas price */\n effectiveGasPrice?: bigint;\n /** Error message if failed */\n error?: string;\n /** Timestamp when transaction was submitted */\n submittedAt: number;\n /** Timestamp when transaction was confirmed */\n confirmedAt?: number;\n /** VAA sequence number (for cross-chain txs) */\n vaaSequence?: bigint;\n}\n\nexport interface TrackerConfig {\n /** Polling interval in ms (default: 2000) */\n pollingInterval?: number;\n /** Required confirmations for finality (default: 1) */\n requiredConfirmations?: number;\n /** Timeout in ms before marking as dropped (default: 300000 - 5 min) */\n timeout?: number;\n /** Custom RPC URLs by chain ID */\n customRpcUrls?: Record<number, string>;\n}\n\nexport type TransactionCallback = (state: TransactionState) => void;\n\n// ============================================================================\n// Constants\n// ============================================================================\n\nconst DEFAULT_POLLING_INTERVAL = 2000;\nconst DEFAULT_REQUIRED_CONFIRMATIONS = 1;\nconst DEFAULT_TIMEOUT = 300_000; // 5 minutes\n\nconst DEFAULT_RPC_URLS: Record<number, string> = {\n 10002: 'https://ethereum-sepolia-rpc.publicnode.com',\n 10003: 'https://sepolia-rollup.arbitrum.io/rpc',\n 10004: 'https://sepolia.base.org',\n 10005: 'https://sepolia.optimism.io',\n};\n\n// ============================================================================\n// Transaction Tracker Class\n// ============================================================================\n\nexport class TransactionTracker {\n private config: Required<TrackerConfig>;\n private providers: Map<number, ethers.JsonRpcProvider> = new Map();\n private trackedTransactions: Map<string, TransactionState> = new Map();\n private callbacks: Map<string, TransactionCallback[]> = new Map();\n private pollingIntervals: Map<string, NodeJS.Timeout> = new Map();\n\n constructor(config: TrackerConfig = {}) {\n this.config = {\n pollingInterval: config.pollingInterval ?? DEFAULT_POLLING_INTERVAL,\n requiredConfirmations: config.requiredConfirmations ?? DEFAULT_REQUIRED_CONFIRMATIONS,\n timeout: config.timeout ?? DEFAULT_TIMEOUT,\n customRpcUrls: config.customRpcUrls ?? {},\n };\n }\n\n // ========================================================================\n // Public Methods\n // ========================================================================\n\n /**\n * Track a transaction and receive status updates\n * \n * @param hash - Transaction hash\n * @param wormholeChainId - Chain where transaction was sent\n * @param callback - Optional callback for status updates\n * @param vaaSequence - Optional VAA sequence for cross-chain transactions\n * @returns Initial transaction state\n */\n track(\n hash: string,\n wormholeChainId: number,\n callback?: TransactionCallback,\n vaaSequence?: bigint\n ): TransactionState {\n // Create initial state\n const state: TransactionState = {\n hash,\n status: 'pending',\n wormholeChainId,\n confirmations: 0,\n requiredConfirmations: this.config.requiredConfirmations,\n submittedAt: Date.now(),\n vaaSequence,\n };\n\n this.trackedTransactions.set(hash, state);\n \n if (callback) {\n this.addCallback(hash, callback);\n }\n\n // Start polling\n this.startPolling(hash, wormholeChainId);\n\n return state;\n }\n\n /**\n * Add a callback for transaction updates\n */\n addCallback(hash: string, callback: TransactionCallback): void {\n const existing = this.callbacks.get(hash) ?? [];\n existing.push(callback);\n this.callbacks.set(hash, existing);\n }\n\n /**\n * Remove a callback\n */\n removeCallback(hash: string, callback: TransactionCallback): void {\n const existing = this.callbacks.get(hash) ?? [];\n const filtered = existing.filter(cb => cb !== callback);\n if (filtered.length > 0) {\n this.callbacks.set(hash, filtered);\n } else {\n this.callbacks.delete(hash);\n }\n }\n\n /**\n * Get current state of a tracked transaction\n */\n getState(hash: string): TransactionState | null {\n return this.trackedTransactions.get(hash) ?? null;\n }\n\n /**\n * Wait for a transaction to reach confirmed status\n * \n * @param hash - Transaction hash\n * @param wormholeChainId - Chain where transaction was sent\n * @returns Promise that resolves when confirmed or rejects on failure\n */\n async waitForConfirmation(\n hash: string,\n wormholeChainId: number\n ): Promise<TransactionState> {\n // Check if already tracked\n let state = this.trackedTransactions.get(hash);\n \n if (!state) {\n state = this.track(hash, wormholeChainId);\n }\n\n // If already confirmed or failed, return immediately\n if (state.status === 'confirmed' || state.status === 'failed' || state.status === 'dropped') {\n return state;\n }\n\n // Wait for confirmation\n return new Promise((resolve, reject) => {\n const callback: TransactionCallback = (newState) => {\n if (newState.status === 'confirmed') {\n this.removeCallback(hash, callback);\n resolve(newState);\n } else if (newState.status === 'failed' || newState.status === 'dropped') {\n this.removeCallback(hash, callback);\n reject(new Error(newState.error ?? `Transaction ${newState.status}`));\n }\n };\n\n this.addCallback(hash, callback);\n });\n }\n\n /**\n * Stop tracking a transaction\n */\n stopTracking(hash: string): void {\n const interval = this.pollingIntervals.get(hash);\n if (interval) {\n clearInterval(interval);\n this.pollingIntervals.delete(hash);\n }\n this.trackedTransactions.delete(hash);\n this.callbacks.delete(hash);\n }\n\n /**\n * Stop tracking all transactions\n */\n stopAll(): void {\n for (const hash of this.pollingIntervals.keys()) {\n this.stopTracking(hash);\n }\n }\n\n /**\n * Get all tracked transactions\n */\n getAllTracked(): TransactionState[] {\n return Array.from(this.trackedTransactions.values());\n }\n\n /**\n * Get pending transactions\n */\n getPending(): TransactionState[] {\n return this.getAllTracked().filter(\n tx => tx.status === 'pending' || tx.status === 'submitted' || tx.status === 'confirming'\n );\n }\n\n // ========================================================================\n // Private Methods\n // ========================================================================\n\n /**\n * Get or create provider for a chain\n */\n private getProvider(wormholeChainId: number): ethers.JsonRpcProvider {\n let provider = this.providers.get(wormholeChainId);\n if (provider) {\n return provider;\n }\n\n const rpcUrl = this.config.customRpcUrls[wormholeChainId] ?? \n DEFAULT_RPC_URLS[wormholeChainId];\n \n if (!rpcUrl) {\n throw new Error(`No RPC URL configured for chain ${wormholeChainId}`);\n }\n\n provider = new ethers.JsonRpcProvider(rpcUrl);\n this.providers.set(wormholeChainId, provider);\n return provider;\n }\n\n /**\n * Start polling for transaction status\n */\n private startPolling(hash: string, wormholeChainId: number): void {\n // Initial check\n this.checkTransaction(hash, wormholeChainId);\n\n // Set up interval\n const interval = setInterval(() => {\n this.checkTransaction(hash, wormholeChainId);\n }, this.config.pollingInterval);\n\n this.pollingIntervals.set(hash, interval);\n }\n\n /**\n * Check transaction status\n */\n private async checkTransaction(hash: string, wormholeChainId: number): Promise<void> {\n const state = this.trackedTransactions.get(hash);\n if (!state) {\n this.stopTracking(hash);\n return;\n }\n\n // Check timeout\n if (Date.now() - state.submittedAt > this.config.timeout) {\n this.updateState(hash, {\n status: 'dropped',\n error: 'Transaction timeout - possibly dropped from mempool',\n });\n this.stopTracking(hash);\n return;\n }\n\n try {\n const provider = this.getProvider(wormholeChainId);\n const receipt = await provider.getTransactionReceipt(hash);\n\n if (!receipt) {\n // Transaction not yet mined\n if (state.status === 'pending') {\n this.updateState(hash, { status: 'submitted' });\n }\n return;\n }\n\n // Transaction is mined\n const currentBlock = await provider.getBlockNumber();\n const confirmations = currentBlock - receipt.blockNumber + 1;\n\n if (receipt.status === 0) {\n // Transaction failed\n this.updateState(hash, {\n status: 'failed',\n blockNumber: receipt.blockNumber,\n confirmations,\n gasUsed: receipt.gasUsed,\n effectiveGasPrice: receipt.gasPrice,\n error: 'Transaction reverted',\n });\n this.stopTracking(hash);\n return;\n }\n\n if (confirmations >= this.config.requiredConfirmations) {\n // Fully confirmed\n this.updateState(hash, {\n status: 'confirmed',\n blockNumber: receipt.blockNumber,\n confirmations,\n gasUsed: receipt.gasUsed,\n effectiveGasPrice: receipt.gasPrice,\n confirmedAt: Date.now(),\n });\n this.stopTracking(hash);\n } else {\n // Still confirming\n this.updateState(hash, {\n status: 'confirming',\n blockNumber: receipt.blockNumber,\n confirmations,\n gasUsed: receipt.gasUsed,\n effectiveGasPrice: receipt.gasPrice,\n });\n }\n } catch (error) {\n console.warn(`Error checking transaction ${hash}:`, error);\n // Don't update state on transient errors\n }\n }\n\n /**\n * Update transaction state and notify callbacks\n */\n private updateState(hash: string, updates: Partial<TransactionState>): void {\n const current = this.trackedTransactions.get(hash);\n if (!current) return;\n\n const newState: TransactionState = { ...current, ...updates };\n this.trackedTransactions.set(hash, newState);\n\n // Notify callbacks\n const callbacks = this.callbacks.get(hash) ?? [];\n for (const callback of callbacks) {\n try {\n callback(newState);\n } catch (error) {\n console.error('Error in transaction callback:', error);\n }\n }\n }\n}\n\n// ============================================================================\n// Helper Functions\n// ============================================================================\n\n/**\n * Create a formatted transaction explorer URL\n */\nexport function getExplorerUrl(\n wormholeChainId: number,\n hash: string\n): string | null {\n const explorers: Record<number, string> = {\n 10004: 'https://sepolia.basescan.org/tx/',\n 10005: 'https://sepolia-optimism.etherscan.io/tx/',\n 10003: 'https://sepolia.arbiscan.io/tx/',\n };\n\n const baseUrl = explorers[wormholeChainId];\n return baseUrl ? `${baseUrl}${hash}` : null;\n}\n\n/**\n * Format transaction state for display\n */\nexport function formatTransactionState(state: TransactionState): string {\n switch (state.status) {\n case 'pending':\n return 'Transaction pending...';\n case 'submitted':\n return 'Transaction submitted, waiting for confirmation...';\n case 'confirming':\n return `Confirming (${state.confirmations}/${state.requiredConfirmations})...`;\n case 'confirmed':\n return 'Transaction confirmed!';\n case 'failed':\n return `Transaction failed: ${state.error ?? 'Unknown error'}`;\n case 'dropped':\n return 'Transaction dropped from mempool';\n default:\n return 'Unknown status';\n }\n}\n","/**\n * Veridex Protocol SDK - Cross-Chain Manager\n * \n * Orchestrates cross-chain transfers including:\n * - VAA fetching and parsing\n * - Fee estimation (message + relayer fees)\n * - Transaction status tracking across chains\n * - Lifecycle callbacks for UI updates\n */\n\nimport { ethers } from 'ethers';\nimport {\n fetchVAA,\n fetchVAAByTxHash,\n parseVAA,\n parseVeridexPayload,\n encodeVAAToBytes,\n getSequenceFromTxReceipt,\n waitForGuardianSignatures,\n normalizeEmitterAddress,\n GUARDIAN_CONFIG,\n} from '../wormhole.js';\nimport type {\n BridgeParams,\n VAA,\n VeridexPayload,\n ChainConfig,\n} from './types.js';\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Cross-chain transfer lifecycle states\n */\nexport type CrossChainStatus =\n | 'preparing'\n | 'signing'\n | 'dispatching'\n | 'waiting_confirmations'\n | 'waiting_guardians'\n | 'vaa_ready'\n | 'relaying'\n | 'executing'\n | 'completed'\n | 'failed';\n\n/**\n * Progress callback for cross-chain operations\n */\nexport interface CrossChainProgress {\n status: CrossChainStatus;\n step: number;\n totalSteps: number;\n message: string;\n details?: {\n txHash?: string;\n sequence?: bigint;\n guardianSignatures?: number;\n requiredSignatures?: number;\n vaaReady?: boolean;\n destinationTxHash?: string;\n };\n}\n\n/**\n * Cross-chain transfer result\n */\nexport interface CrossChainResult {\n /** Source chain transaction hash */\n sourceTxHash: string;\n /** Wormhole message sequence number */\n sequence: bigint;\n /** Emitter address (Hub contract) */\n emitterAddress: string;\n /** Source chain Wormhole ID */\n sourceChain: number;\n /** Destination chain Wormhole ID */\n destinationChain: number;\n /** VAA base64 (once ready) */\n vaa?: string;\n /** Parsed VAA */\n parsedVaa?: VAA;\n /** Destination chain transaction hash */\n destinationTxHash?: string;\n /** Total time taken in ms */\n duration: number;\n /** Final status */\n status: CrossChainStatus;\n /** Error message if failed */\n error?: string;\n}\n\n/**\n * Fee breakdown for cross-chain transfers\n */\nexport interface CrossChainFees {\n /** Gas cost on source chain */\n sourceGas: bigint;\n /** Wormhole message fee */\n messageFee: bigint;\n /** Relayer fee (if using automatic relay) */\n relayerFee: bigint;\n /** Total estimated cost in source chain native token */\n totalCost: bigint;\n /** Formatted total cost */\n formattedTotal: string;\n /** Currency symbol */\n currency: string;\n}\n\n/**\n * Configuration for CrossChainManager\n */\nexport interface CrossChainConfig {\n /** Use testnet APIs (default: true) */\n testnet?: boolean;\n /** Relayer service URL (optional) */\n relayerUrl?: string;\n /** Max time to wait for VAA (ms) */\n vaaTimeoutMs?: number;\n /** Interval to poll for VAA (ms) */\n vaaPollingIntervalMs?: number;\n /** Required block confirmations before fetching VAA */\n confirmationsRequired?: number;\n /** Auto-relay VAA to destination (requires relayer) */\n autoRelay?: boolean;\n}\n\n/**\n * Callback type for progress updates\n */\nexport type CrossChainProgressCallback = (progress: CrossChainProgress) => void;\n\n// ============================================================================\n// Default Configuration\n// ============================================================================\n\nconst DEFAULT_CONFIG: Required<CrossChainConfig> = {\n testnet: true,\n relayerUrl: '',\n vaaTimeoutMs: 120_000, // 2 minutes\n vaaPollingIntervalMs: 3_000, // 3 seconds\n confirmationsRequired: 1,\n autoRelay: false,\n};\n\n// ============================================================================\n// CrossChainManager Class\n// ============================================================================\n\n/**\n * Manages cross-chain transfer lifecycle\n */\nexport class CrossChainManager {\n private config: Required<CrossChainConfig>;\n private pendingTransfers: Map<string, CrossChainResult> = new Map();\n\n constructor(config: CrossChainConfig = {}) {\n this.config = { ...DEFAULT_CONFIG, ...config };\n }\n\n // ========================================================================\n // Configuration\n // ========================================================================\n\n /**\n * Update configuration\n */\n setConfig(config: Partial<CrossChainConfig>): void {\n this.config = { ...this.config, ...config };\n }\n\n /**\n * Get current configuration\n */\n getConfig(): CrossChainConfig {\n return { ...this.config };\n }\n\n // ========================================================================\n // Fee Estimation\n // ========================================================================\n\n /**\n * Estimate fees for a cross-chain transfer\n */\n async estimateFees(\n params: BridgeParams,\n sourceChainConfig: ChainConfig,\n provider: ethers.Provider\n ): Promise<CrossChainFees> {\n // Get current gas price\n const feeData = await provider.getFeeData();\n const gasPrice = feeData.gasPrice ?? 0n;\n \n // Estimate gas for dispatch (Hub chain)\n // This is an approximation - actual gas depends on payload size\n const estimatedGas = 300_000n;\n const sourceGas = estimatedGas * gasPrice;\n\n // Get Wormhole message fee\n let messageFee = 0n;\n try {\n const wormholeAbi = ['function messageFee() view returns (uint256)'];\n const wormhole = new ethers.Contract(\n sourceChainConfig.contracts.wormholeCoreBridge,\n wormholeAbi,\n provider\n );\n messageFee = await wormhole.messageFee();\n } catch {\n // Default to 0 if bridge doesn't have messageFee\n }\n\n // Get relayer fee if using automatic relay\n let relayerFee = 0n;\n if (this.config.autoRelay && this.config.relayerUrl) {\n try {\n relayerFee = await this.fetchRelayerFee(\n params.destinationChain,\n sourceChainConfig.wormholeChainId\n );\n } catch {\n // Relayer fee fetch failed, continue with 0\n }\n }\n\n const totalCost = sourceGas + messageFee + relayerFee;\n\n return {\n sourceGas,\n messageFee,\n relayerFee,\n totalCost,\n formattedTotal: this.formatWei(totalCost),\n currency: 'ETH',\n };\n }\n\n /**\n * Fetch relayer fee from relayer service\n */\n private async fetchRelayerFee(\n destinationChain: number,\n _sourceChain: number\n ): Promise<bigint> {\n if (!this.config.relayerUrl) {\n return 0n;\n }\n\n // The current Veridex relayer exposes a simplified fee endpoint.\n // Source chain is accepted here for future-proofing but not required by the API today.\n const response = await fetch(\n `${this.config.relayerUrl}/api/v1/fee?targetChain=${destinationChain}`\n );\n\n if (!response.ok) {\n throw new Error('Failed to fetch relayer fee');\n }\n\n const data = await response.json() as {\n fees?: {\n wormhole?: string;\n relayer?: string;\n total?: string;\n };\n };\n\n return BigInt(data.fees?.relayer ?? '0');\n }\n\n // ========================================================================\n // VAA Operations\n // ========================================================================\n\n /**\n * Fetch VAA by sequence number\n */\n async fetchVAA(\n emitterChain: number,\n emitterAddress: string,\n sequence: bigint,\n onProgress?: CrossChainProgressCallback\n ): Promise<string> {\n onProgress?.({\n status: 'waiting_guardians',\n step: 4,\n totalSteps: 6,\n message: 'Waiting for Wormhole guardians to sign...',\n details: { sequence },\n });\n\n const vaaBase64 = await fetchVAA(emitterChain, emitterAddress, sequence, {\n testnet: this.config.testnet,\n maxRetries: Math.ceil(this.config.vaaTimeoutMs / this.config.vaaPollingIntervalMs),\n retryDelayMs: this.config.vaaPollingIntervalMs,\n onRetry: (attempt, max) => {\n onProgress?.({\n status: 'waiting_guardians',\n step: 4,\n totalSteps: 6,\n message: `Waiting for guardians (attempt ${attempt}/${max})...`,\n details: { sequence },\n });\n },\n });\n\n onProgress?.({\n status: 'vaa_ready',\n step: 5,\n totalSteps: 6,\n message: 'VAA signed and ready!',\n details: { sequence, vaaReady: true },\n });\n\n return vaaBase64;\n }\n\n /**\n * Fetch VAA by transaction hash (more reliable)\n */\n async fetchVAAByTxHash(\n txHash: string,\n onProgress?: CrossChainProgressCallback\n ): Promise<string> {\n onProgress?.({\n status: 'waiting_guardians',\n step: 4,\n totalSteps: 6,\n message: 'Waiting for Wormhole guardians to sign...',\n details: { txHash },\n });\n\n const vaaBase64 = await fetchVAAByTxHash(txHash, {\n testnet: this.config.testnet,\n maxRetries: Math.ceil(this.config.vaaTimeoutMs / this.config.vaaPollingIntervalMs),\n retryDelayMs: this.config.vaaPollingIntervalMs,\n onRetry: (attempt, max) => {\n onProgress?.({\n status: 'waiting_guardians',\n step: 4,\n totalSteps: 6,\n message: `Waiting for guardians (attempt ${attempt}/${max})...`,\n details: { txHash },\n });\n },\n });\n\n onProgress?.({\n status: 'vaa_ready',\n step: 5,\n totalSteps: 6,\n message: 'VAA signed and ready!',\n details: { txHash, vaaReady: true },\n });\n\n return vaaBase64;\n }\n\n /**\n * Wait for guardians to sign a message with progress tracking\n */\n async waitForGuardians(\n emitterChain: number,\n emitterAddress: string,\n sequence: bigint,\n onProgress?: CrossChainProgressCallback\n ): Promise<VAA> {\n const requiredSignatures = this.config.testnet\n ? GUARDIAN_CONFIG.TESTNET_QUORUM\n : GUARDIAN_CONFIG.MAINNET_QUORUM;\n\n return await waitForGuardianSignatures(\n emitterChain,\n emitterAddress,\n sequence,\n {\n testnet: this.config.testnet,\n requiredSignatures,\n maxWaitMs: this.config.vaaTimeoutMs,\n checkIntervalMs: this.config.vaaPollingIntervalMs,\n onProgress: (current, required) => {\n onProgress?.({\n status: 'waiting_guardians',\n step: 4,\n totalSteps: 6,\n message: `Collecting signatures (${current}/${required})...`,\n details: {\n sequence,\n guardianSignatures: current,\n requiredSignatures: required,\n },\n });\n },\n }\n );\n }\n\n /**\n * Parse a VAA and extract Veridex payload\n */\n parseVAA(vaaBase64: string): { vaa: VAA; payload: VeridexPayload } {\n const vaa = parseVAA(vaaBase64);\n const payload = parseVeridexPayload(vaa.payload);\n return { vaa, payload };\n }\n\n /**\n * Encode VAA for on-chain submission\n */\n encodeVAAForSubmission(vaaBase64: string): string {\n return encodeVAAToBytes(vaaBase64);\n }\n\n // ========================================================================\n // Transfer Lifecycle\n // ========================================================================\n\n /**\n * Track a cross-chain transfer\n */\n trackTransfer(\n sourceTxHash: string,\n sourceChain: number,\n destinationChain: number,\n sequence: bigint,\n emitterAddress: string\n ): CrossChainResult {\n const result: CrossChainResult = {\n sourceTxHash,\n sequence,\n emitterAddress,\n sourceChain,\n destinationChain,\n duration: 0,\n status: 'waiting_guardians',\n };\n\n this.pendingTransfers.set(sourceTxHash, result);\n return result;\n }\n\n /**\n * Get pending transfer by source tx hash\n */\n getPendingTransfer(sourceTxHash: string): CrossChainResult | undefined {\n return this.pendingTransfers.get(sourceTxHash);\n }\n\n /**\n * Get all pending transfers\n */\n getAllPendingTransfers(): CrossChainResult[] {\n return Array.from(this.pendingTransfers.values()).filter(\n t => t.status !== 'completed' && t.status !== 'failed'\n );\n }\n\n /**\n * Update transfer status\n */\n updateTransfer(\n sourceTxHash: string,\n updates: Partial<CrossChainResult>\n ): CrossChainResult | undefined {\n const transfer = this.pendingTransfers.get(sourceTxHash);\n if (!transfer) return undefined;\n\n Object.assign(transfer, updates);\n return transfer;\n }\n\n /**\n * Complete transfer with VAA\n */\n completeTransfer(\n sourceTxHash: string,\n vaa: string,\n destinationTxHash?: string\n ): CrossChainResult | undefined {\n const transfer = this.pendingTransfers.get(sourceTxHash);\n if (!transfer) return undefined;\n\n transfer.vaa = vaa;\n transfer.parsedVaa = parseVAA(vaa);\n transfer.destinationTxHash = destinationTxHash;\n transfer.status = 'completed';\n\n return transfer;\n }\n\n /**\n * Mark transfer as failed\n */\n failTransfer(sourceTxHash: string, error: string): CrossChainResult | undefined {\n const transfer = this.pendingTransfers.get(sourceTxHash);\n if (!transfer) return undefined;\n\n transfer.status = 'failed';\n transfer.error = error;\n\n return transfer;\n }\n\n /**\n * Clear completed/failed transfers\n */\n clearFinishedTransfers(): void {\n for (const [hash, transfer] of this.pendingTransfers.entries()) {\n if (transfer.status === 'completed' || transfer.status === 'failed') {\n this.pendingTransfers.delete(hash);\n }\n }\n }\n\n // ========================================================================\n // Utilities\n // ========================================================================\n\n /**\n * Extract sequence from transaction receipt\n */\n async getSequenceFromTx(\n provider: ethers.Provider,\n txHash: string,\n wormholeCoreBridge: string\n ): Promise<bigint> {\n return await getSequenceFromTxReceipt(provider, txHash, wormholeCoreBridge);\n }\n\n /**\n * Normalize address to emitter format\n */\n normalizeAddress(address: string): string {\n return normalizeEmitterAddress(address);\n }\n\n /**\n * Get explorer URL for a cross-chain transfer\n */\n getExplorerUrl(\n txHash: string,\n _chain: 'source' | 'destination',\n explorerBaseUrl: string\n ): string {\n return `${explorerBaseUrl}/tx/${txHash}`;\n }\n\n /**\n * Get Wormholescan URL for VAA\n */\n getWormholeExplorerUrl(\n emitterChain: number,\n emitterAddress: string,\n sequence: bigint\n ): string {\n const base = this.config.testnet\n ? 'https://wormholescan.io/#/tx'\n : 'https://wormholescan.io/#/tx';\n \n const normalizedEmitter = normalizeEmitterAddress(emitterAddress);\n return `${base}/${emitterChain}/${normalizedEmitter}/${sequence.toString()}`;\n }\n\n /**\n * Format wei to human-readable string\n */\n private formatWei(wei: bigint): string {\n const eth = Number(wei) / 1e18;\n if (eth < 0.0001) {\n return `${(Number(wei) / 1e9).toFixed(4)} gwei`;\n }\n return `${eth.toFixed(6)} ETH`;\n }\n}\n\n// ============================================================================\n// Export singleton for convenience\n// ============================================================================\n\nexport const crossChainManager = new CrossChainManager();\n","/**\n * Veridex Protocol SDK - Relayer Client\n * \n * Client for interacting with the Veridex relayer service.\n * The relayer automatically submits VAAs to destination chains.\n * \n * Features:\n * - Submit VAA for relay\n * - Check relay status\n * - Get supported routes\n * - Fee estimation\n */\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Relay request status\n */\nexport type RelayStatus =\n | 'pending'\n | 'processing'\n | 'submitted'\n | 'confirmed'\n | 'failed';\n\n/**\n * Relay request result\n */\nexport interface RelayRequest {\n /** Unique relay request ID */\n id: string;\n /** VAA sequence number */\n sequence: bigint;\n /** Source chain Wormhole ID */\n sourceChain: number;\n /** Destination chain Wormhole ID */\n destinationChain: number;\n /** Relay status */\n status: RelayStatus;\n /** Source transaction hash */\n sourceTxHash: string;\n /** Destination transaction hash (when completed) */\n destinationTxHash?: string;\n /** Timestamp when request was created */\n createdAt: number;\n /** Timestamp when request was last updated */\n updatedAt: number;\n /** Error message if failed */\n error?: string;\n /** Gas used on destination chain */\n gasUsed?: bigint;\n /** Fee paid */\n feePaid?: bigint;\n}\n\n/**\n * Supported route information\n */\nexport interface RelayRoute {\n /** Source chain Wormhole ID */\n sourceChain: number;\n /** Destination chain Wormhole ID */\n destinationChain: number;\n /** Whether the route is active */\n active: boolean;\n /** Estimated relay time in seconds */\n estimatedTimeSeconds: number;\n /** Base fee in destination chain native token */\n baseFee: bigint;\n /** Fee per gas unit */\n gasPrice: bigint;\n /** Maximum gas limit */\n maxGas: bigint;\n}\n\n/**\n * Relayer service info\n */\nexport interface RelayerInfo {\n /** Relayer name/identifier */\n name: string;\n /** Relayer version */\n version: string;\n /** Supported chains */\n supportedChains: number[];\n /** Available routes */\n routes: RelayRoute[];\n /** Whether the relayer is online */\n online: boolean;\n /** Current queue depth */\n queueDepth: number;\n}\n\n/**\n * Request body for submitting a signed action to the relayer (gasless)\n * Uses full WebAuthn data for authenticateAndDispatch\n */\nexport interface SubmitSignedActionRequest {\n /** WebAuthn authenticatorData (hex) */\n authenticatorData: string;\n /** WebAuthn clientDataJSON (raw string) */\n clientDataJSON: string;\n /** Index of \"challenge\":\"...\" in clientDataJSON */\n challengeIndex: number;\n /** Index of \"type\":\"...\" in clientDataJSON */\n typeIndex: number;\n /** P-256 signature r component (hex) */\n r: string;\n /** P-256 signature s component (hex) */\n s: string;\n /** P-256 public key X coordinate (hex) */\n publicKeyX: string;\n /** P-256 public key Y coordinate (hex) */\n publicKeyY: string;\n /** Target chain Wormhole ID */\n targetChain: number;\n /** Action payload (hex) */\n actionPayload: string;\n /** User nonce */\n nonce: number;\n}\n\n/**\n * Response from submitting a signed action\n */\nexport interface SubmitActionResult {\n /** Whether the submission was successful */\n success: boolean;\n /** Transaction hash on Hub chain */\n txHash?: string;\n /** Wormhole sequence number */\n sequence?: string;\n /** Error message if failed */\n error?: string;\n /** Human-readable message */\n message?: string;\n}\n\n/**\n * Query submission request (Issue #11/#12)\n * For optimistic execution via Wormhole Query proofs (~5-7s vs ~120s)\n */\nexport interface SubmitQueryRequest {\n /** Target spoke chain Wormhole ID */\n targetChain: number;\n /** User's key hash */\n userKeyHash: string;\n /** Serialized transaction for spoke chain */\n serializedTx: string; // hex\n /** Query proof with Guardian signatures */\n queryProof: {\n /** Raw query response bytes */\n queryResponse: string; // hex\n /** Guardian signatures */\n signatures: string; // hex\n };\n /** Whether to fallback to VAA if Query fails */\n fallbackToVaa?: boolean;\n /** Optional metadata */\n metadata?: {\n /** User's preferred execution path */\n preferredPath?: 'query' | 'vaa';\n /** Transaction value in USD (for routing decisions) */\n estimatedValueUSD?: number;\n };\n}\n\n/**\n * Query submission result (Issue #11/#12)\n */\nexport interface SubmitQueryResult {\n /** Whether submission succeeded */\n success: boolean;\n /** Transaction hash on spoke chain */\n txHash?: string;\n /** Execution path used */\n path: 'query' | 'vaa';\n /** Latency in milliseconds */\n latencyMs?: number;\n /** Error message if failed */\n error?: string;\n /** Whether fallback to VAA occurred */\n fellBack?: boolean;\n}\n\n/**\n * Fee quote for a relay\n */\nexport interface RelayFeeQuote {\n /** Source chain Wormhole ID */\n sourceChain: number;\n /** Destination chain Wormhole ID */\n destinationChain: number;\n /** Estimated fee in source chain native token */\n feeInSourceToken: bigint;\n /** Estimated fee in destination chain native token */\n feeInDestinationToken: bigint;\n /** Estimated gas on destination */\n estimatedGas: bigint;\n /** Quote expiration timestamp */\n expiresAt: number;\n /** Quote ID for submission */\n quoteId: string;\n}\n\n/**\n * Configuration for RelayerClient\n */\nexport interface RelayerClientConfig {\n /** Base URL of the relayer service */\n baseUrl: string;\n /** API key for authentication (optional) */\n apiKey?: string;\n /** Timeout for requests in ms */\n timeoutMs?: number;\n /** Max retries for failed requests */\n maxRetries?: number;\n}\n\nexport type RegisteredAppStatus = 'active' | 'suspended' | 'revoked';\nexport type RegisteredAppTrustLevel = 'verified' | 'registered' | 'pending';\n\nexport interface RegisteredAppSummary {\n id: string;\n name: string;\n origin: string;\n trustLevel: RegisteredAppTrustLevel;\n status: RegisteredAppStatus;\n requestCount: number;\n createdAt: number;\n lastUsedAt?: number;\n}\n\nexport interface RegisteredAppDetail extends RegisteredAppSummary {\n description?: string;\n apiKey?: string;\n activeSessionCount?: number;\n}\n\nexport interface RelayerAppSession {\n id: string;\n keyHash: string;\n appOrigin: string;\n sessionPublicKey: string;\n permissions: string[];\n expiresAt: number;\n createdAt: number;\n revoked: boolean;\n active: boolean;\n}\n\nexport interface CredentialMetadataRecord {\n credentialId: string;\n keyHash: string;\n displayName: string;\n platformHint: string;\n backupEligible: boolean | null;\n backupState: boolean | null;\n isRoot: boolean;\n status: 'active' | 'revoked';\n lastUsedAt: number | null;\n useCount: number;\n createdAt: number;\n updatedAt: number;\n}\n\n// ============================================================================\n// Default Configuration\n// ============================================================================\n\nconst DEFAULT_CONFIG: Required<Omit<RelayerClientConfig, 'baseUrl'>> = {\n apiKey: '',\n timeoutMs: 30_000,\n maxRetries: 3,\n};\n\n// ============================================================================\n// RelayerClient Class\n// ============================================================================\n\n/**\n * Client for the Veridex relayer service\n */\nexport class RelayerClient {\n private baseUrl: string;\n private config: Required<Omit<RelayerClientConfig, 'baseUrl'>>;\n\n constructor(config: RelayerClientConfig) {\n this.baseUrl = config.baseUrl.replace(/\\/+$/, ''); // Remove trailing slashes\n this.config = { ...DEFAULT_CONFIG, ...config };\n }\n\n // ========================================================================\n // Relay Operations\n // ========================================================================\n\n /**\n * Submit a VAA for relay to destination chain\n */\n async submitRelay(\n vaaBase64: string,\n sourceChain: number,\n destinationChain: number,\n sourceTxHash: string,\n sequence: bigint,\n feeQuoteId?: string\n ): Promise<RelayRequest> {\n void vaaBase64;\n void sourceChain;\n void destinationChain;\n void sourceTxHash;\n void sequence;\n void feeQuoteId;\n throw new Error(\n 'submitRelay() is not supported by the current Veridex relayer API. ' +\n 'Use submitSignedAction() and let the relayer observe hub events to relay automatically.'\n );\n }\n\n /**\n * Submit a signed action to the relayer for gasless execution\n * \n * This allows users to execute transfers without paying gas themselves.\n * The relayer will submit the transaction to the Hub chain and pay the gas.\n * The relayer then automatically relays the VAA to the destination spoke chain.\n * \n * @param request - The signed action request with passkey signature\n * @returns Result including Hub tx hash and Wormhole sequence\n */\n async submitSignedAction(request: SubmitSignedActionRequest): Promise<SubmitActionResult> {\n try {\n const response = await this.fetch('/api/v1/submit', {\n method: 'POST',\n body: JSON.stringify(request),\n });\n\n return {\n success: response.success,\n txHash: response.transactionHash ?? response.txHash,\n sequence: response.sequence,\n error: response.error,\n message: response.message,\n };\n } catch (err: any) {\n // Handle 400 errors gracefully - the relayer returns error details in the body\n if (err.status === 400 && err.body) {\n return {\n success: false,\n error: err.body.error ?? 'Relayer returned 400 Bad Request',\n message: err.body.message,\n };\n }\n // Re-throw other errors\n throw err;\n }\n }\n\n /**\n * Submit a Query-based transaction for optimistic execution (Issue #11/#12)\n * \n * Uses Wormhole Cross-Chain Queries (CCQ) to achieve ~5-7 second latency\n * vs ~120+ seconds for traditional VAA flow.\n * \n * Flow:\n * 1. Client fetches Hub state via queryHubState() from SDK\n * 2. Client constructs and signs transaction\n * 3. Client submits Query proof + tx to this endpoint\n * 4. Relayer validates format and submits to spoke chain\n * 5. Spoke chain verifies Guardian signatures on-chain\n * \n * @param request - Query submission with Guardian-signed proof\n * @returns Result including spoke tx hash and execution path\n */\n async submitQuery(request: SubmitQueryRequest): Promise<SubmitQueryResult> {\n try {\n const response = await this.fetch('/api/v1/submit-query', {\n method: 'POST',\n body: JSON.stringify(request),\n });\n\n return {\n success: response.success ?? false,\n txHash: response.txHash,\n path: response.path ?? 'query',\n latencyMs: response.latencyMs,\n error: response.error,\n fellBack: response.fellBack ?? false,\n };\n } catch (err: any) {\n // Handle errors gracefully\n if (err.status === 400 && err.body) {\n return {\n success: false,\n path: 'query',\n error: err.body.error ?? 'Relayer returned 400 Bad Request',\n };\n }\n throw err;\n }\n }\n\n /**\n * Get relay request status\n */\n async getRelayStatus(requestId: string): Promise<RelayRequest> {\n void requestId;\n throw new Error('getRelayStatus() is not supported by the current Veridex relayer API.');\n }\n\n /**\n * Get relay status by source transaction hash\n */\n async getRelayBySourceTx(sourceTxHash: string): Promise<RelayRequest | null> {\n void sourceTxHash;\n return null;\n }\n\n /**\n * Get relay status by sequence number\n */\n async getRelayBySequence(\n sourceChain: number,\n sequence: bigint\n ): Promise<RelayRequest | null> {\n void sourceChain;\n void sequence;\n return null;\n }\n\n /**\n * Cancel a pending relay request\n */\n async cancelRelay(requestId: string): Promise<boolean> {\n void requestId;\n return false;\n }\n\n /**\n * Poll for relay completion\n */\n async waitForRelay(\n requestId: string,\n timeoutMs: number = 120_000,\n pollingIntervalMs: number = 3_000,\n onProgress?: (status: RelayStatus) => void\n ): Promise<RelayRequest> {\n void requestId;\n void timeoutMs;\n void pollingIntervalMs;\n void onProgress;\n throw new Error('waitForRelay() is not supported by the current Veridex relayer API.');\n }\n\n // ========================================================================\n // Fee Estimation\n // ========================================================================\n\n /**\n * Get fee quote for a relay\n */\n async getFeeQuote(\n sourceChain: number,\n destinationChain: number,\n estimatedGas?: bigint\n ): Promise<RelayFeeQuote> {\n void sourceChain;\n void estimatedGas;\n\n // The relayer currently returns a simple fee breakdown; we map it into the\n // existing RelayFeeQuote shape with best-effort defaults.\n const response = await this.fetch(`/api/v1/fee?targetChain=${destinationChain}`);\n const relayerFee = BigInt(response?.fees?.relayer ?? '0');\n const total = BigInt(response?.fees?.total ?? relayerFee.toString());\n\n return {\n sourceChain: sourceChain,\n destinationChain,\n feeInSourceToken: total,\n feeInDestinationToken: relayerFee,\n estimatedGas: 0n,\n expiresAt: Date.now() + 60_000,\n quoteId: '',\n };\n }\n\n // ========================================================================\n // Service Info\n // ========================================================================\n\n /**\n * Get relayer service info\n */\n async getInfo(): Promise<RelayerInfo> {\n const response = await this.fetch('/api/v1/info');\n\n return {\n name: 'veridex-relayer',\n version: response?.relayer?.version ?? response?.version ?? 'unknown',\n supportedChains: (response?.supportedChains || []).map((c: any) => c.wormholeChainId ?? c),\n routes: [],\n online: true,\n queueDepth: 0,\n };\n }\n\n /**\n * Get supported routes\n */\n async getRoutes(): Promise<RelayRoute[]> {\n throw new Error('getRoutes() is not supported by the current Veridex relayer API.');\n }\n\n /**\n * Check if a route is supported\n */\n async isRouteSupported(\n sourceChain: number,\n destinationChain: number\n ): Promise<boolean> {\n void sourceChain;\n void destinationChain;\n return false;\n }\n\n /**\n * Check relayer health\n */\n async healthCheck(): Promise<boolean> {\n try {\n const response = await this.fetch('/health');\n return response.status === 'healthy' || response.status === 'degraded' || response.healthy === true;\n } catch {\n return false;\n }\n }\n\n // ========================================================================\n // Account And Control Plane\n // ========================================================================\n\n async listApps(): Promise<RegisteredAppSummary[]> {\n const response = await this.fetch('/api/v1/apps');\n return (response.apps ?? []) as RegisteredAppSummary[];\n }\n\n async getApp(appId: string): Promise<RegisteredAppDetail> {\n const response = await this.fetch(`/api/v1/apps/${encodeURIComponent(appId)}`);\n return response.app as RegisteredAppDetail;\n }\n\n async updateAppStatus(appId: string, status: RegisteredAppStatus): Promise<void> {\n await this.fetch(`/api/v1/apps/${encodeURIComponent(appId)}/status`, {\n method: 'PUT',\n body: JSON.stringify({ status }),\n });\n }\n\n async updateAppTrustLevel(appId: string, trustLevel: RegisteredAppTrustLevel): Promise<void> {\n await this.fetch(`/api/v1/apps/${encodeURIComponent(appId)}/trust-level`, {\n method: 'PUT',\n body: JSON.stringify({ trustLevel }),\n });\n }\n\n async listAppSessions(appId: string, options?: { includeRevoked?: boolean }): Promise<RelayerAppSession[]> {\n const query = options?.includeRevoked ? '?includeRevoked=true' : '';\n const response = await this.fetch(`/api/v1/apps/${encodeURIComponent(appId)}/sessions${query}`);\n return (response.sessions ?? []) as RelayerAppSession[];\n }\n\n async revokeAppSessions(appId: string, sessionId?: string): Promise<number> {\n const response = await this.fetch(`/api/v1/apps/${encodeURIComponent(appId)}/sessions/revoke`, {\n method: 'POST',\n body: JSON.stringify(sessionId ? { sessionId } : {}),\n });\n return Number(response.revokedCount ?? 0);\n }\n\n async listCredentialMetadata(keyHash: string): Promise<CredentialMetadataRecord[]> {\n const response = await this.fetch(`/api/v1/credential/metadata?keyHash=${encodeURIComponent(keyHash)}`);\n return (response.credentials ?? []) as CredentialMetadataRecord[];\n }\n\n // ========================================================================\n // Pending Relays\n // ========================================================================\n\n /**\n * Get all pending relay requests for a user\n */\n async getPendingRelays(userKeyHash: string): Promise<RelayRequest[]> {\n void userKeyHash;\n return [];\n }\n\n /**\n * Get relay history for a user\n */\n async getRelayHistory(\n userKeyHash: string,\n limit: number = 50,\n offset: number = 0\n ): Promise<RelayRequest[]> {\n void userKeyHash;\n void limit;\n void offset;\n return [];\n }\n\n // ========================================================================\n // Internal Helpers\n // ========================================================================\n\n /**\n * SDK version for telemetry\n */\n private static readonly SDK_VERSION = '1.0.0-beta.1';\n\n /**\n * Make an HTTP request to the relayer\n */\n private async fetch(\n path: string,\n options: RequestInit = {}\n ): Promise<any> {\n const headers: HeadersInit = {\n 'Content-Type': 'application/json',\n 'User-Agent': `@veridex/sdk/${RelayerClient.SDK_VERSION}`,\n ...(options.headers || {}),\n };\n\n if (this.config.apiKey) {\n (headers as Record<string, string>)['X-API-Key'] = this.config.apiKey;\n }\n\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), this.config.timeoutMs);\n\n let lastError: Error | null = null;\n\n for (let attempt = 0; attempt <= this.config.maxRetries; attempt++) {\n try {\n const response = await fetch(`${this.baseUrl}${path}`, {\n ...options,\n headers,\n signal: controller.signal,\n });\n\n clearTimeout(timeout);\n\n if (!response.ok) {\n const error: any = new Error(\n `Relayer request failed: ${response.status} ${response.statusText}`\n );\n error.status = response.status;\n try {\n error.body = await response.json();\n } catch {\n // Ignore JSON parse errors\n }\n throw error;\n }\n\n return await response.json();\n } catch (error: any) {\n lastError = error;\n\n // Don't retry on client errors (4xx)\n if (error.status && error.status >= 400 && error.status < 500) {\n throw error;\n }\n\n // Don't retry on abort\n if (error.name === 'AbortError') {\n throw new Error('Request timeout');\n }\n\n // Wait before retry\n if (attempt < this.config.maxRetries) {\n await this.sleep(1000 * (attempt + 1));\n }\n }\n }\n\n throw lastError || new Error('Request failed after all retries');\n }\n\n /**\n * Sleep helper\n */\n private sleep(ms: number): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, ms));\n }\n}\n\n// ============================================================================\n// Factory function\n// ============================================================================\n\n/**\n * Create a RelayerClient instance\n */\nexport function createRelayerClient(config: RelayerClientConfig): RelayerClient {\n return new RelayerClient(config);\n}\n","/**\n * Veridex Protocol SDK - Chain Detector\n *\n * Phase 4: Multi-chain client support helper.\n *\n * Provides:\n * - Chain config lookup (testnet/mainnet)\n * - Auto-configuration for non-EVM ChainClient instances\n */\n\nimport type { ChainClient, ChainConfig, PasskeyCredential, ChainAddress } from './types.js';\nimport { TESTNET_CHAINS, MAINNET_CHAINS } from '../constants.js';\nimport { WalletManager } from './WalletManager.js';\nimport { SolanaClient } from '../chains/solana/SolanaClient.js';\nimport { AptosClient } from '../chains/aptos/AptosClient.js';\nimport { SuiClient } from '../chains/sui/SuiClient.js';\nimport { StarknetClient } from '../chains/starknet/StarknetClient.js';\n\nexport interface ChainDetectorConfig {\n testnet?: boolean;\n rpcUrls?: Record<number, string>;\n}\n\nexport interface NativeBalanceCapable {\n getNativeBalance(address: string): Promise<bigint>;\n}\n\nconst NON_EVM_NATIVE_META: Record<number, { symbol: string; name: string; decimals: number }> = {\n 1: { symbol: 'SOL', name: 'Solana', decimals: 9 },\n 21: { symbol: 'SUI', name: 'Sui', decimals: 9 },\n 22: { symbol: 'APT', name: 'Aptos', decimals: 8 },\n};\n\nexport class ChainDetector {\n private readonly testnet: boolean;\n private readonly rpcUrls: Record<number, string>;\n private readonly walletManager: WalletManager;\n\n constructor(config: ChainDetectorConfig = {}) {\n this.testnet = config.testnet ?? true;\n this.rpcUrls = config.rpcUrls ?? {};\n this.walletManager = new WalletManager({ cacheAddresses: true, persistToStorage: false });\n }\n\n getChainConfig(wormholeChainId: number): ChainConfig | undefined {\n const chains = this.testnet ? TESTNET_CHAINS : MAINNET_CHAINS;\n return Object.values(chains).find(c => c.wormholeChainId === wormholeChainId);\n }\n\n /**\n * Create a chain client for non-EVM chains using repo constants.\n * For EVM, callers should instantiate EVMClient directly (Hub-driven).\n */\n createClient(wormholeChainId: number): ChainClient {\n const chain = this.getChainConfig(wormholeChainId);\n if (!chain) {\n throw new Error(`Unknown chain (wormholeChainId=${wormholeChainId})`);\n }\n\n const rpcUrl = this.rpcUrls[wormholeChainId] ?? chain.rpcUrl;\n\n if (chain.isEvm) {\n throw new Error(\n `EVM chain auto-detection is not supported here (wormholeChainId=${wormholeChainId}). ` +\n 'Instantiate EVMClient with hubContractAddress/vaultFactory/vaultImplementation explicitly.'\n );\n }\n\n switch (wormholeChainId) {\n case 1: {\n const programId = chain.contracts.hub;\n if (!programId || !chain.contracts.tokenBridge) {\n throw new Error('Solana config missing programId/tokenBridge in constants');\n }\n return new SolanaClient({\n wormholeChainId,\n rpcUrl,\n programId,\n wormholeCoreBridge: chain.contracts.wormholeCoreBridge,\n tokenBridge: chain.contracts.tokenBridge,\n network: this.testnet ? 'devnet' : 'mainnet',\n });\n }\n case 22: {\n const moduleAddress = chain.contracts.hub;\n if (!moduleAddress || !chain.contracts.tokenBridge) {\n throw new Error('Aptos config missing moduleAddress/tokenBridge in constants');\n }\n return new AptosClient({\n wormholeChainId,\n rpcUrl,\n moduleAddress,\n wormholeCoreBridge: chain.contracts.wormholeCoreBridge,\n tokenBridge: chain.contracts.tokenBridge,\n network: this.testnet ? 'testnet' : 'mainnet',\n });\n }\n case 21: {\n const packageId = chain.contracts.hub;\n return new SuiClient({\n wormholeChainId,\n rpcUrl,\n packageId: packageId ?? '',\n wormholeCoreBridge: chain.contracts.wormholeCoreBridge,\n tokenBridge: chain.contracts.tokenBridge,\n network: this.testnet ? 'testnet' : 'mainnet',\n });\n }\n case 50001: {\n // Starknet Sepolia with custom bridge\n const spokeAddress = chain.contracts.hub;\n const bridgeAddress = chain.contracts.wormholeCoreBridge;\n if (!spokeAddress || !bridgeAddress) {\n throw new Error('Starknet config missing spoke/bridge addresses in constants');\n }\n return new StarknetClient({\n wormholeChainId,\n rpcUrl,\n spokeContractAddress: spokeAddress,\n bridgeContractAddress: bridgeAddress,\n network: this.testnet ? 'sepolia' : 'mainnet',\n });\n }\n default:\n throw new Error(\n `Unsupported non-EVM chain (wormholeChainId=${wormholeChainId}). ` +\n 'Add configuration in ChainDetector.createClient().'\n );\n }\n }\n\n /**\n * Derive a best-effort vault address for a chain from the passkey credential.\n *\n * - EVM chains: requires vaultFactory/vaultImplementation in constants.\n * - Non-EVM chains: uses WalletManager chain-specific derivation.\n */\n deriveVaultAddress(credential: PasskeyCredential, wormholeChainId: number): ChainAddress | null {\n const chain = this.getChainConfig(wormholeChainId);\n if (!chain) {\n return null;\n }\n\n if (chain.isEvm) {\n const factory = chain.contracts.vaultFactory;\n const implementation = chain.contracts.vaultImplementation;\n if (!factory || !implementation) {\n return null;\n }\n\n const address = this.walletManager.computeVaultAddress(credential.keyHash, factory, implementation);\n return {\n wormholeChainId,\n chainName: chain.name,\n address,\n isEvm: true,\n deployed: false,\n derivationType: 'create2',\n };\n }\n\n // Non-EVM: WalletManager derives using keyHash conventions.\n return {\n wormholeChainId,\n chainName: chain.name,\n address: wormholeChainId === 21 \n ? this.normalizeSuiAddress(credential.keyHash)\n : wormholeChainId === 50001\n ? credential.keyHash // Starknet uses keyHash directly (felt252)\n : credential.keyHash,\n isEvm: false,\n deployed: false,\n derivationType: wormholeChainId === 1 \n ? 'pda' \n : wormholeChainId === 22 \n ? 'resource_account' \n : wormholeChainId === 50001\n ? 'keyHash'\n : 'object',\n };\n }\n\n getNonEvmNativeTokenMeta(wormholeChainId: number): { symbol: string; name: string; decimals: number } | null {\n return NON_EVM_NATIVE_META[wormholeChainId] ?? null;\n }\n\n private normalizeSuiAddress(value: string): string {\n const clean = value.replace(/^0x/, '').padStart(64, '0');\n return '0x' + clean;\n }\n}\n\nexport function createChainDetector(config: ChainDetectorConfig = {}): ChainDetector {\n return new ChainDetector(config);\n}\n","/**\n * Veridex Protocol SDK - Transaction Parser\n * \n * Parses transaction payloads into human-readable summaries (Issue #26)\n * \n * Security-critical: This module MUST accurately represent what users are signing.\n * Any mismatch between displayed information and actual transaction is a security vulnerability.\n */\n\nimport { ethers } from 'ethers';\nimport {\n ACTION_TRANSFER,\n ACTION_EXECUTE,\n ACTION_CONFIG,\n ACTION_BRIDGE,\n} from '../constants.js';\nimport {\n decodeTransferAction,\n decodeBridgeAction,\n} from '../payload.js';\nimport type { PreparedTransfer, PreparedBridge } from './types.js';\nimport type { BridgeParams, TransferParams } from '../types.js';\nimport type {\n TransactionSummary,\n TransactionParserConfig,\n TokenDisplay,\n RecipientDisplay,\n ChainDisplay,\n RiskWarning,\n TransferDetails,\n BridgeDetails,\n ExecuteDetails,\n ConfigDetails,\n TokenInfo,\n} from './TransactionSummary.types.js';\nimport { getChainDisplay, getConfigTypeName } from './TransactionSummary.types.js';\n\n// ============================================================================\n// Default Token Registry\n// ============================================================================\n\nconst DEFAULT_TOKENS: Map<string, TokenInfo> = new Map([\n // Native token placeholder\n ['0x0000000000000000000000000000000000000000', {\n symbol: 'ETH',\n name: 'Ether',\n decimals: 18,\n verified: true,\n }],\n ['native', {\n symbol: 'ETH',\n name: 'Ether',\n decimals: 18,\n verified: true,\n }],\n // Common stablecoins (Base Sepolia)\n ['0x036cbd53842c5426634e7929541ec2318f3dcf7e', {\n symbol: 'USDC',\n name: 'USD Coin',\n decimals: 6,\n verified: true,\n }],\n]);\n\n// ============================================================================\n// Utility Functions\n// ============================================================================\n\n/**\n * Format a bigint amount to human-readable string\n */\nexport function formatAmount(amount: bigint, decimals: number): string {\n if (amount === 0n) return '0';\n \n const divisor = 10n ** BigInt(decimals);\n const whole = amount / divisor;\n const remainder = amount % divisor;\n \n if (remainder === 0n) {\n return whole.toString();\n }\n \n // Format with decimal places\n const remainderStr = remainder.toString().padStart(decimals, '0');\n // Trim trailing zeros\n const trimmed = remainderStr.replace(/0+$/, '');\n \n return `${whole}.${trimmed}`;\n}\n\n/**\n * Truncate an address for display\n */\nexport function truncateAddress(address: string, startChars = 6, endChars = 4): string {\n if (address.length <= startChars + endChars + 3) {\n return address;\n }\n return `${address.slice(0, startChars)}...${address.slice(-endChars)}`;\n}\n\n/**\n * Format time remaining until expiration\n */\nexport function formatTimeRemaining(expiresAt: number): string {\n const now = Date.now();\n const remaining = expiresAt - now;\n \n if (remaining <= 0) return 'Expired';\n \n const seconds = Math.floor(remaining / 1000);\n if (seconds < 60) return `${seconds} seconds`;\n \n const minutes = Math.floor(seconds / 60);\n if (minutes < 60) return `${minutes} minute${minutes === 1 ? '' : 's'}`;\n \n const hours = Math.floor(minutes / 60);\n return `${hours} hour${hours === 1 ? '' : 's'}`;\n}\n\n/**\n * Check if address is the zero address (native token)\n */\nexport function isNativeToken(address: string): boolean {\n return address === '0x0000000000000000000000000000000000000000' ||\n address === 'native' ||\n address === ethers.ZeroAddress;\n}\n\n// ============================================================================\n// Transaction Parser Class\n// ============================================================================\n\n/**\n * Parses prepared transactions into human-readable summaries\n */\nexport class TransactionParser {\n private config: TransactionParserConfig;\n private tokenRegistry: Map<string, TokenInfo>;\n\n constructor(config: TransactionParserConfig = {}) {\n this.config = config;\n this.tokenRegistry = config.knownTokens ?? new Map(DEFAULT_TOKENS);\n }\n\n /**\n * Main entry point: parse a prepared transfer into a human-readable summary\n * \n * This method determines the action type from the payload and delegates\n * to the appropriate specialized parser.\n * \n * @param prepared - PreparedTransfer or PreparedBridge object from SDK\n * @param vaultAddress - Optional vault address (uses default if not provided)\n * @param vaultChainId - Optional vault chain ID (uses config default if not provided)\n */\n async parse(\n prepared: PreparedTransfer | PreparedBridge,\n vaultAddress?: string,\n vaultChainId?: number\n ): Promise<TransactionSummary> {\n const effectiveVaultAddress = vaultAddress ?? '0x0000000000000000000000000000000000000000';\n \n // Determine chain ID based on type - PreparedBridge uses destinationChain, PreparedTransfer uses params.targetChain\n const isBridgePrepared = 'destinationChain' in prepared;\n const defaultChainId = isBridgePrepared \n ? (prepared as PreparedBridge).destinationChain \n : (prepared as PreparedTransfer).params.targetChain;\n const effectiveChainId = vaultChainId ?? this.config.defaultChainId ?? defaultChainId;\n \n // Normalize to PreparedTransfer with defaults for missing fields\n // For PreparedBridge, we construct params from the bridge-specific fields\n const normalizedParams: TransferParams = isBridgePrepared \n ? {\n targetChain: (prepared as PreparedBridge).destinationChain,\n token: (prepared as PreparedBridge).params.token,\n recipient: (prepared as PreparedBridge).params.recipient,\n amount: (prepared as PreparedBridge).params.amount,\n }\n : (prepared as PreparedTransfer).params;\n\n const normalized: PreparedTransfer = {\n params: normalizedParams,\n actionPayload: prepared.actionPayload,\n nonce: prepared.nonce,\n challenge: prepared.challenge,\n estimatedGas: (prepared as PreparedTransfer).estimatedGas ?? 0n,\n gasPrice: (prepared as PreparedTransfer).gasPrice ?? 0n,\n messageFee: (prepared as PreparedTransfer).messageFee ?? (isBridgePrepared ? (prepared as PreparedBridge).fees?.relayerFee ?? 0n : 0n),\n totalCost: (prepared as PreparedTransfer).totalCost ?? 0n,\n formattedCost: (prepared as PreparedTransfer).formattedCost ?? '0',\n preparedAt: prepared.preparedAt ?? Date.now(),\n expiresAt: prepared.expiresAt,\n };\n\n // Determine action type from payload\n const actionType = this.detectActionType(normalized.actionPayload);\n\n switch (actionType) {\n case ACTION_TRANSFER:\n return this.parseTransfer(normalized, effectiveVaultAddress, effectiveChainId);\n case ACTION_BRIDGE:\n return this.parseBridgeFromPrepared(normalized, effectiveVaultAddress, effectiveChainId);\n case ACTION_EXECUTE:\n return this.parseExecuteFromPayload(\n normalized.actionPayload,\n normalized.nonce,\n normalized.challenge,\n effectiveVaultAddress,\n effectiveChainId,\n normalized.expiresAt,\n normalized.formattedCost\n );\n case ACTION_CONFIG:\n return this.parseConfigFromPayload(\n normalized.actionPayload,\n normalized.nonce,\n normalized.challenge,\n effectiveVaultAddress,\n effectiveChainId,\n normalized.expiresAt,\n normalized.formattedCost\n );\n default:\n // Fallback for unknown action types\n return this.createUnknownActionSummary(normalized, effectiveVaultAddress, effectiveChainId);\n }\n }\n\n /**\n * Detect action type from payload\n */\n private detectActionType(payload: string): number {\n if (!payload || payload.length < 4) return 0;\n // Action type is typically first byte after 0x\n const typeHex = payload.slice(2, 4);\n return parseInt(typeHex, 16);\n }\n\n /**\n * Parse bridge action from PreparedTransfer\n */\n private async parseBridgeFromPrepared(\n prepared: PreparedTransfer,\n vaultAddress: string,\n vaultChainId: number\n ): Promise<TransactionSummary> {\n const { params, actionPayload, nonce, challenge, expiresAt, formattedCost } = prepared;\n const decoded = decodeBridgeAction(actionPayload);\n\n const token = await this.resolveToken(decoded.token, decoded.amount);\n const sourceChain = getChainDisplay(vaultChainId);\n const destinationChain = getChainDisplay(params.targetChain);\n const recipient = await this.resolveRecipient(decoded.recipient);\n\n const details: BridgeDetails = {\n token,\n sourceChain,\n destinationChain,\n recipient,\n estimatedTime: this.estimateBridgeTime(sourceChain.id, destinationChain.id),\n };\n\n const warnings = await this.assessBridgeRisks({\n sourceChain: vaultChainId,\n destinationChain: params.targetChain,\n token: decoded.token,\n recipient: decoded.recipient,\n amount: decoded.amount,\n }, token, sourceChain, destinationChain);\n\n return {\n action: 'bridge',\n title: `Bridge ${token.symbol}`,\n description: `Bridge ${token.amount} ${token.symbol} from ${sourceChain.name} to ${destinationChain.name}`,\n details,\n vault: {\n address: vaultAddress,\n truncated: truncateAddress(vaultAddress),\n chain: sourceChain,\n },\n fee: {\n gas: formattedCost,\n paidByRelayer: false,\n total: formattedCost,\n },\n warnings,\n raw: {\n actionType: ACTION_BRIDGE,\n actionPayload,\n nonce,\n challenge: ethers.hexlify(challenge),\n chainId: params.targetChain,\n expiresAt,\n expiresIn: formatTimeRemaining(expiresAt),\n },\n generatedAt: Date.now(),\n };\n }\n\n /**\n * Parse execute action from payload\n */\n private async parseExecuteFromPayload(\n actionPayload: string,\n nonce: bigint,\n challenge: Uint8Array,\n vaultAddress: string,\n chainId: number,\n expiresAt: number,\n formattedCost: string\n ): Promise<TransactionSummary> {\n // Decode execute action - basic structure\n const target = '0x' + actionPayload.slice(4, 44);\n const value = BigInt('0x' + actionPayload.slice(44, 108));\n const calldata = '0x' + actionPayload.slice(108);\n\n const targetDisplay = await this.resolveRecipient(target);\n const chain = getChainDisplay(chainId);\n const functionInfo = this.decodeFunctionCall(calldata);\n\n const details: ExecuteDetails = {\n target: targetDisplay,\n value: await this.resolveToken(ethers.ZeroAddress, value),\n chain,\n functionName: functionInfo?.name,\n decodedArgs: functionInfo?.args,\n calldata,\n };\n\n const warnings = await this.assessExecuteRisks(target, value, calldata, targetDisplay);\n\n return {\n action: 'execute',\n title: 'Contract Call',\n description: `Call ${functionInfo?.name ?? 'function'} on ${targetDisplay.ens ?? targetDisplay.truncated}`,\n details,\n vault: {\n address: vaultAddress,\n truncated: truncateAddress(vaultAddress),\n chain,\n },\n fee: {\n gas: formattedCost,\n paidByRelayer: false,\n total: formattedCost,\n },\n warnings,\n raw: {\n actionType: ACTION_EXECUTE,\n actionPayload,\n nonce,\n challenge: ethers.hexlify(challenge),\n chainId,\n expiresAt,\n expiresIn: formatTimeRemaining(expiresAt),\n },\n generatedAt: Date.now(),\n };\n }\n\n /**\n * Parse config action from payload\n */\n private async parseConfigFromPayload(\n actionPayload: string,\n nonce: bigint,\n challenge: Uint8Array,\n vaultAddress: string,\n chainId: number,\n expiresAt: number,\n formattedCost: string\n ): Promise<TransactionSummary> {\n // Decode config action - basic structure\n const configType = parseInt(actionPayload.slice(2, 4), 16);\n const configData = '0x' + actionPayload.slice(4);\n\n const chain = getChainDisplay(chainId);\n const configTypeName = getConfigTypeName(configType);\n\n const details: ConfigDetails = {\n configType,\n configTypeName,\n description: this.describeConfigChange(configType, configData),\n changes: this.parseConfigChanges(configType, configData),\n };\n\n const warnings: RiskWarning[] = [{\n level: 'high',\n type: 'config_change',\n message: 'This transaction will modify your vault settings',\n details: `Changing: ${configTypeName}`,\n }];\n\n return {\n action: 'config',\n title: 'Configuration Change',\n description: `Update vault configuration: ${configTypeName}`,\n details,\n vault: {\n address: vaultAddress,\n truncated: truncateAddress(vaultAddress),\n chain,\n },\n fee: {\n gas: formattedCost,\n paidByRelayer: false,\n total: formattedCost,\n },\n warnings,\n raw: {\n actionType: ACTION_CONFIG,\n actionPayload,\n nonce,\n challenge: ethers.hexlify(challenge),\n chainId,\n expiresAt,\n expiresIn: formatTimeRemaining(expiresAt),\n },\n generatedAt: Date.now(),\n };\n }\n\n /**\n * Create a fallback summary for unknown action types\n */\n private createUnknownActionSummary(\n prepared: PreparedTransfer,\n vaultAddress: string,\n chainId: number\n ): TransactionSummary {\n const chain = getChainDisplay(chainId);\n\n return {\n action: 'execute',\n title: 'Unknown Action',\n description: 'This transaction contains an unrecognized action type',\n details: null,\n vault: {\n address: vaultAddress,\n truncated: truncateAddress(vaultAddress),\n chain,\n },\n fee: {\n gas: prepared.formattedCost,\n paidByRelayer: false,\n total: prepared.formattedCost,\n },\n warnings: [{\n level: 'critical',\n type: 'unknown_token',\n message: 'Unknown action type - proceed with extreme caution',\n details: `Action type: ${this.detectActionType(prepared.actionPayload)}`,\n }],\n raw: {\n actionType: this.detectActionType(prepared.actionPayload),\n actionPayload: prepared.actionPayload,\n nonce: prepared.nonce,\n challenge: ethers.hexlify(prepared.challenge),\n chainId,\n expiresAt: prepared.expiresAt,\n expiresIn: formatTimeRemaining(prepared.expiresAt),\n },\n generatedAt: Date.now(),\n };\n }\n\n /**\n * Parse a prepared transfer into a human-readable summary\n */\n async parseTransfer(\n prepared: PreparedTransfer,\n vaultAddress: string,\n vaultChainId: number\n ): Promise<TransactionSummary> {\n const { params, actionPayload, nonce, challenge, expiresAt } = prepared;\n const decoded = decodeTransferAction(actionPayload);\n\n const token = await this.resolveToken(decoded.token, decoded.amount);\n const recipient = await this.resolveRecipient(decoded.recipient);\n const chain = getChainDisplay(params.targetChain);\n\n const details: TransferDetails = {\n token,\n recipient,\n chain,\n };\n\n const warnings = await this.assessTransferRisks(params, token, recipient);\n\n return {\n action: 'transfer',\n title: `Send ${token.symbol}`,\n description: `Send ${token.amount} ${token.symbol} to ${recipient.ens ?? recipient.truncated}`,\n details,\n vault: {\n address: vaultAddress,\n truncated: truncateAddress(vaultAddress),\n chain: getChainDisplay(vaultChainId),\n },\n fee: {\n gas: prepared.formattedCost,\n paidByRelayer: false, // Will be updated by caller if gasless\n total: prepared.formattedCost,\n },\n warnings,\n raw: {\n actionType: ACTION_TRANSFER,\n actionPayload,\n nonce,\n challenge: ethers.hexlify(challenge),\n chainId: params.targetChain,\n expiresAt,\n expiresIn: formatTimeRemaining(expiresAt),\n },\n generatedAt: Date.now(),\n };\n }\n\n /**\n * Parse a bridge operation into a human-readable summary\n */\n async parseBridge(\n params: BridgeParams,\n actionPayload: string,\n nonce: bigint,\n challenge: Uint8Array,\n vaultAddress: string,\n vaultChainId: number,\n expiresAt: number,\n formattedCost: string\n ): Promise<TransactionSummary> {\n const decoded = decodeBridgeAction(actionPayload);\n\n const token = await this.resolveToken(decoded.token, decoded.amount);\n const sourceChain = getChainDisplay(params.sourceChain);\n const destinationChain = getChainDisplay(params.destinationChain);\n const recipient = await this.resolveRecipient(decoded.recipient);\n\n const details: BridgeDetails = {\n token,\n sourceChain,\n destinationChain,\n recipient,\n estimatedTime: this.estimateBridgeTime(sourceChain.id, destinationChain.id),\n };\n\n const warnings = await this.assessBridgeRisks(params, token, sourceChain, destinationChain);\n\n return {\n action: 'bridge',\n title: `Bridge ${token.symbol}`,\n description: `Bridge ${token.amount} ${token.symbol} from ${sourceChain.name} to ${destinationChain.name}`,\n details,\n vault: {\n address: vaultAddress,\n truncated: truncateAddress(vaultAddress),\n chain: getChainDisplay(vaultChainId),\n },\n fee: {\n gas: formattedCost,\n paidByRelayer: false,\n total: formattedCost,\n },\n warnings,\n raw: {\n actionType: ACTION_BRIDGE,\n actionPayload,\n nonce,\n challenge: ethers.hexlify(challenge),\n chainId: params.sourceChain,\n expiresAt,\n expiresIn: formatTimeRemaining(expiresAt),\n },\n generatedAt: Date.now(),\n };\n }\n\n /**\n * Parse an execute (contract call) operation into a human-readable summary\n */\n async parseExecute(\n target: string,\n value: bigint,\n calldata: string,\n chainId: number,\n nonce: bigint,\n challenge: Uint8Array,\n vaultAddress: string,\n expiresAt: number,\n formattedCost: string\n ): Promise<TransactionSummary> {\n const targetRecipient = await this.resolveRecipient(target);\n const chain = getChainDisplay(chainId);\n const valueToken = await this.resolveToken(ethers.ZeroAddress, value);\n\n // Try to decode function signature\n const functionInfo = this.decodeFunctionCall(calldata);\n\n const details: ExecuteDetails = {\n target: targetRecipient,\n value: valueToken,\n chain,\n functionName: functionInfo?.name,\n decodedArgs: functionInfo?.args,\n calldata,\n };\n\n const warnings = await this.assessExecuteRisks(target, value, calldata, targetRecipient);\n\n const title = functionInfo?.name\n ? `Call ${functionInfo.name}`\n : 'Contract Interaction';\n\n return {\n action: 'execute',\n title,\n description: `Execute contract call on ${targetRecipient.ens ?? targetRecipient.truncated}`,\n details,\n vault: {\n address: vaultAddress,\n truncated: truncateAddress(vaultAddress),\n chain,\n },\n fee: {\n gas: formattedCost,\n paidByRelayer: false,\n total: formattedCost,\n },\n warnings,\n raw: {\n actionType: ACTION_EXECUTE,\n actionPayload: calldata,\n nonce,\n challenge: ethers.hexlify(challenge),\n chainId,\n expiresAt,\n expiresIn: formatTimeRemaining(expiresAt),\n },\n generatedAt: Date.now(),\n };\n }\n\n /**\n * Parse a config change operation\n */\n async parseConfig(\n configType: number,\n configData: string,\n chainId: number,\n nonce: bigint,\n challenge: Uint8Array,\n vaultAddress: string,\n expiresAt: number,\n formattedCost: string\n ): Promise<TransactionSummary> {\n const chain = getChainDisplay(chainId);\n const configTypeName = getConfigTypeName(configType);\n\n const details: ConfigDetails = {\n configType,\n configTypeName,\n description: this.describeConfigChange(configType, configData),\n changes: this.parseConfigChanges(configType, configData),\n };\n\n const warnings: RiskWarning[] = [{\n level: 'warning',\n type: 'config_change',\n message: 'This transaction will modify your vault settings',\n }];\n\n return {\n action: 'config',\n title: configTypeName,\n description: `Update vault configuration: ${configTypeName}`,\n details,\n vault: {\n address: vaultAddress,\n truncated: truncateAddress(vaultAddress),\n chain,\n },\n fee: {\n gas: formattedCost,\n paidByRelayer: false,\n total: formattedCost,\n },\n warnings,\n raw: {\n actionType: ACTION_CONFIG,\n actionPayload: configData,\n nonce,\n challenge: ethers.hexlify(challenge),\n chainId,\n expiresAt,\n expiresIn: formatTimeRemaining(expiresAt),\n },\n generatedAt: Date.now(),\n };\n }\n\n // ============================================================================\n // Resolution Methods\n // ============================================================================\n\n /**\n * Resolve token address to display info\n */\n private async resolveToken(address: string, amount: bigint): Promise<TokenDisplay> {\n const normalizedAddress = address.toLowerCase();\n const isNative = isNativeToken(address);\n\n // Check registry\n let tokenInfo = this.tokenRegistry.get(normalizedAddress);\n if (!tokenInfo && isNative) {\n tokenInfo = this.tokenRegistry.get('native');\n }\n\n const decimals = tokenInfo?.decimals ?? 18;\n const symbol = tokenInfo?.symbol ?? (isNative ? 'ETH' : 'UNKNOWN');\n const formattedAmount = formatAmount(amount, decimals);\n\n // Try to get USD value\n let usdValue: string | undefined;\n if (this.config.priceOracle) {\n try {\n const price = await this.config.priceOracle(address);\n if (price !== null) {\n const amountNum = parseFloat(formattedAmount);\n usdValue = `$${(amountNum * price).toFixed(2)}`;\n }\n } catch {\n // Price oracle failed, continue without USD value\n }\n }\n\n return {\n symbol,\n amount: formattedAmount,\n rawAmount: amount,\n address: isNative ? ethers.ZeroAddress : address,\n decimals,\n usdValue,\n isNative,\n };\n }\n\n /**\n * Resolve recipient address to display info\n */\n private async resolveRecipient(address: string): Promise<RecipientDisplay> {\n const truncated = truncateAddress(address);\n let ens: string | undefined;\n let isContract: boolean | undefined;\n let isNewRecipient: boolean | undefined;\n let label: string | undefined;\n\n // Check known recipients\n if (this.config.knownRecipients) {\n label = this.config.knownRecipients.get(address.toLowerCase());\n }\n\n // Try ENS resolution\n if (this.config.ensResolver) {\n try {\n const resolved = await this.config.ensResolver(address);\n if (resolved) {\n ens = resolved;\n }\n } catch {\n // ENS resolution failed, continue without\n }\n }\n\n // Check if contract\n if (this.config.contractDetector) {\n try {\n isContract = await this.config.contractDetector(address);\n } catch {\n // Contract detection failed\n }\n }\n\n // Check transaction history\n if (this.config.transactionHistory) {\n isNewRecipient = !this.config.transactionHistory.has(address.toLowerCase());\n }\n\n return {\n address,\n ens,\n truncated,\n isContract,\n isNewRecipient,\n label,\n };\n }\n\n // ============================================================================\n // Risk Assessment Methods\n // ============================================================================\n\n /**\n * Assess risks for a transfer transaction\n */\n private async assessTransferRisks(\n _params: TransferParams,\n token: TokenDisplay,\n recipient: RecipientDisplay\n ): Promise<RiskWarning[]> {\n const warnings: RiskWarning[] = [];\n\n // New recipient warning\n if (recipient.isNewRecipient) {\n warnings.push({\n level: 'warning',\n type: 'new_recipient',\n message: \"You've never sent to this address before\",\n details: 'Double-check the recipient address is correct',\n });\n }\n\n // Large transaction warning\n if (this.config.averageTransactionValue) {\n const threshold = this.config.averageTransactionValue * 10n; // 10x average\n if (token.rawAmount > threshold) {\n warnings.push({\n level: 'warning',\n type: 'large_transaction',\n message: 'This transaction is larger than your usual activity',\n details: `Amount: ${token.amount} ${token.symbol}`,\n });\n }\n }\n\n // Contract interaction warning\n if (recipient.isContract) {\n warnings.push({\n level: 'info',\n type: 'contract_interaction',\n message: 'Recipient is a smart contract',\n });\n }\n\n // Unknown token warning\n const tokenInfo = this.tokenRegistry.get(token.address.toLowerCase());\n if (!tokenInfo?.verified) {\n warnings.push({\n level: 'warning',\n type: 'unknown_token',\n message: 'This token is not in our verified list',\n details: 'Verify the token address is correct',\n });\n }\n\n return warnings;\n }\n\n /**\n * Assess risks for a bridge transaction\n */\n private async assessBridgeRisks(\n _params: BridgeParams,\n token: TokenDisplay,\n sourceChain: ChainDisplay,\n destinationChain: ChainDisplay\n ): Promise<RiskWarning[]> {\n const warnings: RiskWarning[] = [];\n\n // Cross-chain operation info\n warnings.push({\n level: 'info',\n type: 'cross_chain',\n message: `This is a cross-chain transfer from ${sourceChain.name} to ${destinationChain.name}`,\n details: 'Funds will be locked on the source chain and released on the destination',\n });\n\n // Large transaction warning\n if (this.config.averageTransactionValue) {\n const threshold = this.config.averageTransactionValue * 10n;\n if (token.rawAmount > threshold) {\n warnings.push({\n level: 'warning',\n type: 'large_transaction',\n message: 'This transaction is larger than your usual activity',\n });\n }\n }\n\n return warnings;\n }\n\n /**\n * Assess risks for an execute transaction\n */\n private async assessExecuteRisks(\n _target: string,\n value: bigint,\n _calldata: string,\n recipient: RecipientDisplay\n ): Promise<RiskWarning[]> {\n const warnings: RiskWarning[] = [];\n\n // Contract interaction is inherently risky\n warnings.push({\n level: 'warning',\n type: 'contract_interaction',\n message: 'This transaction calls an external contract',\n details: 'Review the contract and function being called',\n });\n\n // New recipient warning\n if (recipient.isNewRecipient) {\n warnings.push({\n level: 'warning',\n type: 'new_recipient',\n message: \"You've never interacted with this contract before\",\n });\n }\n\n // Value transfer with contract call\n if (value > 0n) {\n warnings.push({\n level: 'info',\n type: 'large_transaction',\n message: `This transaction sends ${formatAmount(value, 18)} ETH along with the contract call`,\n });\n }\n\n return warnings;\n }\n\n // ============================================================================\n // Helper Methods\n // ============================================================================\n\n /**\n * Estimate bridge completion time\n */\n private estimateBridgeTime(_sourceChain: number, _destChain: number): string {\n // Wormhole typically takes 2-15 minutes depending on chains\n // Query-based is faster (~5-7 seconds), VAA-based is slower (~2+ minutes)\n return '~2-5 minutes';\n }\n\n /**\n * Try to decode a function call from calldata\n */\n private decodeFunctionCall(calldata: string): { name: string; args: Record<string, unknown> } | null {\n if (calldata.length < 10) return null;\n\n // Common function selectors\n const KNOWN_SELECTORS: Record<string, string> = {\n '0xa9059cbb': 'transfer',\n '0x23b872dd': 'transferFrom',\n '0x095ea7b3': 'approve',\n '0x70a08231': 'balanceOf',\n '0x18160ddd': 'totalSupply',\n '0x313ce567': 'decimals',\n '0x06fdde03': 'name',\n '0x95d89b41': 'symbol',\n };\n\n const selector = calldata.slice(0, 10).toLowerCase();\n const name = KNOWN_SELECTORS[selector];\n\n if (name) {\n return { name, args: {} }; // Would need ABI to decode args\n }\n\n return null;\n }\n\n /**\n * Describe a config change in human-readable terms\n */\n private describeConfigChange(configType: number, _configData: string): string {\n const name = getConfigTypeName(configType);\n return `This will update your vault's ${name.toLowerCase()}`;\n }\n\n /**\n * Parse config changes into structured format\n */\n private parseConfigChanges(configType: number, configData: string): Array<{ field: string; newValue: string }> {\n // Basic parsing - would need more context for full implementation\n return [{\n field: getConfigTypeName(configType),\n newValue: configData.length > 66 ? `${configData.slice(0, 66)}...` : configData,\n }];\n }\n\n /**\n * Update parser configuration\n */\n updateConfig(config: Partial<TransactionParserConfig>): void {\n this.config = { ...this.config, ...config };\n if (config.knownTokens) {\n this.tokenRegistry = config.knownTokens;\n }\n }\n\n /**\n * Add a known token to the registry\n */\n addKnownToken(address: string, info: TokenInfo): void {\n this.tokenRegistry.set(address.toLowerCase(), info);\n }\n\n /**\n * Add a known recipient label\n */\n addKnownRecipient(address: string, label: string): void {\n if (!this.config.knownRecipients) {\n this.config.knownRecipients = new Map();\n }\n this.config.knownRecipients.set(address.toLowerCase(), label);\n }\n}\n\n// ============================================================================\n// Audit Logging Types and Functions\n// ============================================================================\n\n/**\n * Audit log entry for transaction summaries\n * Used for security audits and debugging\n */\nexport interface TransactionAuditEntry {\n /** Unique identifier matching the TransactionSummary.id */\n summaryId: string;\n /** ISO timestamp when summary was generated */\n timestamp: string;\n /** Action type that was parsed */\n actionType: string;\n /** Human-readable title shown to user */\n titleDisplayed: string;\n /** Human-readable description shown to user */\n descriptionDisplayed: string;\n /** Number of risk warnings shown */\n riskWarningCount: number;\n /** Highest risk level in warnings */\n highestRiskLevel: string | null;\n /** Whether technical details were available */\n hasTechnicalDetails: boolean;\n /** Hash of the raw payload for verification */\n payloadHash: string;\n /** Expiration time shown */\n expiresAt: number;\n /** Chain ID of the transaction */\n targetChain: number;\n /** Gas cost formatted as shown to user */\n gasCostDisplayed: string;\n}\n\n/**\n * Create an audit log entry from a transaction summary\n * \n * @param summary - The transaction summary that was displayed\n * @returns Audit entry for logging\n */\nexport function createAuditEntry(summary: TransactionSummary): TransactionAuditEntry {\n const highestRisk = summary.warnings.reduce<string | null>((acc, r) => {\n const order: Record<string, number> = { critical: 0, high: 1, warning: 2, info: 3 };\n if (acc === null) return r.level;\n if (order[r.level] < order[acc]) {\n return r.level;\n }\n return acc;\n }, null);\n\n return {\n summaryId: `${summary.generatedAt}-${summary.action}`,\n timestamp: new Date().toISOString(),\n actionType: summary.action,\n titleDisplayed: summary.title,\n descriptionDisplayed: summary.description,\n riskWarningCount: summary.warnings.length,\n highestRiskLevel: highestRisk,\n hasTechnicalDetails: !!summary.raw,\n payloadHash: summary.raw?.actionPayload ? ethers.keccak256(summary.raw.actionPayload) : '',\n expiresAt: summary.raw?.expiresAt ?? 0,\n targetChain: summary.raw?.chainId ?? 0,\n gasCostDisplayed: summary.fee.total,\n };\n}\n\n/**\n * Log a transaction summary for audit purposes\n * \n * @param summary - The transaction summary to log\n * @param logger - Optional custom logger (defaults to console.info)\n */\nexport function logTransactionSummary(\n summary: TransactionSummary,\n logger: (entry: TransactionAuditEntry) => void = (entry) => {\n // Default: structured console logging\n console.info('[VERIDEX_TX_AUDIT]', JSON.stringify(entry));\n }\n): TransactionAuditEntry {\n const entry = createAuditEntry(summary);\n logger(entry);\n return entry;\n}\n\n// ============================================================================\n// Factory Function\n// ============================================================================\n\n/**\n * Create a transaction parser with optional configuration\n */\nexport function createTransactionParser(config?: TransactionParserConfig): TransactionParser {\n return new TransactionParser(config);\n}\n","/**\n * Veridex Protocol SDK - Transaction Summary Types\n * \n * Human-readable transaction summary types for security and UX (Issue #26)\n * \n * These types enable users to understand what they're signing before\n * providing biometric authentication, preventing phishing and social engineering.\n */\n\n// ============================================================================\n// Action Display Types\n// ============================================================================\n\n/**\n * Human-readable action type\n */\nexport type ActionDisplayType = 'transfer' | 'bridge' | 'config' | 'execute' | 'unknown';\n\n/**\n * Token display information\n */\nexport interface TokenDisplay {\n /** Token symbol (e.g., \"ETH\", \"USDC\") */\n symbol: string;\n /** Human-readable amount (e.g., \"1.5\") */\n amount: string;\n /** Raw amount in smallest unit */\n rawAmount: bigint;\n /** Token contract address */\n address: string;\n /** Number of decimals */\n decimals: number;\n /** Estimated USD value (if available) */\n usdValue?: string;\n /** Whether this is the native token */\n isNative: boolean;\n}\n\n/**\n * Recipient display information\n */\nexport interface RecipientDisplay {\n /** Raw address (hex) */\n address: string;\n /** ENS name (if resolved) */\n ens?: string;\n /** Truncated address for display (e.g., \"0x1234...5678\") */\n truncated: string;\n /** Whether this is a contract address */\n isContract?: boolean;\n /** Whether this is a new recipient (never sent to before) */\n isNewRecipient?: boolean;\n /** Label if known (e.g., \"My Wallet\", \"Exchange\") */\n label?: string;\n}\n\n/**\n * Chain display information\n */\nexport interface ChainDisplay {\n /** Wormhole chain ID */\n id: number;\n /** Human-readable chain name */\n name: string;\n /** Chain icon URL (optional) */\n iconUrl?: string;\n /** Whether this is a testnet */\n isTestnet: boolean;\n}\n\n// ============================================================================\n// Risk Warning Types\n// ============================================================================\n\n/**\n * Risk level for warnings\n */\nexport type RiskLevel = 'info' | 'warning' | 'high' | 'critical';\n\n/**\n * Risk warning with message and metadata\n */\nexport interface RiskWarning {\n /** Severity level */\n level: RiskLevel;\n /** Human-readable warning message */\n message: string;\n /** Warning type for programmatic handling */\n type: RiskWarningType;\n /** Additional context/details */\n details?: string;\n}\n\n/**\n * Types of risk warnings\n */\nexport type RiskWarningType =\n | 'large_transaction' // Amount exceeds usual activity\n | 'new_recipient' // First time sending to this address\n | 'contract_interaction' // Calling an external contract\n | 'full_balance' // Transferring all assets\n | 'high_gas' // Gas cost is unusually high\n | 'unknown_token' // Token not in verified list\n | 'cross_chain' // Cross-chain operation\n | 'config_change' // Vault configuration change\n | 'all_tokens' // Affects all tokens in vault\n | 'irreversible'; // Action cannot be undone\n\n// ============================================================================\n// Transaction Summary Types\n// ============================================================================\n\n/**\n * Transfer-specific details\n */\nexport interface TransferDetails {\n token: TokenDisplay;\n recipient: RecipientDisplay;\n chain: ChainDisplay;\n}\n\n/**\n * Bridge-specific details\n */\nexport interface BridgeDetails {\n token: TokenDisplay;\n sourceChain: ChainDisplay;\n destinationChain: ChainDisplay;\n recipient: RecipientDisplay;\n /** Estimated bridge fee */\n bridgeFee?: string;\n /** Estimated arrival time */\n estimatedTime?: string;\n}\n\n/**\n * Execute (contract call) details\n */\nexport interface ExecuteDetails {\n target: RecipientDisplay;\n value: TokenDisplay;\n chain: ChainDisplay;\n /** Function signature if decodable */\n functionName?: string;\n /** Decoded function arguments if available */\n decodedArgs?: Record<string, unknown>;\n /** Raw calldata (hex) */\n calldata: string;\n}\n\n/**\n * Config change details\n */\nexport interface ConfigDetails {\n configType: number;\n configTypeName: string;\n description: string;\n changes: Array<{\n field: string;\n oldValue?: string;\n newValue: string;\n }>;\n}\n\n/**\n * Union type for all action-specific details\n */\nexport type ActionDetails = TransferDetails | BridgeDetails | ExecuteDetails | ConfigDetails;\n\n/**\n * Complete transaction summary for display\n */\nexport interface TransactionSummary {\n /** Action type for display */\n action: ActionDisplayType;\n\n /** Human-readable title (e.g., \"Send ETH\", \"Bridge USDC\") */\n title: string;\n\n /** Human-readable description */\n description: string;\n\n /** Action-specific details */\n details: TransferDetails | BridgeDetails | ExecuteDetails | ConfigDetails | null;\n\n /** Source vault information */\n vault: {\n address: string;\n truncated: string;\n chain: ChainDisplay;\n };\n\n /** Fee information */\n fee: {\n /** Estimated gas fee */\n gas: string;\n /** Gas in USD (if available) */\n gasUsd?: string;\n /** Whether fee is paid by relayer */\n paidByRelayer: boolean;\n /** Relayer fee (if applicable) */\n relayerFee?: string;\n /** Total fee */\n total: string;\n };\n\n /** Risk warnings */\n warnings: RiskWarning[];\n\n /** Raw technical details for advanced users */\n raw: {\n actionType: number;\n actionPayload: string;\n nonce: bigint;\n challenge: string;\n chainId: number;\n /** Expiration timestamp */\n expiresAt: number;\n /** Time until expiration in human readable form */\n expiresIn: string;\n };\n\n /** Timestamp when summary was generated */\n generatedAt: number;\n}\n\n// ============================================================================\n// Parser Configuration\n// ============================================================================\n\n/**\n * Configuration for the transaction parser\n */\nexport interface TransactionParserConfig {\n /** Default chain ID for vault operations */\n defaultChainId?: number;\n /** Known token registry (address -> info) */\n knownTokens?: Map<string, TokenInfo>;\n /** Known recipient labels (address -> label) */\n knownRecipients?: Map<string, string>;\n /** ENS resolver function */\n ensResolver?: (address: string) => Promise<string | null>;\n /** Contract detector function */\n contractDetector?: (address: string) => Promise<boolean>;\n /** Price oracle for USD values */\n priceOracle?: (tokenAddress: string) => Promise<number | null>;\n /** User's transaction history for new recipient detection */\n transactionHistory?: Set<string>;\n /** User's average transaction value for large tx detection */\n averageTransactionValue?: bigint;\n}\n\n/**\n * Token info for registry\n */\nexport interface TokenInfo {\n symbol: string;\n name: string;\n decimals: number;\n logoUrl?: string;\n verified: boolean;\n}\n\n// ============================================================================\n// Chain Name Mapping\n// ============================================================================\n\n/**\n * Get chain display info from Wormhole chain ID\n */\nexport const CHAIN_DISPLAY_INFO: Record<number, Omit<ChainDisplay, 'id'>> = {\n // Mainnets\n 1: { name: 'Solana', isTestnet: false },\n 2: { name: 'Ethereum', isTestnet: false },\n 4: { name: 'BSC', isTestnet: false },\n 5: { name: 'Polygon', isTestnet: false },\n 6: { name: 'Avalanche', isTestnet: false },\n 21: { name: 'Sui', isTestnet: false },\n 22: { name: 'Aptos', isTestnet: false },\n 23: { name: 'Arbitrum', isTestnet: false },\n 24: { name: 'Optimism', isTestnet: false },\n 30: { name: 'Base', isTestnet: false },\n\n // Testnets\n 10002: { name: 'Sepolia', isTestnet: true },\n 10003: { name: 'Arbitrum Sepolia', isTestnet: true },\n 10004: { name: 'Base Sepolia', isTestnet: true },\n 10005: { name: 'Optimism Sepolia', isTestnet: true },\n 50001: { name: 'Starknet Sepolia', isTestnet: true },\n // Note: Avalanche Fuji also uses Wormhole chain ID 6 — same as mainnet.\n // The isTestnet flag on mainnet entry (6) is set to false; frontends should\n // detect testnet via EVM chainId (43113 vs 43114) rather than Wormhole chain ID.\n};\n\n/**\n * Get chain display info with fallback\n */\nexport function getChainDisplay(chainId: number): ChainDisplay {\n const info = CHAIN_DISPLAY_INFO[chainId];\n if (info) {\n return { id: chainId, ...info };\n }\n return {\n id: chainId,\n name: `Chain ${chainId}`,\n isTestnet: chainId >= 10000,\n };\n}\n\n// ============================================================================\n// Config Type Names\n// ============================================================================\n\nexport const CONFIG_TYPE_NAMES: Record<number, string> = {\n 1: 'Update Spending Limits',\n 2: 'Add Guardian',\n 3: 'Remove Guardian',\n 4: 'Update Recovery Threshold',\n 5: 'Add Session Key',\n 6: 'Revoke Session Key',\n 7: 'Update Emergency Contact',\n};\n\n/**\n * Get config type name with fallback\n */\nexport function getConfigTypeName(configType: number): string {\n return CONFIG_TYPE_NAMES[configType] ?? `Config Update (Type ${configType})`;\n}\n","/**\n * Veridex Protocol SDK - Spending Limits Manager (Issue #27)\n * \n * Manages vault spending limits including:\n * - Reading current limits and usage from on-chain state\n * - Preparing limit update transactions (requires passkey signature)\n * - Checking transactions against limits before signing\n * - Formatting limits for UI display\n * \n * Security Considerations:\n * - All limit changes require Hub authentication (passkey signature)\n * - Changes are propagated via VAA to spoke chains\n * - Local checks are advisory; on-chain enforcement is authoritative\n */\n\nimport { ethers } from 'ethers';\nimport {\n type SpendingLimits,\n type FormattedSpendingLimits,\n type LimitCheckResult,\n type LimitViolationSuggestion,\n type SpendingTransaction,\n type DailySpendingSummary,\n type DurationDisplay,\n type SpendingLimitConfig,\n type SpendingLimitChangedEvent,\n type SpendingLimitEventCallback,\n CONFIG_TYPE,\n formatDuration,\n calculatePercentage,\n formatLargeAmount,\n} from './SpendingLimits.types.js';\nimport { encodeConfigAction } from '../payload.js';\n\n// ============================================================================\n// Vault ABI Fragment (spending limit related functions)\n// ============================================================================\n\nconst VAULT_ABI = [\n 'function dailyLimit() view returns (uint256)',\n 'function dailyWithdrawn() view returns (uint256)',\n 'function dayStart() view returns (uint256)',\n 'function paused() view returns (bool)',\n 'function getRemainingDailyLimit() view returns (uint256)',\n 'event Paused(bool paused)',\n 'event DailyLimitUpdated(uint256 newLimit)',\n];\n\n// ============================================================================\n// Constants\n// ============================================================================\n\n/** One day in seconds */\nconst DAY_SECONDS = 86400;\n\n/** One day in milliseconds */\nconst DAY_MS = DAY_SECONDS * 1000;\n\n// ============================================================================\n// Configuration\n// ============================================================================\n\nexport interface SpendingLimitsManagerConfig {\n /** Default token decimals for formatting */\n defaultDecimals?: number;\n \n /** Default token symbol for formatting */\n defaultSymbol?: string;\n \n /** Custom RPC URLs by chain ID */\n rpcUrls?: Record<number, string>;\n \n /** Cache TTL in milliseconds */\n cacheTtl?: number;\n \n /** Event callback for limit changes */\n onLimitChange?: SpendingLimitEventCallback;\n}\n\n// ============================================================================\n// Main Class\n// ============================================================================\n\nexport class SpendingLimitsManager {\n private config: Required<SpendingLimitsManagerConfig>;\n private cache: Map<string, { data: SpendingLimits; expiry: number }> = new Map();\n private eventListeners: SpendingLimitEventCallback[] = [];\n \n constructor(config: SpendingLimitsManagerConfig = {}) {\n this.config = {\n defaultDecimals: config.defaultDecimals ?? 18,\n defaultSymbol: config.defaultSymbol ?? 'ETH',\n rpcUrls: config.rpcUrls ?? {},\n cacheTtl: config.cacheTtl ?? 10000, // 10 seconds\n onLimitChange: config.onLimitChange ?? (() => {}),\n };\n \n if (config.onLimitChange) {\n this.eventListeners.push(config.onLimitChange);\n }\n }\n \n // ============================================================================\n // Read Spending Limits\n // ============================================================================\n \n /**\n * Get current spending limits for a vault\n * @param vaultAddress - Vault contract address\n * @param chainId - Chain ID where the vault is deployed\n * @param rpcUrl - Optional RPC URL override\n */\n async getSpendingLimits(\n vaultAddress: string,\n chainId: number,\n rpcUrl?: string\n ): Promise<SpendingLimits> {\n // Check cache first\n const cacheKey = `${chainId}:${vaultAddress.toLowerCase()}`;\n const cached = this.cache.get(cacheKey);\n if (cached && Date.now() < cached.expiry) {\n return cached.data;\n }\n \n const provider = this.getProvider(chainId, rpcUrl);\n const vault = new ethers.Contract(vaultAddress, VAULT_ABI, provider);\n \n // Fetch all values in parallel\n const [dailyLimit, dailyWithdrawn, dayStart, paused] = await Promise.all([\n vault.dailyLimit() as Promise<bigint>,\n vault.dailyWithdrawn() as Promise<bigint>,\n vault.dayStart() as Promise<bigint>,\n vault.paused() as Promise<boolean>,\n ]);\n \n const now = Date.now();\n const dayStartMs = Number(dayStart) * 1000;\n const dayEndMs = dayStartMs + DAY_MS;\n \n // Calculate effective values (handle day rollover)\n let effectiveSpent = dailyWithdrawn;\n let effectiveResetTime = new Date(dayEndMs);\n let timeUntilReset = dayEndMs - now;\n \n if (now >= dayEndMs) {\n // New day has started, spent resets to 0\n effectiveSpent = 0n;\n // Calculate next reset time\n const daysSinceStart = Math.floor((now - dayStartMs) / DAY_MS);\n const nextDayStart = dayStartMs + (daysSinceStart + 1) * DAY_MS;\n effectiveResetTime = new Date(nextDayStart);\n timeUntilReset = nextDayStart - now;\n }\n \n const dailyRemaining = dailyLimit === 0n \n ? BigInt('0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff') // max uint256\n : dailyLimit > effectiveSpent \n ? dailyLimit - effectiveSpent \n : 0n;\n \n const limits: SpendingLimits = {\n dailyLimit,\n dailySpent: effectiveSpent,\n dailyRemaining,\n dayResetTime: effectiveResetTime,\n timeUntilReset: Math.max(0, timeUntilReset),\n transactionLimit: 0n, // Per-tx limits are in SpendingLimitModule, not base vault\n isPaused: paused,\n lastUpdated: new Date(),\n chainId,\n };\n \n // Cache the result\n this.cache.set(cacheKey, {\n data: limits,\n expiry: now + this.config.cacheTtl,\n });\n \n return limits;\n }\n \n /**\n * Get spending limits formatted for UI display\n */\n async getFormattedSpendingLimits(\n vaultAddress: string,\n chainId: number,\n options?: {\n rpcUrl?: string;\n decimals?: number;\n symbol?: string;\n }\n ): Promise<FormattedSpendingLimits> {\n const limits = await this.getSpendingLimits(vaultAddress, chainId, options?.rpcUrl);\n const decimals = options?.decimals ?? this.config.defaultDecimals;\n const symbol = options?.symbol ?? this.config.defaultSymbol;\n \n return this.formatLimits(limits, decimals, symbol);\n }\n \n /**\n * Format raw limits for display\n */\n formatLimits(\n limits: SpendingLimits,\n decimals: number = 18,\n symbol: string = 'ETH'\n ): FormattedSpendingLimits {\n const hasDailyLimit = limits.dailyLimit > 0n;\n \n // Convert to number for display (safe for typical amounts)\n const toNumber = (val: bigint): number => {\n const divisor = 10n ** BigInt(decimals);\n return Number(val * 10000n / divisor) / 10000;\n };\n \n return {\n dailyLimit: hasDailyLimit \n ? formatLargeAmount(limits.dailyLimit, decimals, symbol)\n : 'Unlimited',\n dailyLimitValue: toNumber(limits.dailyLimit),\n dailySpent: formatLargeAmount(limits.dailySpent, decimals, symbol),\n dailySpentValue: toNumber(limits.dailySpent),\n dailyRemaining: hasDailyLimit \n ? formatLargeAmount(limits.dailyRemaining, decimals, symbol)\n : 'Unlimited',\n dailyRemainingValue: toNumber(limits.dailyRemaining),\n dailyUsedPercentage: hasDailyLimit \n ? calculatePercentage(limits.dailySpent, limits.dailyLimit)\n : 0,\n timeUntilReset: formatDuration(limits.timeUntilReset).formatted,\n transactionLimit: limits.transactionLimit > 0n\n ? formatLargeAmount(limits.transactionLimit, decimals, symbol)\n : 'Unlimited',\n transactionLimitValue: toNumber(limits.transactionLimit),\n isPaused: limits.isPaused,\n hasDailyLimit,\n hasTransactionLimit: limits.transactionLimit > 0n,\n };\n }\n \n // ============================================================================\n // Limit Checks\n // ============================================================================\n \n /**\n * Check if a transaction amount is within limits\n * @param vaultAddress - Vault to check\n * @param chainId - Chain ID\n * @param amount - Amount to transfer (in base units)\n * @returns Result indicating if transfer is allowed\n */\n async checkTransactionLimit(\n vaultAddress: string,\n chainId: number,\n amount: bigint,\n options?: { rpcUrl?: string }\n ): Promise<LimitCheckResult> {\n const limits = await this.getSpendingLimits(vaultAddress, chainId, options?.rpcUrl);\n \n // Check if paused first\n if (limits.isPaused) {\n return {\n allowed: false,\n reason: 'vault_paused',\n message: 'Vault is paused. Unpause to continue.',\n suggestions: [\n {\n action: 'unpause_vault',\n label: 'Unpause Vault',\n },\n ],\n };\n }\n \n // Check per-transaction limit\n if (limits.transactionLimit > 0n && amount > limits.transactionLimit) {\n return {\n allowed: false,\n reason: 'transaction_limit_exceeded',\n message: `Transaction exceeds per-transaction limit of ${formatLargeAmount(limits.transactionLimit, this.config.defaultDecimals, this.config.defaultSymbol)}`,\n allowedAmount: limits.transactionLimit,\n excessAmount: amount - limits.transactionLimit,\n suggestions: [\n {\n action: 'send_partial',\n label: `Send ${formatLargeAmount(limits.transactionLimit, this.config.defaultDecimals, this.config.defaultSymbol)} (within limit)`,\n data: { amount: limits.transactionLimit },\n },\n {\n action: 'increase_limit',\n label: 'Increase Transaction Limit',\n },\n ],\n };\n }\n \n // Check daily limit\n if (limits.dailyLimit > 0n) {\n const wouldSpend = limits.dailySpent + amount;\n \n if (wouldSpend > limits.dailyLimit) {\n const excessAmount = wouldSpend - limits.dailyLimit;\n const suggestions: LimitViolationSuggestion[] = [];\n \n // Suggest partial transfer if some amount is available\n if (limits.dailyRemaining > 0n) {\n suggestions.push({\n action: 'send_partial',\n label: `Send ${formatLargeAmount(limits.dailyRemaining, this.config.defaultDecimals, this.config.defaultSymbol)} (within limit)`,\n data: { amount: limits.dailyRemaining },\n });\n }\n \n suggestions.push({\n action: 'increase_limit',\n label: 'Increase Daily Limit',\n data: { newLimit: wouldSpend },\n });\n \n suggestions.push({\n action: 'wait_for_reset',\n label: `Wait ${formatDuration(limits.timeUntilReset).formatted} for limit reset`,\n data: { waitTimeMs: limits.timeUntilReset },\n });\n \n return {\n allowed: false,\n reason: 'daily_limit_exceeded',\n message: `Transaction would exceed daily limit. Already spent ${formatLargeAmount(limits.dailySpent, this.config.defaultDecimals, this.config.defaultSymbol)} of ${formatLargeAmount(limits.dailyLimit, this.config.defaultDecimals, this.config.defaultSymbol)} today.`,\n allowedAmount: limits.dailyRemaining,\n excessAmount,\n waitTime: limits.timeUntilReset,\n suggestions,\n };\n }\n }\n \n return {\n allowed: true,\n message: 'Transaction is within limits',\n };\n }\n \n // ============================================================================\n // Limit Configuration (Prepare for Signing)\n // ============================================================================\n \n /**\n * Prepare a transaction to update the daily spending limit\n * Returns the config action payload that needs to be signed via passkey\n * \n * @param newLimit - New daily limit in base units (0 = unlimited)\n * @returns Config action payload for signing\n */\n prepareDailyLimitUpdate(newLimit: bigint): string {\n // Config type 1 = daily limit update\n // Config data format: [limit(32)]\n const limitBytes = ethers.zeroPadValue(ethers.toBeHex(newLimit), 32);\n return encodeConfigAction(CONFIG_TYPE.DAILY_LIMIT, limitBytes);\n }\n \n /**\n * Prepare a transaction to pause the vault\n * @returns Config action payload for signing\n */\n preparePauseVault(): string {\n // Config type 2 = pause, config data: [paused(1)] where 1 = paused\n const pausedByte = ethers.toBeHex(1, 1);\n return encodeConfigAction(CONFIG_TYPE.PAUSE, pausedByte);\n }\n \n /**\n * Prepare a transaction to unpause the vault\n * @returns Config action payload for signing\n */\n prepareUnpauseVault(): string {\n // Config type 2 = pause, config data: [paused(1)] where 0 = unpaused\n const unpausedByte = ethers.toBeHex(0, 1);\n return encodeConfigAction(CONFIG_TYPE.PAUSE, unpausedByte);\n }\n \n /**\n * Get the full spending limit configuration encoded as config payload\n * Used during vault creation to set initial limits\n */\n encodeInitialLimits(config: SpendingLimitConfig): string {\n if (!config.dailyLimit || config.dailyLimit === 0n) {\n // No limit configuration needed\n return '';\n }\n return this.prepareDailyLimitUpdate(config.dailyLimit);\n }\n \n // ============================================================================\n // Transaction History\n // ============================================================================\n \n /**\n * Get recent spending transactions for a vault\n * Note: This requires indexer integration for full history\n * @param vaultAddress - Vault to query\n * @param chainId - Chain ID\n * @param limit - Maximum number of transactions to return\n */\n async getRecentTransactions(\n vaultAddress: string,\n chainId: number,\n limit: number = 10\n ): Promise<SpendingTransaction[]> {\n // Note: Full implementation requires indexer/subgraph integration\n // For now, return empty array - UI should handle gracefully\n // In production, this would query a subgraph or indexer API\n console.log(`[SpendingLimitsManager] getRecentTransactions not fully implemented. Vault: ${vaultAddress}, Chain: ${chainId}, Limit: ${limit}`);\n return [];\n }\n \n /**\n * Get daily spending summary\n */\n async getDailySpendingSummary(\n vaultAddress: string,\n chainId: number,\n date?: Date\n ): Promise<DailySpendingSummary> {\n const targetDate = date ?? new Date();\n const transactions = await this.getRecentTransactions(vaultAddress, chainId, 100);\n \n // Filter transactions from the target date\n const startOfDay = new Date(targetDate);\n startOfDay.setHours(0, 0, 0, 0);\n const endOfDay = new Date(startOfDay);\n endOfDay.setDate(endOfDay.getDate() + 1);\n \n const dayTransactions = transactions.filter(\n tx => tx.timestamp >= startOfDay && tx.timestamp < endOfDay\n );\n \n const totalSpent = dayTransactions.reduce(\n (sum, tx) => sum + tx.amount,\n 0n\n );\n \n return {\n date: targetDate,\n totalSpent,\n formattedTotal: formatLargeAmount(totalSpent, this.config.defaultDecimals, this.config.defaultSymbol),\n transactionCount: dayTransactions.length,\n transactions: dayTransactions,\n };\n }\n \n // ============================================================================\n // Event Subscription\n // ============================================================================\n \n /**\n * Subscribe to spending limit change events\n */\n onLimitChange(callback: SpendingLimitEventCallback): () => void {\n this.eventListeners.push(callback);\n return () => {\n const index = this.eventListeners.indexOf(callback);\n if (index >= 0) {\n this.eventListeners.splice(index, 1);\n }\n };\n }\n \n /**\n * Notify listeners of a limit change event\n * Call this after a successful limit update transaction\n */\n notifyLimitChange(event: SpendingLimitChangedEvent): void {\n for (const listener of this.eventListeners) {\n try {\n listener(event);\n } catch (error) {\n console.error('[SpendingLimitsManager] Event listener error:', error);\n }\n }\n }\n \n // ============================================================================\n // Countdown Timer\n // ============================================================================\n \n /**\n * Get a live countdown to daily limit reset\n * Returns an object with current time remaining that updates\n */\n async getResetCountdown(\n vaultAddress: string,\n chainId: number,\n options?: { rpcUrl?: string }\n ): Promise<{\n getCurrentTimeRemaining: () => DurationDisplay;\n timeUntilResetMs: number;\n resetTime: Date;\n }> {\n const limits = await this.getSpendingLimits(vaultAddress, chainId, options?.rpcUrl);\n const fetchTime = Date.now();\n \n return {\n getCurrentTimeRemaining: () => {\n const elapsed = Date.now() - fetchTime;\n const remaining = Math.max(0, limits.timeUntilReset - elapsed);\n return formatDuration(remaining);\n },\n timeUntilResetMs: limits.timeUntilReset,\n resetTime: limits.dayResetTime,\n };\n }\n \n // ============================================================================\n // Cache Management\n // ============================================================================\n \n /**\n * Clear the cache for a specific vault or all vaults\n */\n clearCache(vaultAddress?: string, chainId?: number): void {\n if (vaultAddress && chainId) {\n this.cache.delete(`${chainId}:${vaultAddress.toLowerCase()}`);\n } else {\n this.cache.clear();\n }\n }\n \n /**\n * Invalidate cache after a limit change\n */\n invalidateCacheAfterChange(vaultAddress: string, chainId: number): void {\n this.clearCache(vaultAddress, chainId);\n }\n \n // ============================================================================\n // Helpers\n // ============================================================================\n \n /**\n * Get a provider for the specified chain\n */\n private getProvider(chainId: number, rpcUrl?: string): ethers.Provider {\n const url = rpcUrl ?? this.config.rpcUrls[chainId];\n if (!url) {\n throw new Error(`No RPC URL configured for chain ${chainId}`);\n }\n return new ethers.JsonRpcProvider(url);\n }\n}\n\n// ============================================================================\n// Factory Function\n// ============================================================================\n\n/**\n * Create a SpendingLimitsManager instance\n */\nexport function createSpendingLimitsManager(\n config?: SpendingLimitsManagerConfig\n): SpendingLimitsManager {\n return new SpendingLimitsManager(config);\n}\n","/**\n * Veridex Protocol SDK - Spending Limits Type Definitions (Issue #27)\n * \n * Types for configuring, viewing, and enforcing spending limits on vaults.\n * Spending limits provide an additional security layer against:\n * - Compromised passkeys draining entire vault\n * - Accidental large transactions\n * - Malicious session key abuse\n * \n * Security Model:\n * - Limits are enforced on-chain by the vault contract\n * - Limit changes require passkey signature (Hub authentication)\n * - Circuit breaker auto-pauses vault on limit violation\n * - Daily limits reset 24 hours from first spend\n */\n\n// ============================================================================\n// Core Types\n// ============================================================================\n\n/**\n * Current spending limits and usage for a vault\n */\nexport interface SpendingLimits {\n /** Daily spending limit (0 = unlimited) */\n dailyLimit: bigint;\n \n /** Amount spent in current 24-hour period */\n dailySpent: bigint;\n \n /** Remaining daily allowance */\n dailyRemaining: bigint;\n \n /** When the daily counter resets (UTC timestamp) */\n dayResetTime: Date;\n \n /** Time remaining until daily reset (milliseconds) */\n timeUntilReset: number;\n \n /** Per-transaction limit (0 = unlimited) */\n transactionLimit: bigint;\n \n /** Whether the vault is currently paused */\n isPaused: boolean;\n \n /** Last updated timestamp */\n lastUpdated: Date;\n \n /** Chain where these limits are enforced */\n chainId: number;\n}\n\n/**\n * Formatted spending limits for UI display\n */\nexport interface FormattedSpendingLimits {\n /** Daily limit as human-readable string (e.g., \"1,000 USDC\") */\n dailyLimit: string;\n \n /** Daily limit as raw number for calculations */\n dailyLimitValue: number;\n \n /** Amount spent today as human-readable string */\n dailySpent: string;\n \n /** Amount spent as raw number */\n dailySpentValue: number;\n \n /** Remaining daily allowance as human-readable string */\n dailyRemaining: string;\n \n /** Remaining as raw number */\n dailyRemainingValue: number;\n \n /** Percentage of daily limit used (0-100) */\n dailyUsedPercentage: number;\n \n /** Time until reset as human-readable string (e.g., \"6h 23m\") */\n timeUntilReset: string;\n \n /** Transaction limit as human-readable string */\n transactionLimit: string;\n \n /** Transaction limit as raw number */\n transactionLimitValue: number;\n \n /** Whether the vault is paused */\n isPaused: boolean;\n \n /** Whether daily limit is set (false = unlimited) */\n hasDailyLimit: boolean;\n \n /** Whether transaction limit is set (false = unlimited) */\n hasTransactionLimit: boolean;\n}\n\n/**\n * Spending limit configuration during vault creation\n */\nexport interface SpendingLimitConfig {\n /** Daily spending limit (optional, 0 = unlimited) */\n dailyLimit?: bigint;\n \n /** Per-transaction limit (optional, 0 = unlimited) */\n transactionLimit?: bigint;\n \n /** Whether to require 2FA for transactions above threshold */\n requireMultiSigAbove?: bigint;\n \n /** Whitelisted recipients (unlimited transfers allowed) */\n whitelistedRecipients?: string[];\n}\n\n/**\n * Parameters for setting daily limit\n */\nexport interface SetDailyLimitParams {\n /** New daily limit in wei/lamports/base units */\n limit: bigint;\n \n /** Optional chain to configure (defaults to current chain) */\n chainId?: number;\n}\n\n/**\n * Parameters for setting transaction limit\n */\nexport interface SetTransactionLimitParams {\n /** New transaction limit in wei/lamports/base units */\n limit: bigint;\n \n /** Optional chain to configure (defaults to current chain) */\n chainId?: number;\n}\n\n// ============================================================================\n// Limit Enforcement Types\n// ============================================================================\n\n/**\n * Result of checking if a transaction is within limits\n */\nexport interface LimitCheckResult {\n /** Whether the transaction is allowed */\n allowed: boolean;\n \n /** Reason code if not allowed */\n reason?: LimitViolationType;\n \n /** Human-readable message */\n message: string;\n \n /** Amount that would be allowed (if partially allowed) */\n allowedAmount?: bigint;\n \n /** Amount that exceeds limit */\n excessAmount?: bigint;\n \n /** Time to wait if daily limit reached */\n waitTime?: number;\n \n /** Suggested actions for the user */\n suggestions?: LimitViolationSuggestion[];\n}\n\n/**\n * Types of limit violations\n */\nexport type LimitViolationType =\n | 'daily_limit_exceeded'\n | 'transaction_limit_exceeded'\n | 'vault_paused'\n | 'insufficient_balance'\n | 'daily_limit_would_exceed';\n\n/**\n * Suggestion for resolving a limit violation\n */\nexport interface LimitViolationSuggestion {\n /** Action type */\n action: 'send_partial' | 'increase_limit' | 'wait_for_reset' | 'unpause_vault';\n \n /** Human-readable label */\n label: string;\n \n /** Additional data for the action */\n data?: {\n amount?: bigint;\n waitTimeMs?: number;\n newLimit?: bigint;\n };\n}\n\n// ============================================================================\n// Transaction History Types\n// ============================================================================\n\n/**\n * A spending transaction in the history\n */\nexport interface SpendingTransaction {\n /** Transaction hash */\n hash: string;\n \n /** Amount spent (in wei/lamports) */\n amount: bigint;\n \n /** Human-readable amount */\n formattedAmount: string;\n \n /** Token symbol */\n tokenSymbol: string;\n \n /** Recipient address */\n recipient: string;\n \n /** Recipient display name (ENS, label, or truncated) */\n recipientDisplay: string;\n \n /** When the transaction occurred */\n timestamp: Date;\n \n /** Relative time (e.g., \"2h ago\") */\n relativeTime: string;\n \n /** Transaction type */\n type: 'transfer' | 'bridge' | 'execute';\n \n /** Whether this counted against daily limit */\n countedAgainstLimit: boolean;\n}\n\n/**\n * Daily spending summary\n */\nexport interface DailySpendingSummary {\n /** Date for this summary */\n date: Date;\n \n /** Total amount spent */\n totalSpent: bigint;\n \n /** Formatted total */\n formattedTotal: string;\n \n /** Number of transactions */\n transactionCount: number;\n \n /** Individual transactions */\n transactions: SpendingTransaction[];\n}\n\n// ============================================================================\n// Config Action Encoding\n// ============================================================================\n\n/**\n * Config types matching VeridexVault.sol\n */\nexport const CONFIG_TYPE = {\n /** Update daily limit */\n DAILY_LIMIT: 1,\n /** Pause/unpause vault */\n PAUSE: 2,\n /** Update guardians */\n GUARDIANS: 3,\n /** Register sender */\n REGISTER_SENDER: 4,\n /** Allow source chain */\n ALLOW_CHAIN: 5,\n /** Set query verifier */\n QUERY_VERIFIER: 6,\n} as const;\n\nexport type ConfigType = (typeof CONFIG_TYPE)[keyof typeof CONFIG_TYPE];\n\n// ============================================================================\n// Event Types\n// ============================================================================\n\n/**\n * Event emitted when spending limits change\n */\nexport interface SpendingLimitChangedEvent {\n /** Event type */\n type: 'daily_limit_changed' | 'transaction_limit_changed' | 'vault_paused' | 'vault_unpaused';\n \n /** Previous value */\n previousValue: bigint | boolean;\n \n /** New value */\n newValue: bigint | boolean;\n \n /** Transaction hash */\n txHash: string;\n \n /** Block timestamp */\n timestamp: Date;\n}\n\n/**\n * Callback for spending limit events\n */\nexport type SpendingLimitEventCallback = (event: SpendingLimitChangedEvent) => void;\n\n// ============================================================================\n// Preset Configurations\n// ============================================================================\n\n/**\n * Predefined spending limit configurations\n */\nexport interface LimitPreset {\n /** Preset identifier */\n id: string;\n \n /** Display name */\n name: string;\n \n /** Description */\n description: string;\n \n /** Daily limit suggestion (in USD equivalent) */\n dailyLimitUsd: number;\n \n /** Transaction limit suggestion (in USD equivalent) */\n transactionLimitUsd: number;\n \n /** Icon for UI */\n icon: string;\n \n /** Recommended for user type */\n recommendedFor: string;\n}\n\n/**\n * Standard limit presets\n */\nexport const LIMIT_PRESETS: LimitPreset[] = [\n {\n id: 'conservative',\n name: 'Conservative',\n description: 'Low limits for maximum security',\n dailyLimitUsd: 500,\n transactionLimitUsd: 100,\n icon: '🔒',\n recommendedFor: 'New users or high-value vaults',\n },\n {\n id: 'balanced',\n name: 'Balanced',\n description: 'Moderate limits for everyday use',\n dailyLimitUsd: 2500,\n transactionLimitUsd: 500,\n icon: '⚖️',\n recommendedFor: 'Regular users',\n },\n {\n id: 'generous',\n name: 'Generous',\n description: 'Higher limits for active traders',\n dailyLimitUsd: 10000,\n transactionLimitUsd: 2500,\n icon: '🚀',\n recommendedFor: 'Active traders and power users',\n },\n {\n id: 'unlimited',\n name: 'No Limits',\n description: 'No spending restrictions (not recommended)',\n dailyLimitUsd: 0, // 0 = unlimited\n transactionLimitUsd: 0,\n icon: '⚠️',\n recommendedFor: 'Advanced users who accept full risk',\n },\n];\n\n// ============================================================================\n// Utility Types\n// ============================================================================\n\n/**\n * Duration display for reset countdown\n */\nexport interface DurationDisplay {\n hours: number;\n minutes: number;\n seconds: number;\n formatted: string; // e.g., \"6h 23m\"\n}\n\n/**\n * Calculate duration display from milliseconds\n */\nexport function formatDuration(ms: number): DurationDisplay {\n const totalSeconds = Math.max(0, Math.floor(ms / 1000));\n const hours = Math.floor(totalSeconds / 3600);\n const minutes = Math.floor((totalSeconds % 3600) / 60);\n const seconds = totalSeconds % 60;\n \n let formatted: string;\n if (hours > 0) {\n formatted = `${hours}h ${minutes}m`;\n } else if (minutes > 0) {\n formatted = `${minutes}m ${seconds}s`;\n } else {\n formatted = `${seconds}s`;\n }\n \n return { hours, minutes, seconds, formatted };\n}\n\n/**\n * Calculate percentage safely (handles zero division)\n */\nexport function calculatePercentage(spent: bigint, limit: bigint): number {\n if (limit === 0n) return 0;\n // Use fixed-point math to avoid precision loss\n const percentage = Number((spent * 10000n) / limit) / 100;\n return Math.min(100, Math.max(0, percentage));\n}\n\n/**\n * Format large numbers with appropriate units\n */\nexport function formatLargeAmount(\n amount: bigint,\n decimals: number = 18,\n symbol: string = 'ETH'\n): string {\n const divisor = 10n ** BigInt(decimals);\n const whole = amount / divisor;\n const fraction = amount % divisor;\n \n // Format with up to 4 decimal places\n const fractionStr = fraction.toString().padStart(decimals, '0').slice(0, 4);\n const trimmedFraction = fractionStr.replace(/0+$/, '');\n \n const numStr = trimmedFraction \n ? `${whole.toLocaleString()}.${trimmedFraction}`\n : whole.toLocaleString();\n \n return `${numStr} ${symbol}`;\n}\n","import type { PasskeyManager, PasskeyCredential } from './PasskeyManager.js';\nimport type { WalletManager, ChainAddressConfig } from './WalletManager.js';\nimport type { ChainAddress, ChainClient, UnifiedIdentity } from './types.js';\nimport type { SessionKey } from '../types.js';\nimport { CHAIN_PRESETS, type ChainName, type NetworkType } from '../presets.js';\nimport {\n RelayerClient,\n type CredentialMetadataRecord,\n type RegisteredAppDetail,\n type RegisteredAppStatus,\n type RegisteredAppSummary,\n type RegisteredAppTrustLevel,\n type RelayerAppSession,\n} from './RelayerClient.js';\n\ntype RecoveryGuardiansResult = {\n guardians: string[];\n threshold: bigint;\n isConfigured: boolean;\n};\n\ntype RecoveryStatusResult = {\n isActive: boolean;\n newOwnerKeyHash: string;\n initiatedAt: bigint;\n approvalCount: bigint;\n threshold: bigint;\n canExecuteAt: bigint;\n expiresAt: bigint;\n};\n\ntype RecoveryCapableChain = ChainClient & {\n getGuardians(identityKeyHash: string): Promise<RecoveryGuardiansResult>;\n getRecoveryStatus(identityKeyHash: string): Promise<RecoveryStatusResult>;\n};\n\ntype OnchainSessionCapableChain = ChainClient & {\n getUserSessions(userKeyHash: string): Promise<SessionKey[]>;\n};\n\nexport interface PortabilityOverview {\n credential: PasskeyCredential;\n unifiedIdentity: UnifiedIdentity;\n supportedChainIdentity: UnifiedIdentity;\n localCredentialCount: number;\n remoteCredentials: CredentialMetadataRecord[];\n syncedCredentialCount: number;\n backupEligibleCount: number;\n backupBackedCount: number;\n rootCredentialCount: number;\n supportedChainCount: number;\n nonEvmAddressCount: number;\n}\n\nexport interface RecoveryOverview {\n identityKeyHash: string;\n guardians: string[];\n threshold: bigint;\n isConfigured: boolean;\n recovery: RecoveryStatusResult;\n}\n\nexport interface AccountManagerConfig {\n passkey: PasskeyManager;\n wallet: WalletManager;\n chain: ChainClient;\n relayer?: RelayerClient;\n testnet?: boolean;\n getUnifiedIdentity: () => Promise<UnifiedIdentity>;\n}\n\nfunction isRecoveryCapableChain(chain: ChainClient): chain is RecoveryCapableChain {\n return typeof (chain as RecoveryCapableChain).getGuardians === 'function'\n && typeof (chain as RecoveryCapableChain).getRecoveryStatus === 'function';\n}\n\nfunction isOnchainSessionCapableChain(chain: ChainClient): chain is OnchainSessionCapableChain {\n return typeof (chain as OnchainSessionCapableChain).getUserSessions === 'function';\n}\n\nexport class AccountManager {\n private readonly passkey: PasskeyManager;\n private readonly wallet: WalletManager;\n private readonly chain: ChainClient;\n private readonly relayer?: RelayerClient;\n private readonly network: NetworkType;\n private readonly getUnifiedIdentityImpl: () => Promise<UnifiedIdentity>;\n\n constructor(config: AccountManagerConfig) {\n this.passkey = config.passkey;\n this.wallet = config.wallet;\n this.chain = config.chain;\n this.relayer = config.relayer;\n this.network = config.testnet === false ? 'mainnet' : 'testnet';\n this.getUnifiedIdentityImpl = config.getUnifiedIdentity;\n }\n\n private requireCredential(): PasskeyCredential {\n const credential = this.passkey.getCredential();\n if (!credential) {\n throw new Error('No credential set. Call passkey.register() or passkey.authenticate() first.');\n }\n return credential;\n }\n\n private requireRelayer(): RelayerClient {\n if (!this.relayer) {\n throw new Error('Relayer integration is not configured for this SDK instance.');\n }\n return this.relayer;\n }\n\n async getPortabilityOverview(): Promise<PortabilityOverview> {\n const credential = this.requireCredential();\n const localCredentials = this.passkey.getAllStoredCredentials();\n const unifiedIdentity = await this.getUnifiedIdentityImpl();\n const supportedChainIdentity = await this.getSupportedChainIdentity();\n const remoteCredentials = this.relayer\n ? await this.relayer.listCredentialMetadata(credential.keyHash)\n : [];\n\n return {\n credential,\n unifiedIdentity,\n supportedChainIdentity,\n localCredentialCount: localCredentials.length,\n remoteCredentials,\n syncedCredentialCount: remoteCredentials.filter((item) => item.backupState === true).length,\n backupEligibleCount: remoteCredentials.filter((item) => item.backupEligible === true).length,\n backupBackedCount: remoteCredentials.filter((item) => item.backupState === true).length,\n rootCredentialCount: remoteCredentials.filter((item) => item.isRoot).length,\n supportedChainCount: supportedChainIdentity.addresses.length,\n nonEvmAddressCount: supportedChainIdentity.addresses.filter((item) => item.isEvm === false).length,\n };\n }\n\n async getSupportedChainIdentity(chainNames?: ChainName[]): Promise<UnifiedIdentity> {\n const credential = this.requireCredential();\n return this.wallet.getUnifiedIdentity(credential, this.buildChainAddressConfigMap(chainNames));\n }\n\n async getSupportedChainAddresses(chainNames?: ChainName[]): Promise<ChainAddress[]> {\n const identity = await this.getSupportedChainIdentity(chainNames);\n return identity.addresses;\n }\n\n async listCredentialMetadata(keyHash?: string): Promise<CredentialMetadataRecord[]> {\n const relayer = this.requireRelayer();\n const resolvedKeyHash = keyHash ?? this.requireCredential().keyHash;\n return relayer.listCredentialMetadata(resolvedKeyHash);\n }\n\n async getRecoveryOverview(identityKeyHash?: string): Promise<RecoveryOverview> {\n if (!isRecoveryCapableChain(this.chain)) {\n throw new Error('The configured chain client does not support recovery queries.');\n }\n\n const resolvedKeyHash = identityKeyHash ?? this.requireCredential().keyHash;\n const [guardians, recovery] = await Promise.all([\n this.chain.getGuardians(resolvedKeyHash),\n this.chain.getRecoveryStatus(resolvedKeyHash),\n ]);\n\n return {\n identityKeyHash: resolvedKeyHash,\n guardians: guardians.guardians,\n threshold: guardians.threshold,\n isConfigured: guardians.isConfigured,\n recovery,\n };\n }\n\n async getOnchainSessions(identityKeyHash?: string): Promise<SessionKey[]> {\n if (!isOnchainSessionCapableChain(this.chain)) {\n throw new Error('The configured chain client does not support on-chain session queries.');\n }\n\n const resolvedKeyHash = identityKeyHash ?? this.requireCredential().keyHash;\n return this.chain.getUserSessions(resolvedKeyHash);\n }\n\n async listApps(): Promise<RegisteredAppSummary[]> {\n return this.requireRelayer().listApps();\n }\n\n async getApp(appId: string): Promise<RegisteredAppDetail> {\n return this.requireRelayer().getApp(appId);\n }\n\n async updateAppStatus(appId: string, status: RegisteredAppStatus): Promise<void> {\n await this.requireRelayer().updateAppStatus(appId, status);\n }\n\n async updateAppTrustLevel(appId: string, trustLevel: RegisteredAppTrustLevel): Promise<void> {\n await this.requireRelayer().updateAppTrustLevel(appId, trustLevel);\n }\n\n async listAppSessions(appId: string, options?: { includeRevoked?: boolean }): Promise<RelayerAppSession[]> {\n return this.requireRelayer().listAppSessions(appId, options);\n }\n\n async revokeAppSession(appId: string, sessionId: string): Promise<number> {\n return this.requireRelayer().revokeAppSessions(appId, sessionId);\n }\n\n async revokeAllAppSessions(appId: string): Promise<number> {\n return this.requireRelayer().revokeAppSessions(appId);\n }\n\n private buildChainAddressConfigMap(chainNames?: ChainName[]): Map<number, ChainAddressConfig> {\n const names = chainNames ?? (Object.keys(CHAIN_PRESETS) as ChainName[]);\n const chainConfigs = new Map<number, ChainAddressConfig>();\n\n for (const chainName of names) {\n const preset = CHAIN_PRESETS[chainName];\n const networkConfig = preset[this.network];\n\n chainConfigs.set(networkConfig.wormholeChainId, {\n chainName: preset.displayName,\n isEvm: preset.type === 'evm',\n factoryAddress: networkConfig.contracts?.vaultFactory,\n implementationAddress: networkConfig.contracts?.vaultImplementation,\n });\n }\n\n return chainConfigs;\n }\n}","/**\n * Veridex Protocol SDK — Recovery Manager\n *\n * Orchestrates the full guardian-based social recovery lifecycle on top of the\n * low-level EVMClient methods. Provides a high-level, ergonomic API for:\n *\n * 1. Guardian configuration (setup / add / remove)\n * 2. Recovery initiation (initiateRecovery — called from a guardian device)\n * 3. Approval collection (approveRecovery — each guardian signs)\n * 4. Execution (executeRecovery — permissionless after threshold + timelock)\n * 5. Cancellation (cancelRecovery — by the current owner)\n * 6. Status monitoring (readiness, state, approvals)\n *\n * Design rationale\n * ────────────────\n * • All mutating operations require a WebAuthn signature and an on-chain signer\n * (ethers.Signer). The SDK never holds private-key material — ADR-0040.\n * • The manager delegates on-chain calls to the provided ChainClient, which must\n * implement {@link RecoveryCapableChainClient}. At runtime this is checked via\n * duck-typing so non-EVM chains that lack recovery simply throw clearly.\n * • Cross-chain propagation of recovery results (new-owner VAA) is out of scope\n * for this manager; it is handled by the relayer once the Hub emits the VAA.\n *\n * @module RecoveryManager\n */\n\nimport type { PasskeyManager } from './PasskeyManager.js';\nimport type {\n ChainClient,\n WebAuthnSignature,\n\n} from './types.js';\n\n// ============================================================================\n// Recovery-capable chain detection\n// ============================================================================\n\n/**\n * Subset of ChainClient that supports the guardian / recovery contract surface.\n * EVMClient satisfies this; non-EVM clients currently do not.\n */\nexport interface RecoveryCapableChainClient extends ChainClient {\n getGuardians(identityKeyHash: string): Promise<GuardiansResult>;\n getRecoveryStatus(identityKeyHash: string): Promise<RecoveryStatusResult>;\n hasGuardianApproved(identityKeyHash: string, guardianKeyHash: string): Promise<boolean>;\n setupGuardians(\n signature: WebAuthnSignature,\n publicKeyX: bigint,\n publicKeyY: bigint,\n guardians: string[],\n threshold: bigint,\n signer: unknown,\n ): Promise<{ receipt: unknown; sequence: bigint }>;\n addGuardian(\n signature: WebAuthnSignature,\n publicKeyX: bigint,\n publicKeyY: bigint,\n guardianKeyHash: string,\n signer: unknown,\n ): Promise<{ receipt: unknown; sequence: bigint }>;\n removeGuardian(\n signature: WebAuthnSignature,\n publicKeyX: bigint,\n publicKeyY: bigint,\n guardianKeyHash: string,\n signer: unknown,\n ): Promise<{ receipt: unknown; sequence: bigint }>;\n initiateRecovery(\n signature: WebAuthnSignature,\n publicKeyX: bigint,\n publicKeyY: bigint,\n identityToRecover: string,\n newOwnerKeyHash: string,\n signer: unknown,\n ): Promise<{ receipt: unknown; sequence: bigint }>;\n approveRecovery(\n signature: WebAuthnSignature,\n publicKeyX: bigint,\n publicKeyY: bigint,\n identityToRecover: string,\n signer: unknown,\n ): Promise<{ receipt: unknown; sequence: bigint }>;\n executeRecovery(\n identityToRecover: string,\n newPublicKeyX: bigint,\n newPublicKeyY: bigint,\n signer: unknown,\n ): Promise<{ receipt: unknown; sequence: bigint }>;\n cancelRecovery(\n signature: WebAuthnSignature,\n publicKeyX: bigint,\n publicKeyY: bigint,\n signer: unknown,\n ): Promise<{ receipt: unknown; sequence: bigint }>;\n}\n\n// ============================================================================\n// Public types\n// ============================================================================\n\nexport interface GuardiansResult {\n guardians: string[];\n threshold: bigint;\n isConfigured: boolean;\n}\n\nexport interface RecoveryStatusResult {\n isActive: boolean;\n newOwnerKeyHash: string;\n initiatedAt: bigint;\n approvalCount: bigint;\n threshold: bigint;\n canExecuteAt: bigint;\n expiresAt: bigint;\n}\n\nexport interface RecoveryReadiness {\n /** Whether at least one guardian is configured */\n guardiansConfigured: boolean;\n /** Number of guardians */\n guardianCount: number;\n /** Required approval count */\n threshold: bigint;\n /** Whether a recovery is currently in progress */\n recoveryInProgress: boolean;\n /** If in progress, whether it can be executed now */\n canExecuteNow: boolean;\n /** If in progress, whether it has expired */\n isExpired: boolean;\n /** If in progress, how many more approvals are needed (0 when ready) */\n approvalsRemaining: number;\n /** Full recovery status if active */\n recoveryStatus: RecoveryStatusResult | null;\n /** List of guardian key hashes */\n guardians: string[];\n}\n\nexport interface SetupGuardiansParams {\n /** WebAuthn assertion for the operation */\n signature: WebAuthnSignature;\n /** Guardian key hashes to set */\n guardians: string[];\n /** Approval threshold (must be >= 1 and <= guardians.length) */\n threshold: number;\n /** Ethers signer to submit the transaction */\n signer: unknown;\n}\n\nexport interface AddGuardianParams {\n signature: WebAuthnSignature;\n guardianKeyHash: string;\n signer: unknown;\n}\n\nexport interface RemoveGuardianParams {\n signature: WebAuthnSignature;\n guardianKeyHash: string;\n signer: unknown;\n}\n\nexport interface InitiateRecoveryParams {\n signature: WebAuthnSignature;\n /** Identity key hash to recover */\n identityToRecover: string;\n /** New owner key hash that will replace the old one */\n newOwnerKeyHash: string;\n signer: unknown;\n}\n\nexport interface ApproveRecoveryParams {\n signature: WebAuthnSignature;\n identityToRecover: string;\n signer: unknown;\n}\n\nexport interface ExecuteRecoveryParams {\n identityToRecover: string;\n /** The new owner's P-256 public key X coordinate */\n newPublicKeyX: bigint;\n /** The new owner's P-256 public key Y coordinate */\n newPublicKeyY: bigint;\n signer: unknown;\n}\n\nexport interface CancelRecoveryParams {\n signature: WebAuthnSignature;\n signer: unknown;\n}\n\nexport interface RecoveryManagerConfig {\n passkey: PasskeyManager;\n chain: ChainClient;\n}\n\n// ============================================================================\n// RecoveryManager\n// ============================================================================\n\nexport class RecoveryManager {\n private readonly passkey: PasskeyManager;\n private readonly chain: RecoveryCapableChainClient;\n\n constructor(config: RecoveryManagerConfig) {\n this.passkey = config.passkey;\n\n if (!isRecoveryCapable(config.chain)) {\n throw new Error(\n 'RecoveryManager requires a chain client that supports guardian and recovery methods. ' +\n 'Currently only EVMClient implements RecoveryCapableChainClient.',\n );\n }\n this.chain = config.chain;\n }\n\n // ────────────────────────────────────────────────────────────────────────\n // Queries\n // ────────────────────────────────────────────────────────────────────────\n\n /**\n * Get full recovery readiness — combines guardian config and recovery state\n * into a single, user-friendly view.\n */\n async getReadiness(identityKeyHash?: string): Promise<RecoveryReadiness> {\n const keyHash = identityKeyHash ?? this.requireCredential().keyHash;\n\n const [guardians, status] = await Promise.all([\n this.chain.getGuardians(keyHash),\n this.chain.getRecoveryStatus(keyHash),\n ]);\n\n const nowSec = BigInt(Math.floor(Date.now() / 1000));\n const canExecuteNow = status.isActive\n && status.approvalCount >= status.threshold\n && nowSec >= status.canExecuteAt\n && nowSec < status.expiresAt;\n const isExpired = status.isActive && nowSec >= status.expiresAt;\n const approvalsRemaining = status.isActive\n ? Math.max(0, Number(status.threshold - status.approvalCount))\n : 0;\n\n return {\n guardiansConfigured: guardians.isConfigured,\n guardianCount: guardians.guardians.length,\n threshold: guardians.threshold,\n recoveryInProgress: status.isActive,\n canExecuteNow,\n isExpired,\n approvalsRemaining,\n recoveryStatus: status.isActive ? status : null,\n guardians: guardians.guardians,\n };\n }\n\n /**\n * Check whether a specific guardian has already approved the active recovery.\n */\n async hasGuardianApproved(\n identityKeyHash: string,\n guardianKeyHash: string,\n ): Promise<boolean> {\n return this.chain.hasGuardianApproved(identityKeyHash, guardianKeyHash);\n }\n\n /**\n * Get the raw guardian configuration for a given identity.\n */\n async getGuardians(identityKeyHash?: string): Promise<GuardiansResult> {\n const keyHash = identityKeyHash ?? this.requireCredential().keyHash;\n return this.chain.getGuardians(keyHash);\n }\n\n /**\n * Get the raw recovery status for a given identity.\n */\n async getRecoveryStatus(identityKeyHash?: string): Promise<RecoveryStatusResult> {\n const keyHash = identityKeyHash ?? this.requireCredential().keyHash;\n return this.chain.getRecoveryStatus(keyHash);\n }\n\n // ────────────────────────────────────────────────────────────────────────\n // Mutations\n // ────────────────────────────────────────────────────────────────────────\n\n /**\n * Configure the guardian set and approval threshold for the current identity.\n *\n * @throws If threshold < 1 or threshold > guardians.length\n */\n async setupGuardians(params: SetupGuardiansParams): Promise<{ sequence: bigint }> {\n const { signature, guardians, threshold, signer } = params;\n\n if (threshold < 1 || threshold > guardians.length) {\n throw new Error(\n `Invalid threshold ${threshold}: must be between 1 and ${guardians.length} (guardian count).`,\n );\n }\n\n const credential = this.requireCredential();\n const result = await this.chain.setupGuardians(\n signature,\n credential.publicKeyX,\n credential.publicKeyY,\n guardians,\n BigInt(threshold),\n signer,\n );\n return { sequence: result.sequence };\n }\n\n /**\n * Add a single guardian to the current identity's guardian set.\n */\n async addGuardian(params: AddGuardianParams): Promise<{ sequence: bigint }> {\n const credential = this.requireCredential();\n const result = await this.chain.addGuardian(\n params.signature,\n credential.publicKeyX,\n credential.publicKeyY,\n params.guardianKeyHash,\n params.signer,\n );\n return { sequence: result.sequence };\n }\n\n /**\n * Remove a guardian from the current identity's guardian set.\n */\n async removeGuardian(params: RemoveGuardianParams): Promise<{ sequence: bigint }> {\n const credential = this.requireCredential();\n const result = await this.chain.removeGuardian(\n params.signature,\n credential.publicKeyX,\n credential.publicKeyY,\n params.guardianKeyHash,\n params.signer,\n );\n return { sequence: result.sequence };\n }\n\n /**\n * Initiate social recovery — typically called from a guardian's device.\n *\n * The caller must be a guardian of the identity being recovered.\n */\n async initiateRecovery(params: InitiateRecoveryParams): Promise<{ sequence: bigint }> {\n const credential = this.requireCredential();\n const result = await this.chain.initiateRecovery(\n params.signature,\n credential.publicKeyX,\n credential.publicKeyY,\n params.identityToRecover,\n params.newOwnerKeyHash,\n params.signer,\n );\n return { sequence: result.sequence };\n }\n\n /**\n * Approve an in-progress recovery — each guardian calls this once.\n */\n async approveRecovery(params: ApproveRecoveryParams): Promise<{ sequence: bigint }> {\n const credential = this.requireCredential();\n const result = await this.chain.approveRecovery(\n params.signature,\n credential.publicKeyX,\n credential.publicKeyY,\n params.identityToRecover,\n params.signer,\n );\n return { sequence: result.sequence };\n }\n\n /**\n * Execute a recovery after threshold + timelock are satisfied.\n *\n * This is permissionless — anyone may call it. No WebAuthn signature required.\n */\n async executeRecovery(params: ExecuteRecoveryParams): Promise<{ sequence: bigint }> {\n const result = await this.chain.executeRecovery(\n params.identityToRecover,\n params.newPublicKeyX,\n params.newPublicKeyY,\n params.signer,\n );\n return { sequence: result.sequence };\n }\n\n /**\n * Cancel an in-progress recovery — only the current owner can do this.\n */\n async cancelRecovery(params: CancelRecoveryParams): Promise<{ sequence: bigint }> {\n const credential = this.requireCredential();\n const result = await this.chain.cancelRecovery(\n params.signature,\n credential.publicKeyX,\n credential.publicKeyY,\n params.signer,\n );\n return { sequence: result.sequence };\n }\n\n // ────────────────────────────────────────────────────────────────────────\n // Internal helpers\n // ────────────────────────────────────────────────────────────────────────\n\n private requireCredential() {\n const credential = this.passkey.getCredential();\n if (!credential) {\n throw new Error(\n 'No credential set. Call passkey.register() or passkey.authenticate() first.',\n );\n }\n return credential;\n }\n}\n\n// ============================================================================\n// Runtime type guard\n// ============================================================================\n\nfunction isRecoveryCapable(chain: ChainClient): chain is RecoveryCapableChainClient {\n const c = chain as Partial<RecoveryCapableChainClient>;\n return (\n typeof c.getGuardians === 'function' &&\n typeof c.getRecoveryStatus === 'function' &&\n typeof c.hasGuardianApproved === 'function' &&\n typeof c.setupGuardians === 'function' &&\n typeof c.initiateRecovery === 'function' &&\n typeof c.approveRecovery === 'function' &&\n typeof c.executeRecovery === 'function' &&\n typeof c.cancelRecovery === 'function'\n );\n}\n","/**\n * Veridex Protocol SDK — Multisig Manager (ADR-0037)\n *\n * Implements the SDK surface for **threshold multisig transaction authorization**.\n *\n * Architecture summary (from ADR-0037):\n * ─────────────────────────────────────\n * • A per-identity **TransactionPolicy** on the Hub defines whether threshold\n * approval is required. When `policy.enabled === true`, direct dispatch of\n * protected actions (transfer, execute, bridge, config) reverts on-chain.\n * • Instead, an authorized key **creates a proposal**. Other authorized keys\n * **approve** it. Once `approvalCount >= threshold`, anyone may **execute** it.\n * • Sessions are disabled for threshold-governed identities in Phase 1.\n * • Proposals expire after `proposalTtl`.\n * • Execution emits a Wormhole VAA wrapping the inner action\n * (ACTION_EXECUTE_MULTISIG = 14).\n *\n * This manager exposes:\n * 1. Policy configuration & queries\n * 2. Proposal lifecycle (create / approve / cancel / execute / query)\n * 3. Convenience proposal creators for transfer, execute, bridge\n * 4. Policy-aware guard for direct dispatch (`assertDirectDispatchAllowed`)\n *\n * @module MultisigManager\n */\n\nimport type { PasskeyManager } from './PasskeyManager.js';\nimport type {\n ChainClient,\n WebAuthnSignature,\n TransferParams,\n ExecuteParams,\n BridgeParams,\n DispatchResult,\n} from './types.js';\n\n// ============================================================================\n// Multisig types (ADR-0037 §3, §4, §11)\n// ============================================================================\n\n/** Phase 1 action type bitmask values (ADR-0037 §2) */\nexport const PROTECTED_ACTION = {\n TRANSFER: 1 << 0,\n EXECUTE: 1 << 1,\n BRIDGE: 1 << 2,\n CONFIG: 1 << 3,\n} as const;\n\n/** Default protected-action mask covering all sensitive operations */\nexport const DEFAULT_PROTECTED_ACTION_MASK =\n PROTECTED_ACTION.TRANSFER |\n PROTECTED_ACTION.EXECUTE |\n PROTECTED_ACTION.BRIDGE |\n PROTECTED_ACTION.CONFIG;\n\n/** Default proposal TTL in seconds (24 hours) */\nexport const DEFAULT_PROPOSAL_TTL = 86_400;\n\nexport type ProposalState =\n | 'none'\n | 'pending'\n | 'approved'\n | 'executed'\n | 'cancelled'\n | 'expired';\n\n/**\n * Per-identity transaction policy stored on-chain (Hub).\n */\nexport interface MultisigPolicy {\n enabled: boolean;\n threshold: number;\n protectedActionMask: number;\n proposalTtl: number;\n disableSessions: boolean;\n}\n\n/**\n * On-chain transaction proposal.\n */\nexport interface TransactionProposal {\n proposalId: string;\n identityKeyHash: string;\n proposerKeyHash: string;\n targetChain: number;\n actionType: number;\n actionHash: string;\n actionPayload: string;\n createdAt: bigint;\n expiresAt: bigint;\n approvalCount: number;\n requiredThreshold: number;\n state: ProposalState;\n}\n\n/**\n * Human-readable summary of a proposal's action payload.\n */\nexport interface ProposalActionSummary {\n type: 'transfer' | 'execute' | 'bridge' | 'config' | 'unknown';\n description: string;\n targetChain: number;\n /** Decoded parameters — shape depends on `type` */\n params: TransferParams | ExecuteParams | BridgeParams | Record<string, unknown>;\n}\n\nexport interface CreateProposalResult {\n proposalId: string;\n sequence: bigint;\n summary: ProposalActionSummary;\n}\n\nexport interface ApproveProposalResult {\n proposalId: string;\n approvalCount: number;\n thresholdReached: boolean;\n}\n\nexport interface ExecuteProposalResult {\n proposalId: string;\n sequence: bigint;\n dispatch: DispatchResult;\n}\n\n// ============================================================================\n// Multisig-capable chain detection\n// ============================================================================\n\n/**\n * Chain client methods required for threshold multisig.\n * In Phase 1 these exist only on EVMClient (Hub chain).\n */\nexport interface MultisigCapableChainClient extends ChainClient {\n configureTransactionPolicy(\n signature: WebAuthnSignature,\n publicKeyX: bigint,\n publicKeyY: bigint,\n threshold: number,\n protectedActionMask: number,\n proposalTtl: number,\n disableSessions: boolean,\n signer: unknown,\n ): Promise<{ receipt: unknown }>;\n\n getTransactionPolicy(identityKeyHash: string): Promise<MultisigPolicy>;\n\n createTransactionProposal(\n signature: WebAuthnSignature,\n publicKeyX: bigint,\n publicKeyY: bigint,\n targetChain: number,\n actionPayload: string,\n signer: unknown,\n ): Promise<{ proposalId: string; receipt: unknown; sequence: bigint }>;\n\n approveTransactionProposal(\n signature: WebAuthnSignature,\n publicKeyX: bigint,\n publicKeyY: bigint,\n proposalId: string,\n signer: unknown,\n ): Promise<{ receipt: unknown; approvalCount: number; thresholdReached: boolean }>;\n\n cancelTransactionProposal(\n signature: WebAuthnSignature,\n publicKeyX: bigint,\n publicKeyY: bigint,\n proposalId: string,\n signer: unknown,\n ): Promise<{ receipt: unknown }>;\n\n executeTransactionProposal(\n proposalId: string,\n signer: unknown,\n ): Promise<{ receipt: unknown; sequence: bigint }>;\n\n getTransactionProposal(proposalId: string): Promise<TransactionProposal>;\n\n hasApprovedTransactionProposal(\n proposalId: string,\n keyHash: string,\n ): Promise<boolean>;\n}\n\n// ============================================================================\n// Configuration\n// ============================================================================\n\nexport interface MultisigManagerConfig {\n passkey: PasskeyManager;\n chain: ChainClient;\n}\n\nexport interface ConfigurePolicyParams {\n signature: WebAuthnSignature;\n threshold: number;\n protectedActionMask?: number;\n proposalTtl?: number;\n disableSessions?: boolean;\n signer: unknown;\n}\n\nexport interface CreateProposalParams {\n signature: WebAuthnSignature;\n targetChain: number;\n actionPayload: string;\n signer: unknown;\n}\n\nexport interface ApproveProposalParams {\n signature: WebAuthnSignature;\n proposalId: string;\n signer: unknown;\n}\n\nexport interface CancelProposalParams {\n signature: WebAuthnSignature;\n proposalId: string;\n signer: unknown;\n}\n\nexport interface ExecuteProposalParams {\n proposalId: string;\n signer: unknown;\n}\n\n// ============================================================================\n// MultisigManager\n// ============================================================================\n\nexport class MultisigManager {\n private readonly passkey: PasskeyManager;\n private readonly chain: MultisigCapableChainClient;\n\n constructor(config: MultisigManagerConfig) {\n this.passkey = config.passkey;\n\n if (!isMultisigCapable(config.chain)) {\n throw new Error(\n 'MultisigManager requires a chain client that supports threshold multisig. ' +\n 'Ensure your EVMClient implements the ADR-0037 contract extensions.',\n );\n }\n this.chain = config.chain;\n }\n\n // ────────────────────────────────────────────────────────────────────────\n // Policy\n // ────────────────────────────────────────────────────────────────────────\n\n /**\n * Query the current transaction policy for the active identity.\n */\n async getPolicy(identityKeyHash?: string): Promise<MultisigPolicy> {\n const keyHash = identityKeyHash ?? this.requireCredential().keyHash;\n return this.chain.getTransactionPolicy(keyHash);\n }\n\n /**\n * Configure (or update) the transaction policy for the current identity.\n *\n * @throws If threshold < 2\n */\n async configurePolicy(params: ConfigurePolicyParams): Promise<void> {\n const { signature, threshold, signer } = params;\n const protectedActionMask = params.protectedActionMask ?? DEFAULT_PROTECTED_ACTION_MASK;\n const proposalTtl = params.proposalTtl ?? DEFAULT_PROPOSAL_TTL;\n const disableSessions = params.disableSessions ?? true;\n\n if (threshold < 2) {\n throw new Error(\n `Threshold must be >= 2 for multisig policy. Got ${threshold}.`,\n );\n }\n\n const credential = this.requireCredential();\n await this.chain.configureTransactionPolicy(\n signature,\n credential.publicKeyX,\n credential.publicKeyY,\n threshold,\n protectedActionMask,\n proposalTtl,\n disableSessions,\n signer,\n );\n }\n\n /**\n * Check whether direct (single-signer) dispatch is allowed for the given\n * action type under the current policy. Throws a descriptive error when\n * threshold approval is required instead.\n *\n * Call this before `sdk.transfer()` / `sdk.execute()` / `sdk.bridge()`\n * to fail fast in the SDK rather than reverting on-chain.\n */\n async assertDirectDispatchAllowed(\n actionType: 'transfer' | 'execute' | 'bridge' | 'config',\n identityKeyHash?: string,\n ): Promise<void> {\n const keyHash = identityKeyHash ?? this.requireCredential().keyHash;\n const policy = await this.chain.getTransactionPolicy(keyHash);\n\n if (!policy.enabled) return; // single-signer is fine\n\n const bit = actionTypeToBit(actionType);\n if ((policy.protectedActionMask & bit) !== 0) {\n throw new Error(\n `Direct dispatch of \"${actionType}\" is not allowed: identity ${keyHash} ` +\n `requires threshold multisig approval (threshold=${policy.threshold}). ` +\n 'Use sdk.multisig.createProposal() instead.',\n );\n }\n }\n\n // ────────────────────────────────────────────────────────────────────────\n // Proposal lifecycle\n // ────────────────────────────────────────────────────────────────────────\n\n /**\n * Create a new transaction proposal.\n *\n * The proposer's signature counts as the first approval automatically.\n */\n async createProposal(params: CreateProposalParams): Promise<CreateProposalResult> {\n const credential = this.requireCredential();\n const result = await this.chain.createTransactionProposal(\n params.signature,\n credential.publicKeyX,\n credential.publicKeyY,\n params.targetChain,\n params.actionPayload,\n params.signer,\n );\n\n const summary = decodeActionSummary(params.targetChain, params.actionPayload);\n\n return {\n proposalId: result.proposalId,\n sequence: result.sequence,\n summary,\n };\n }\n\n /**\n * Approve an existing proposal. Each authorized key may approve once.\n */\n async approveProposal(params: ApproveProposalParams): Promise<ApproveProposalResult> {\n const credential = this.requireCredential();\n const result = await this.chain.approveTransactionProposal(\n params.signature,\n credential.publicKeyX,\n credential.publicKeyY,\n params.proposalId,\n params.signer,\n );\n return {\n proposalId: params.proposalId,\n approvalCount: result.approvalCount,\n thresholdReached: result.thresholdReached,\n };\n }\n\n /**\n * Cancel a proposal — only allowed by an authorized key of the identity.\n */\n async cancelProposal(params: CancelProposalParams): Promise<void> {\n const credential = this.requireCredential();\n await this.chain.cancelTransactionProposal(\n params.signature,\n credential.publicKeyX,\n credential.publicKeyY,\n params.proposalId,\n params.signer,\n );\n }\n\n /**\n * Execute a proposal after threshold + timelock are satisfied.\n * Permissionless — anyone may call.\n */\n async executeProposal(params: ExecuteProposalParams): Promise<ExecuteProposalResult> {\n const result = await this.chain.executeTransactionProposal(\n params.proposalId,\n params.signer,\n );\n return {\n proposalId: params.proposalId,\n sequence: result.sequence,\n dispatch: {\n transactionHash: '', // filled by chain client\n sequence: result.sequence,\n userKeyHash: '',\n targetChain: 0,\n },\n };\n }\n\n // ────────────────────────────────────────────────────────────────────────\n // Queries\n // ────────────────────────────────────────────────────────────────────────\n\n /**\n * Retrieve a proposal by ID.\n */\n async getProposal(proposalId: string): Promise<TransactionProposal> {\n return this.chain.getTransactionProposal(proposalId);\n }\n\n /**\n * Check whether a specific key has approved a given proposal.\n */\n async hasApproved(proposalId: string, keyHash?: string): Promise<boolean> {\n const resolvedKeyHash = keyHash ?? this.requireCredential().keyHash;\n return this.chain.hasApprovedTransactionProposal(proposalId, resolvedKeyHash);\n }\n\n /**\n * Convenience: check if a proposal is ready for execution.\n */\n async isProposalExecutable(proposalId: string): Promise<boolean> {\n const proposal = await this.getProposal(proposalId);\n if (proposal.state !== 'pending' && proposal.state !== 'approved') return false;\n\n const nowSec = BigInt(Math.floor(Date.now() / 1000));\n return (\n proposal.approvalCount >= proposal.requiredThreshold &&\n nowSec < proposal.expiresAt\n );\n }\n\n // ────────────────────────────────────────────────────────────────────────\n // Internal\n // ────────────────────────────────────────────────────────────────────────\n\n private requireCredential() {\n const credential = this.passkey.getCredential();\n if (!credential) {\n throw new Error(\n 'No credential set. Call passkey.register() or passkey.authenticate() first.',\n );\n }\n return credential;\n }\n}\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\nfunction isMultisigCapable(chain: ChainClient): chain is MultisigCapableChainClient {\n const c = chain as Partial<MultisigCapableChainClient>;\n return (\n typeof c.configureTransactionPolicy === 'function' &&\n typeof c.getTransactionPolicy === 'function' &&\n typeof c.createTransactionProposal === 'function' &&\n typeof c.approveTransactionProposal === 'function' &&\n typeof c.cancelTransactionProposal === 'function' &&\n typeof c.executeTransactionProposal === 'function' &&\n typeof c.getTransactionProposal === 'function' &&\n typeof c.hasApprovedTransactionProposal === 'function'\n );\n}\n\nfunction actionTypeToBit(type: 'transfer' | 'execute' | 'bridge' | 'config'): number {\n switch (type) {\n case 'transfer': return PROTECTED_ACTION.TRANSFER;\n case 'execute': return PROTECTED_ACTION.EXECUTE;\n case 'bridge': return PROTECTED_ACTION.BRIDGE;\n case 'config': return PROTECTED_ACTION.CONFIG;\n }\n}\n\n/**\n * Best-effort decode of an action payload for human-readable display.\n * Falls back to an opaque summary if decoding fails.\n */\nfunction decodeActionSummary(targetChain: number, actionPayload: string): ProposalActionSummary {\n // Action payloads are ABI-encoded with a leading action-type byte.\n // We attempt a lightweight decode here; full parsing is done by\n // TransactionParser if the integrator wants richer display.\n try {\n const bytes = hexToBytes(actionPayload);\n if (bytes.length === 0) {\n return { type: 'unknown', description: 'Empty payload', targetChain, params: {} };\n }\n\n const actionByte = bytes[0];\n switch (actionByte) {\n case 1: return { type: 'transfer', description: 'Token transfer', targetChain, params: {} as TransferParams };\n case 2: return { type: 'execute', description: 'Contract execution', targetChain, params: {} as ExecuteParams };\n case 3: return { type: 'bridge', description: 'Cross-chain bridge', targetChain, params: {} as BridgeParams };\n case 4: return { type: 'config', description: 'Configuration change', targetChain, params: {} };\n default: return { type: 'unknown', description: `Action type ${actionByte}`, targetChain, params: {} };\n }\n } catch {\n return { type: 'unknown', description: 'Unable to decode payload', targetChain, params: {} };\n }\n}\n\nfunction hexToBytes(hex: string): Uint8Array {\n const clean = hex.startsWith('0x') ? hex.slice(2) : hex;\n if (clean.length === 0) return new Uint8Array(0);\n const bytes = new Uint8Array(clean.length / 2);\n for (let i = 0; i < bytes.length; i++) {\n bytes[i] = parseInt(clean.substring(i * 2, i * 2 + 2), 16);\n }\n return bytes;\n}\n","/**\n * Veridex Protocol SDK — Launch Gate & Policy Enforcement (ADR-0040)\n *\n * Runtime validation layer that enforces the product boundaries defined in\n * ADR-0040 across the SDK surface. Every SDK operation that touches\n * credentials, sessions, or dispatch is funnelled through this module's\n * `validate*` helpers to catch violations early with clear developer errors.\n *\n * Non-negotiables enforced here:\n *\n * 1. Passkeys are non-extractable. No API may expose private-key material.\n * 2. Self-custody is preserved. The SDK never constructs or transmits\n * private keys.\n * 3. Cross-site passkey reuse is scoped to the Veridex RP federation model.\n * 4. Cross-ecosystem portability requires explicit credential registration.\n * 5. MetaMask interop is limited to smart-account / injected-wallet flows.\n * 6. Chain parity claims require real cryptographic verification.\n *\n * Additionally this module exposes a lightweight **CapabilityMatrix** that\n * integrators can use to understand what is available on a given platform,\n * browser, and chain combination — preventing false assumptions at the UI\n * level.\n *\n * @module PolicyEnforcement\n */\n\n// ============================================================================\n// Product boundary constants\n// ============================================================================\n\n/**\n * Capability tiers per chain type — used to gate SDK features at runtime.\n */\nexport type ChainCapabilityTier = 'full' | 'partial' | 'unsupported';\n\nexport interface ChainCapabilities {\n /** WebAuthn P-256 verification on-chain */\n passkeyVerification: ChainCapabilityTier;\n /** On-chain session key registration and validation */\n sessionKeys: ChainCapabilityTier;\n /** Guardian recovery initiation, approval, execution */\n recovery: ChainCapabilityTier;\n /** Threshold multisig (ADR-0037) */\n multisig: ChainCapabilityTier;\n /** Cross-chain VAA reception (Wormhole spoke) */\n crossChainReceive: ChainCapabilityTier;\n}\n\n/**\n * Canonical capability definitions per chain type.\n * These are validated before claiming \"supported\" status.\n */\nexport const CHAIN_CAPABILITIES: Record<string, ChainCapabilities> = {\n evm: {\n passkeyVerification: 'full',\n sessionKeys: 'full',\n recovery: 'full',\n multisig: 'full',\n crossChainReceive: 'full',\n },\n avalanche: {\n passkeyVerification: 'full', // ACP-204 native P-256\n sessionKeys: 'full',\n recovery: 'full',\n multisig: 'full',\n crossChainReceive: 'full',\n },\n solana: {\n passkeyVerification: 'partial', // via precompile / verifier program\n sessionKeys: 'partial',\n recovery: 'unsupported',\n multisig: 'unsupported',\n crossChainReceive: 'full',\n },\n aptos: {\n passkeyVerification: 'partial',\n sessionKeys: 'partial',\n recovery: 'unsupported',\n multisig: 'unsupported',\n crossChainReceive: 'full',\n },\n sui: {\n passkeyVerification: 'partial',\n sessionKeys: 'partial',\n recovery: 'unsupported',\n multisig: 'unsupported',\n crossChainReceive: 'full',\n },\n starknet: {\n passkeyVerification: 'partial',\n sessionKeys: 'unsupported',\n recovery: 'unsupported',\n multisig: 'unsupported',\n crossChainReceive: 'partial',\n },\n stacks: {\n passkeyVerification: 'partial',\n sessionKeys: 'partial',\n recovery: 'unsupported',\n multisig: 'unsupported',\n crossChainReceive: 'partial',\n },\n};\n\n// ============================================================================\n// Validation helpers\n// ============================================================================\n\n/**\n * Prevent any code path that would attempt to export or derive private keys\n * from passkey material (ADR-0040, Non-Negotiable #1).\n */\nexport function validateNoKeyExtraction(operation: string): void {\n const forbidden = [\n 'exportPrivateKey', 'derivePrivateKey', 'getMnemonic',\n 'getSeedPhrase', 'getKeystore', 'extractKey',\n 'exportSeed', 'deriveSeed', 'getEntropy',\n ];\n const lower = operation.toLowerCase();\n for (const keyword of forbidden) {\n if (lower.includes(keyword.toLowerCase())) {\n throw new PolicyViolationError(\n `Operation \"${operation}\" violates Veridex security policy: ` +\n 'passkey credentials are non-extractable WebAuthn keys and cannot be ' +\n 'exported as private keys, mnemonics, or keystore files.',\n 'NON_EXTRACTABLE_CREDENTIAL',\n );\n }\n }\n}\n\n/**\n * Validate that a chain has real (not placeholder) support for a capability\n * before claiming it is available (ADR-0040, Non-Negotiable #6).\n */\nexport function validateChainCapability(\n chainType: string,\n capability: keyof ChainCapabilities,\n operation: string,\n): void {\n const caps = CHAIN_CAPABILITIES[chainType];\n if (!caps) {\n throw new PolicyViolationError(\n `Unknown chain type \"${chainType}\" — cannot validate capability \"${capability}\" ` +\n `for operation \"${operation}\".`,\n 'UNKNOWN_CHAIN_TYPE',\n );\n }\n\n const tier = caps[capability];\n if (tier === 'unsupported') {\n throw new PolicyViolationError(\n `Chain type \"${chainType}\" does not support \"${capability}\". ` +\n `Operation \"${operation}\" is not available on this chain.`,\n 'UNSUPPORTED_CAPABILITY',\n );\n }\n}\n\n/**\n * Validate that MetaMask interop claims are limited to the smart-account\n * execution path (ADR-0040, Non-Negotiable #5).\n */\nexport function validateMetaMaskInteropClaim(interopType: string): void {\n const allowed = [\n 'injected-wallet',\n 'smart-account-control',\n 'session-key-delegation',\n 'companion-wallet',\n 'funding-deposit',\n ];\n if (!allowed.includes(interopType)) {\n throw new PolicyViolationError(\n `MetaMask interop type \"${interopType}\" is not supported. ` +\n `Allowed types: ${allowed.join(', ')}. ` +\n 'Native passkey import into MetaMask is not yet available.',\n 'UNSUPPORTED_METAMASK_INTEROP',\n );\n }\n}\n\n/**\n * Validate that session creation is allowed for the given identity's\n * multisig policy state (ADR-0037 §9).\n */\nexport function validateSessionCreationPolicy(\n policyEnabled: boolean,\n sessionsDisabled: boolean,\n): void {\n if (policyEnabled && sessionsDisabled) {\n throw new PolicyViolationError(\n 'Session key creation is disabled for this identity because a threshold ' +\n 'multisig policy is active with disableSessions=true. ' +\n 'Use the proposal workflow instead.',\n 'SESSIONS_DISABLED_BY_POLICY',\n );\n }\n}\n\n/**\n * Validate that cross-site passkey reuse is within the Veridex federation\n * model (ADR-0040, Non-Negotiable #3).\n */\nexport function validateFederatedOrigin(\n rpId: string,\n allowedRpIds: string[] = ['veridex.network'],\n): void {\n const isAllowed = allowedRpIds.some(\n allowed => rpId === allowed || rpId.endsWith('.' + allowed),\n );\n if (!isAllowed) {\n throw new PolicyViolationError(\n `Origin RP ID \"${rpId}\" is not part of the Veridex federation model. ` +\n 'Cross-site passkey reuse requires federation via Related Origin Requests ' +\n 'or the Auth Portal fallback.',\n 'UNFEDERATED_ORIGIN',\n );\n }\n}\n\n// ============================================================================\n// Capability matrix for integrator UX\n// ============================================================================\n\nexport interface PlatformCapabilityMatrix {\n /** Whether passkeys (WebAuthn) are supported on this platform */\n webauthnSupported: boolean;\n /** Whether conditional UI (autofill) is available */\n conditionalUISupported: boolean;\n /** Whether platform authenticators are available (Touch ID, Face ID, etc.) */\n platformAuthenticatorAvailable: boolean;\n /** Chain-specific capabilities */\n chainCapabilities: ChainCapabilities;\n /** Feature set available for the current configuration */\n features: {\n passkeyAuth: boolean;\n sessionKeys: boolean;\n socialRecovery: boolean;\n thresholdMultisig: boolean;\n crossChainBridge: boolean;\n injectedWalletInterop: boolean;\n gaslessTransactions: boolean;\n };\n}\n\n/**\n * Build a capability matrix for the current platform and chain configuration.\n * Used by integrator UIs to show/hide features appropriately.\n */\nexport function buildCapabilityMatrix(\n chainType: string,\n platformInfo: {\n webauthnSupported: boolean;\n conditionalUISupported: boolean;\n platformAuthenticatorAvailable: boolean;\n },\n hasRelayer: boolean,\n): PlatformCapabilityMatrix {\n const caps = CHAIN_CAPABILITIES[chainType] ?? CHAIN_CAPABILITIES['evm']!;\n\n return {\n webauthnSupported: platformInfo.webauthnSupported,\n conditionalUISupported: platformInfo.conditionalUISupported,\n platformAuthenticatorAvailable: platformInfo.platformAuthenticatorAvailable,\n chainCapabilities: caps,\n features: {\n passkeyAuth: platformInfo.webauthnSupported && caps.passkeyVerification !== 'unsupported',\n sessionKeys: caps.sessionKeys === 'full',\n socialRecovery: caps.recovery === 'full',\n thresholdMultisig: caps.multisig === 'full',\n crossChainBridge: caps.crossChainReceive !== 'unsupported',\n injectedWalletInterop: typeof globalThis !== 'undefined' && 'ethereum' in (globalThis as Record<string, unknown>),\n gaslessTransactions: hasRelayer,\n },\n };\n}\n\n// ============================================================================\n// Error type\n// ============================================================================\n\nexport type PolicyViolationCode =\n | 'NON_EXTRACTABLE_CREDENTIAL'\n | 'UNKNOWN_CHAIN_TYPE'\n | 'UNSUPPORTED_CAPABILITY'\n | 'UNSUPPORTED_METAMASK_INTEROP'\n | 'SESSIONS_DISABLED_BY_POLICY'\n | 'UNFEDERATED_ORIGIN';\n\nexport class PolicyViolationError extends Error {\n public readonly code: PolicyViolationCode;\n\n constructor(message: string, code: PolicyViolationCode) {\n super(message);\n this.name = 'PolicyViolationError';\n this.code = code;\n }\n}\n","/**\n * Veridex Protocol SDK — Unified Error Normalization\n *\n * Wraps chain-specific errors (ethers, Anchor, Clarity, Starknet felt, etc.)\n * into a single VeridexError class with a unified code, human-readable message,\n * and chain identifier. Integrators can catch `VeridexError` consistently\n * regardless of which chain's SDK surfaced the underlying fault.\n */\n\n// ============================================================================\n// Unified Error Codes\n// ============================================================================\n\n/**\n * Language-agnostic error codes that map consistently across all chains.\n */\nexport enum VeridexErrorCode {\n // Wallet / identity errors\n NO_CREDENTIAL = 'NO_CREDENTIAL',\n UNAUTHORIZED = 'UNAUTHORIZED',\n INVALID_SIGNATURE = 'INVALID_SIGNATURE',\n\n // Vault state errors\n VAULT_NOT_FOUND = 'VAULT_NOT_FOUND',\n VAULT_PAUSED = 'VAULT_PAUSED',\n PROTOCOL_PAUSED = 'PROTOCOL_PAUSED',\n\n // Balance / limits errors\n INSUFFICIENT_FUNDS = 'INSUFFICIENT_FUNDS',\n DAILY_LIMIT_EXCEEDED = 'DAILY_LIMIT_EXCEEDED',\n\n // Payload / dispatch errors\n INVALID_PAYLOAD = 'INVALID_PAYLOAD',\n INVALID_ACTION = 'INVALID_ACTION',\n EXPIRED = 'EXPIRED',\n\n // Cross-chain / Wormhole errors\n VAA_ALREADY_PROCESSED = 'VAA_ALREADY_PROCESSED',\n INVALID_VAA = 'INVALID_VAA',\n INVALID_EMITTER = 'INVALID_EMITTER',\n BRIDGE_ERROR = 'BRIDGE_ERROR',\n\n // Network / RPC errors\n RPC_ERROR = 'RPC_ERROR',\n TIMEOUT = 'TIMEOUT',\n RELAYER_ERROR = 'RELAYER_ERROR',\n\n // Session errors\n SESSION_EXPIRED = 'SESSION_EXPIRED',\n SESSION_INVALID = 'SESSION_INVALID',\n\n // Capability errors\n UNSUPPORTED_FEATURE = 'UNSUPPORTED_FEATURE',\n\n // Catch-all\n UNKNOWN = 'UNKNOWN',\n}\n\n/**\n * Default human-readable messages for each unified error code.\n */\nconst DEFAULT_MESSAGES: Record<VeridexErrorCode, string> = {\n [VeridexErrorCode.NO_CREDENTIAL]: 'No credential set. Call passkey.register() or passkey.setCredential() first.',\n [VeridexErrorCode.UNAUTHORIZED]: 'Unauthorized: the signer is not an owner of this vault.',\n [VeridexErrorCode.INVALID_SIGNATURE]: 'Signature verification failed.',\n [VeridexErrorCode.VAULT_NOT_FOUND]: 'Vault does not exist. Call ensureVault() first.',\n [VeridexErrorCode.VAULT_PAUSED]: 'Vault is paused. Unpause before continuing.',\n [VeridexErrorCode.PROTOCOL_PAUSED]: 'Protocol is paused. Try again later.',\n [VeridexErrorCode.INSUFFICIENT_FUNDS]: 'Insufficient funds in vault.',\n [VeridexErrorCode.DAILY_LIMIT_EXCEEDED]: 'Daily spending limit exceeded. Try a smaller amount or wait for reset.',\n [VeridexErrorCode.INVALID_PAYLOAD]: 'Invalid action payload.',\n [VeridexErrorCode.INVALID_ACTION]: 'Unknown or invalid action type.',\n [VeridexErrorCode.EXPIRED]: 'Prepared transaction has expired. Please prepare again.',\n [VeridexErrorCode.VAA_ALREADY_PROCESSED]: 'This cross-chain message has already been processed (replay protection).',\n [VeridexErrorCode.INVALID_VAA]: 'Invalid VAA: verification failed.',\n [VeridexErrorCode.INVALID_EMITTER]: 'Invalid emitter: message source is not trusted.',\n [VeridexErrorCode.BRIDGE_ERROR]: 'Cross-chain bridge error.',\n [VeridexErrorCode.RPC_ERROR]: 'RPC call failed. The node may be unavailable.',\n [VeridexErrorCode.TIMEOUT]: 'Operation timed out.',\n [VeridexErrorCode.RELAYER_ERROR]: 'Relayer submission failed.',\n [VeridexErrorCode.SESSION_EXPIRED]: 'Session key has expired. Create a new session.',\n [VeridexErrorCode.SESSION_INVALID]: 'Session key is invalid or revoked.',\n [VeridexErrorCode.UNSUPPORTED_FEATURE]: 'This feature is not supported on the current chain.',\n [VeridexErrorCode.UNKNOWN]: 'An unknown error occurred.',\n};\n\n// ============================================================================\n// VeridexError class\n// ============================================================================\n\n/**\n * Unified error class for all Veridex SDK operations.\n *\n * @example\n * ```typescript\n * try {\n * await sdk.executeTransfer(prepared, signer);\n * } catch (err) {\n * if (err instanceof VeridexError) {\n * console.log(err.code); // 'INSUFFICIENT_FUNDS'\n * console.log(err.chain); // 'base'\n * console.log(err.cause); // original ethers error\n * }\n * }\n * ```\n */\nexport class VeridexError extends Error {\n /** Unified error code */\n public readonly code: VeridexErrorCode;\n /** Chain name where the error originated (e.g. 'base', 'solana') */\n public readonly chain: string | undefined;\n /** Original chain-specific error */\n public override readonly cause: unknown;\n /** Whether the operation could succeed if retried */\n public readonly retryable: boolean;\n\n constructor(\n code: VeridexErrorCode,\n message?: string,\n options?: {\n chain?: string;\n cause?: unknown;\n retryable?: boolean;\n },\n ) {\n super(message ?? DEFAULT_MESSAGES[code]);\n this.name = 'VeridexError';\n this.code = code;\n this.chain = options?.chain;\n this.cause = options?.cause;\n this.retryable = options?.retryable ?? RETRYABLE_CODES.has(code);\n }\n}\n\n/** Codes that are inherently retryable (transient failures) */\nconst RETRYABLE_CODES = new Set<VeridexErrorCode>([\n VeridexErrorCode.RPC_ERROR,\n VeridexErrorCode.TIMEOUT,\n VeridexErrorCode.RELAYER_ERROR,\n]);\n\n// ============================================================================\n// Chain-specific error normalization\n// ============================================================================\n\n// Regex / string patterns used to detect common chain errors\nconst EVM_PATTERNS: Array<[RegExp | string, VeridexErrorCode]> = [\n [/insufficient funds/i, VeridexErrorCode.INSUFFICIENT_FUNDS],\n [/execution reverted.*paused/i, VeridexErrorCode.VAULT_PAUSED],\n [/execution reverted.*unauthorized|not\\s*owner/i, VeridexErrorCode.UNAUTHORIZED],\n [/daily.*limit/i, VeridexErrorCode.DAILY_LIMIT_EXCEEDED],\n [/nonce.*expired|nonce.*too\\s*low/i, VeridexErrorCode.EXPIRED],\n [/already.*processed|already\\s*known/i, VeridexErrorCode.VAA_ALREADY_PROCESSED],\n [/invalid.*signature|ECDSA/i, VeridexErrorCode.INVALID_SIGNATURE],\n [/timeout|ETIMEDOUT|ECONNREFUSED/i, VeridexErrorCode.TIMEOUT],\n [/could not detect network|failed to fetch|network/i, VeridexErrorCode.RPC_ERROR],\n];\n\nconst SOLANA_CODE_MAP: Record<number, VeridexErrorCode> = {\n 6000: VeridexErrorCode.PROTOCOL_PAUSED,\n 6001: VeridexErrorCode.VAULT_PAUSED,\n 6002: VeridexErrorCode.VAA_ALREADY_PROCESSED,\n 6003: VeridexErrorCode.INVALID_EMITTER,\n 6004: VeridexErrorCode.INVALID_EMITTER,\n 6005: VeridexErrorCode.UNAUTHORIZED,\n 6006: VeridexErrorCode.BRIDGE_ERROR,\n 6007: VeridexErrorCode.INVALID_PAYLOAD,\n 6008: VeridexErrorCode.INVALID_PAYLOAD,\n 6009: VeridexErrorCode.INVALID_ACTION,\n 6010: VeridexErrorCode.DAILY_LIMIT_EXCEEDED,\n 6011: VeridexErrorCode.INSUFFICIENT_FUNDS,\n 6012: VeridexErrorCode.UNAUTHORIZED,\n 6013: VeridexErrorCode.INVALID_VAA,\n};\n\nconst STARKNET_PATTERNS: Array<[RegExp | string, VeridexErrorCode]> = [\n [/insufficient.*balance|not enough/i, VeridexErrorCode.INSUFFICIENT_FUNDS],\n [/PAUSED|is paused/i, VeridexErrorCode.VAULT_PAUSED],\n [/UNAUTHORIZED|not.*authorized/i, VeridexErrorCode.UNAUTHORIZED],\n [/already.*processed/i, VeridexErrorCode.VAA_ALREADY_PROCESSED],\n [/invalid.*signature/i, VeridexErrorCode.INVALID_SIGNATURE],\n];\n\nconst STACKS_CLARITY_MAP: Record<number, VeridexErrorCode> = {\n 100: VeridexErrorCode.UNAUTHORIZED, // err-unauthorized\n 101: VeridexErrorCode.VAULT_PAUSED, // err-paused\n 102: VeridexErrorCode.INVALID_PAYLOAD, // err-invalid-payload\n 103: VeridexErrorCode.INSUFFICIENT_FUNDS, // err-insufficient-funds\n 104: VeridexErrorCode.DAILY_LIMIT_EXCEEDED, // err-limit-exceeded\n 105: VeridexErrorCode.VAULT_NOT_FOUND, // err-not-found\n 106: VeridexErrorCode.INVALID_SIGNATURE, // err-invalid-signature\n 200: VeridexErrorCode.VAA_ALREADY_PROCESSED, // err-already-processed\n 201: VeridexErrorCode.INVALID_VAA, // err-invalid-vaa\n 202: VeridexErrorCode.INVALID_EMITTER, // err-invalid-emitter\n};\n\n/**\n * Normalize any chain-specific error into a VeridexError.\n *\n * Call this at SDK boundaries (dispatch, balance fetch, vault creation) to\n * give integrators a consistent error surface.\n *\n * @param error - The original error from chain client / RPC / Anchor / etc.\n * @param chain - Chain identifier string (e.g. 'base', 'solana', 'starknet')\n * @returns A VeridexError wrapping the original\n */\nexport function normalizeError(error: unknown, chain?: string): VeridexError {\n // Already normalized\n if (error instanceof VeridexError) {\n return error;\n }\n\n const msg = error instanceof Error ? error.message : String(error);\n\n // --- Solana / Anchor numeric codes ---\n const anchorMatch = msg.match(/custom program error:\\s*0x([0-9a-fA-F]+)/i)\n ?? msg.match(/Error Code:\\s*(\\w+)\\.\\s*Error Number:\\s*(\\d+)/i);\n if (anchorMatch) {\n const code = anchorMatch[2]\n ? parseInt(anchorMatch[2], 10)\n : parseInt(anchorMatch[1], 16);\n const mapped = SOLANA_CODE_MAP[code];\n if (mapped) {\n return new VeridexError(mapped, undefined, { chain: chain ?? 'solana', cause: error });\n }\n }\n\n // --- Stacks Clarity error codes ---\n const clarityMatch = msg.match(/\\(err\\s+u(\\d+)\\)/i);\n if (clarityMatch) {\n const code = parseInt(clarityMatch[1], 10);\n const mapped = STACKS_CLARITY_MAP[code];\n if (mapped) {\n return new VeridexError(mapped, undefined, { chain: chain ?? 'stacks', cause: error });\n }\n }\n\n // --- Starknet patterns ---\n if (chain === 'starknet' || /felt|starknet|cairo/i.test(msg)) {\n for (const [pattern, code] of STARKNET_PATTERNS) {\n if (typeof pattern === 'string' ? msg.includes(pattern) : pattern.test(msg)) {\n return new VeridexError(code, undefined, { chain: chain ?? 'starknet', cause: error });\n }\n }\n }\n\n // --- EVM patterns (including ethers error codes) ---\n for (const [pattern, code] of EVM_PATTERNS) {\n if (typeof pattern === 'string' ? msg.includes(pattern) : pattern.test(msg)) {\n return new VeridexError(code, undefined, { chain, cause: error });\n }\n }\n\n // --- ethers specific error codes ---\n const ethersError = error as any;\n if (ethersError?.code === 'INSUFFICIENT_FUNDS') {\n return new VeridexError(VeridexErrorCode.INSUFFICIENT_FUNDS, undefined, { chain, cause: error });\n }\n if (ethersError?.code === 'CALL_EXCEPTION') {\n return new VeridexError(VeridexErrorCode.RPC_ERROR, `Contract call failed: ${msg}`, { chain, cause: error });\n }\n if (ethersError?.code === 'NETWORK_ERROR' || ethersError?.code === 'SERVER_ERROR') {\n return new VeridexError(VeridexErrorCode.RPC_ERROR, undefined, { chain, cause: error, retryable: true });\n }\n if (ethersError?.code === 'TIMEOUT') {\n return new VeridexError(VeridexErrorCode.TIMEOUT, undefined, { chain, cause: error, retryable: true });\n }\n\n // --- Generic fallback ---\n return new VeridexError(VeridexErrorCode.UNKNOWN, msg, { chain, cause: error });\n}\n","/**\n * Veridex Protocol SDK — Balance Watcher\n *\n * Provides a polling-based subscription API for vault balance changes.\n * Returns an unsubscribe function so integrators can react to incoming\n * transfers, outgoing withdrawals, or spending limit resets without\n * manually implementing polling.\n *\n * Where chains expose WebSocket endpoints in the future, this module\n * can be extended to use push-based notifications without changing the\n * public API surface.\n */\n\nimport type { PortfolioBalance, TokenBalance } from './BalanceManager.js';\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/** Event types emitted by the balance watcher */\nexport type BalanceEventType = 'balanceChange' | 'error';\n\n/** Callback signature for balance change events */\nexport type BalanceChangeCallback = (event: BalanceChangeEvent) => void;\n\n/** Callback signature for error events */\nexport type BalanceErrorCallback = (error: Error) => void;\n\n/** A balance change event delivered to subscribers */\nexport interface BalanceChangeEvent {\n /** Wormhole chain ID */\n wormholeChainId: number;\n /** Vault address */\n address: string;\n /** Updated portfolio snapshot */\n portfolio: PortfolioBalance;\n /** Individual tokens whose balance changed since last poll */\n changes: TokenBalanceChange[];\n /** Timestamp of this poll */\n timestamp: number;\n}\n\n/** Describes a single token balance that changed */\nexport interface TokenBalanceChange {\n token: TokenBalance['token'];\n previousBalance: bigint;\n currentBalance: bigint;\n /** Positive = received, negative = sent/withdrawn */\n delta: bigint;\n}\n\n/** Options for the watcher */\nexport interface BalanceWatcherOptions {\n /** Poll interval in milliseconds (default: 15_000 — 15 seconds) */\n intervalMs?: number;\n /** Minimum interval allowed (floor, to protect against aggressive polling) */\n minIntervalMs?: number;\n /** Whether to emit an initial event immediately with current balances */\n emitInitial?: boolean;\n}\n\n/** Function to stop watching */\nexport type Unsubscribe = () => void;\n\n// ============================================================================\n// Constants\n// ============================================================================\n\nconst DEFAULT_INTERVAL_MS = 15_000;\nconst MIN_INTERVAL_MS = 5_000;\n\n// ============================================================================\n// BalanceWatcher class\n// ============================================================================\n\n/**\n * Watch vault balances for changes via periodic polling.\n *\n * @example\n * ```typescript\n * const watcher = new BalanceWatcher(fetchBalance);\n *\n * const unsub = watcher.watch(\n * 10004, '0xVaultAddr',\n * (event) => {\n * for (const c of event.changes) {\n * console.log(`${c.token.symbol}: ${c.delta > 0n ? '+' : ''}${c.delta}`);\n * }\n * },\n * { intervalMs: 10_000 }\n * );\n *\n * // Later:\n * unsub();\n * ```\n */\nexport class BalanceWatcher {\n private subscriptions = new Map<string, Subscription>();\n\n /**\n * @param fetchBalance - Function that fetches the current portfolio balance.\n * Typically bound to `BalanceManager.getPortfolioBalance` or the SDK's\n * `getVaultBalances()`.\n */\n constructor(\n private readonly fetchBalance: (\n wormholeChainId: number,\n address: string,\n ) => Promise<PortfolioBalance>,\n ) {}\n\n /**\n * Start watching a vault's balances.\n *\n * @returns An unsubscribe function that stops polling.\n */\n watch(\n wormholeChainId: number,\n address: string,\n onChange: BalanceChangeCallback,\n options?: BalanceWatcherOptions,\n onError?: BalanceErrorCallback,\n ): Unsubscribe {\n const key = `${wormholeChainId}:${address}`;\n const interval = Math.max(\n options?.minIntervalMs ?? MIN_INTERVAL_MS,\n options?.intervalMs ?? DEFAULT_INTERVAL_MS,\n );\n\n // If there's already a subscription for this combo, add the callback\n const existing = this.subscriptions.get(key);\n if (existing) {\n existing.onChangeCallbacks.push(onChange);\n if (onError) existing.onErrorCallbacks.push(onError);\n return () => this.removeCallback(key, onChange, onError);\n }\n\n const sub: Subscription = {\n wormholeChainId,\n address,\n intervalMs: interval,\n onChangeCallbacks: [onChange],\n onErrorCallbacks: onError ? [onError] : [],\n lastSnapshot: null,\n timer: null,\n };\n\n this.subscriptions.set(key, sub);\n\n // Start polling\n const poll = async () => {\n try {\n const portfolio = await this.fetchBalance(wormholeChainId, address);\n const changes = this.diffBalances(sub.lastSnapshot, portfolio);\n\n const isInitial = sub.lastSnapshot === null;\n sub.lastSnapshot = portfolio;\n\n // Only emit if there are actual changes, or if emitInitial is set\n if (changes.length > 0 || (isInitial && options?.emitInitial)) {\n const event: BalanceChangeEvent = {\n wormholeChainId,\n address,\n portfolio,\n changes,\n timestamp: Date.now(),\n };\n for (const cb of sub.onChangeCallbacks) {\n try { cb(event); } catch { /* subscriber error — don't crash poller */ }\n }\n }\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n for (const cb of sub.onErrorCallbacks) {\n try { cb(error); } catch { /* ignore */ }\n }\n }\n };\n\n // Immediate first poll if requested\n if (options?.emitInitial) {\n void poll();\n }\n\n sub.timer = setInterval(poll, interval) as unknown as number;\n\n return () => this.removeCallback(key, onChange, onError);\n }\n\n /**\n * Stop all watchers.\n */\n stopAll(): void {\n for (const [key, sub] of this.subscriptions) {\n if (sub.timer !== null) {\n clearInterval(sub.timer);\n }\n this.subscriptions.delete(key);\n }\n }\n\n /**\n * Get the number of active subscriptions.\n */\n get activeCount(): number {\n return this.subscriptions.size;\n }\n\n // --- Internal helpers ---\n\n private removeCallback(\n key: string,\n onChange: BalanceChangeCallback,\n onError?: BalanceErrorCallback,\n ): void {\n const sub = this.subscriptions.get(key);\n if (!sub) return;\n\n sub.onChangeCallbacks = sub.onChangeCallbacks.filter(cb => cb !== onChange);\n if (onError) {\n sub.onErrorCallbacks = sub.onErrorCallbacks.filter(cb => cb !== onError);\n }\n\n // If no more callbacks, tear down the subscription\n if (sub.onChangeCallbacks.length === 0) {\n if (sub.timer !== null) {\n clearInterval(sub.timer);\n }\n this.subscriptions.delete(key);\n }\n }\n\n private diffBalances(\n previous: PortfolioBalance | null,\n current: PortfolioBalance,\n ): TokenBalanceChange[] {\n if (!previous) return [];\n\n const prevMap = new Map(\n previous.tokens.map(t => [t.token.address.toLowerCase(), t]),\n );\n\n const changes: TokenBalanceChange[] = [];\n\n for (const curr of current.tokens) {\n const key = curr.token.address.toLowerCase();\n const prev = prevMap.get(key);\n const previousBalance = prev?.balance ?? 0n;\n\n if (curr.balance !== previousBalance) {\n changes.push({\n token: curr.token,\n previousBalance,\n currentBalance: curr.balance,\n delta: curr.balance - previousBalance,\n });\n }\n }\n\n // Check for tokens that disappeared (balance went to 0 or token removed)\n for (const [key, prev] of prevMap) {\n const inCurrent = current.tokens.some(\n t => t.token.address.toLowerCase() === key,\n );\n if (!inCurrent && prev.balance > 0n) {\n changes.push({\n token: prev.token,\n previousBalance: prev.balance,\n currentBalance: 0n,\n delta: -prev.balance,\n });\n }\n }\n\n return changes;\n }\n}\n\n// ============================================================================\n// Internal types\n// ============================================================================\n\ninterface Subscription {\n wormholeChainId: number;\n address: string;\n intervalMs: number;\n onChangeCallbacks: BalanceChangeCallback[];\n onErrorCallbacks: BalanceErrorCallback[];\n lastSnapshot: PortfolioBalance | null;\n timer: number | null;\n}\n","/**\n * Veridex Protocol SDK - Main SDK Class\n */\n\nimport { PasskeyManager } from './PasskeyManager.js';\nimport { WalletManager } from './WalletManager.js';\nimport { BalanceManager, type TokenBalance, type PortfolioBalance } from './BalanceManager.js';\nimport { TransactionTracker, type TransactionState, type TransactionCallback } from './TransactionTracker.js';\nimport { \n CrossChainManager, \n type CrossChainResult,\n type CrossChainFees,\n type CrossChainProgressCallback,\n} from './CrossChainManager.js';\nimport { RelayerClient, type SubmitSignedActionRequest } from './RelayerClient.js';\nimport { ChainDetector } from './ChainDetector.js';\nimport { TransactionParser } from './TransactionParser.js';\nimport type { TransactionSummary } from './TransactionSummary.types.js';\nimport { SpendingLimitsManager } from './SpendingLimitsManager.js';\nimport { AccountManager } from './AccountManager.js';\nimport { RecoveryManager } from './RecoveryManager.js';\nimport { MultisigManager } from './MultisigManager.js';\nimport { buildCapabilityMatrix, CHAIN_CAPABILITIES } from './PolicyEnforcement.js';\nimport type { PlatformCapabilityMatrix, ChainCapabilities } from './PolicyEnforcement.js';\nimport { normalizeError, VeridexError, VeridexErrorCode } from './VeridexError.js';\nimport { BalanceWatcher } from './BalanceWatcher.js';\nimport type { BalanceChangeCallback, BalanceErrorCallback, BalanceWatcherOptions, Unsubscribe } from './BalanceWatcher.js';\nimport type { SpendingLimits, FormattedSpendingLimits, LimitCheckResult } from './SpendingLimits.types.js';\nimport { ethers } from 'ethers';\n// NOTE: authenticateAndPrepare and queryPortfolio are loaded via dynamic import()\n// to avoid pulling @wormhole-foundation/wormhole-query-sdk into the static\n// module graph, which causes a TDZ crash in browser/SSR bundles.\nimport { \n GasSponsor, \n type SponsoredVaultResult, \n type MultiChainVaultResult,\n type ChainDeploymentConfig,\n} from './GasSponsor.js';\nimport { buildChallenge, buildGaslessChallenge } from '../payload.js';\nimport { normalizeEmitterAddress } from '../wormhole.js';\nimport { \n getAllTokens, \n getTokenBySymbol, \n isNativeToken,\n type TokenInfo \n} from '../constants/tokens.js';\nimport type {\n VeridexConfig,\n ChainClient,\n PasskeyCredential,\n TransferParams,\n ExecuteParams,\n BridgeParams,\n DispatchResult,\n VaultInfo,\n UnifiedIdentity,\n ChainAddress,\n VaultCreationResult,\n PreparedTransfer,\n TransferResult,\n ReceiveAddress,\n BridgeResult,\n PreparedBridge,\n IdentityState,\n AddBackupKeyResult,\n RemoveKeyResult,\n AuthorizedKey,\n} from './types.js';\n\n/** Default expiration time for prepared transfers (5 minutes) */\nconst DEFAULT_PREPARED_TRANSFER_TTL = 5 * 60 * 1000;\n/** Maximum allowed TTL for prepared transfers (30 minutes) */\nconst MAX_PREPARED_TRANSFER_TTL = 30 * 60 * 1000;\n\nexport class VeridexSDK {\n public readonly passkey: PasskeyManager;\n public readonly wallet: WalletManager;\n public readonly account: AccountManager;\n public readonly balance: BalanceManager;\n public readonly transactions: TransactionTracker;\n public readonly crossChain: CrossChainManager;\n public readonly sponsor: GasSponsor;\n public readonly transactionParser: TransactionParser;\n public readonly spendingLimits: SpendingLimitsManager;\n public readonly recovery: RecoveryManager | null;\n public readonly multisig: MultisigManager | null;\n public readonly balanceWatcher: BalanceWatcher;\n private readonly chain: ChainClient;\n private readonly relayer?: RelayerClient;\n // TODO: Use relayerApiKey when relayer integration is complete (Issue #8)\n // private readonly relayerApiKey?: string;\n private readonly queryApiKey?: string;\n private readonly testnet: boolean;\n private readonly sponsorPrivateKey?: string;\n private readonly chainRpcUrls?: Record<number, string>;\n private readonly chainDetector: ChainDetector;\n private readonly preparedTransferTtl: number;\n private unifiedIdentity: UnifiedIdentity | null = null;\n\n constructor(config: VeridexConfig) {\n this.chain = config.chain;\n this.testnet = config.testnet ?? true;\n this.sponsorPrivateKey = config.sponsorPrivateKey;\n this.chainRpcUrls = config.chainRpcUrls;\n // TODO: Uncomment when relayerApiKey is used (Issue #8)\n // this.relayerApiKey = config.relayerApiKey;\n this.queryApiKey = config.queryApiKey ?? config.relayerApiKey;\n this.passkey = new PasskeyManager({\n relayerUrl: config.relayerUrl,\n });\n this.wallet = new WalletManager({\n cacheAddresses: true,\n persistToStorage: config.persistWallet ?? true,\n });\n this.balance = new BalanceManager({\n cacheBalances: true,\n cacheTtl: 30_000, // 30 seconds\n customRpcUrls: config.chainRpcUrls ?? {},\n });\n this.transactions = new TransactionTracker({\n pollingInterval: 2000,\n requiredConfirmations: 1,\n });\n\n this.chainDetector = new ChainDetector({\n testnet: this.testnet,\n rpcUrls: config.chainRpcUrls ?? {},\n });\n this.crossChain = new CrossChainManager({\n testnet: this.testnet,\n relayerUrl: config.relayerUrl,\n autoRelay: !!config.relayerUrl,\n });\n this.sponsor = new GasSponsor({\n // Veridex fallback sponsorship\n sponsorPrivateKey: config.sponsorPrivateKey,\n // Integrator-provided sponsorship (takes priority over Veridex)\n integratorSponsorKey: config.integratorSponsorKey,\n // Relayer for remote sponsorship (future primary method)\n relayerUrl: config.relayerUrl,\n relayerApiKey: config.relayerApiKey,\n // Chain configuration\n testnet: this.testnet,\n customRpcUrls: config.chainRpcUrls,\n });\n\n // Initialize relayer client if URL provided\n if (config.relayerUrl) {\n this.relayer = new RelayerClient({\n baseUrl: config.relayerUrl,\n apiKey: config.relayerApiKey,\n });\n }\n\n this.account = new AccountManager({\n passkey: this.passkey,\n wallet: this.wallet,\n chain: this.chain,\n relayer: this.relayer,\n testnet: this.testnet,\n getUnifiedIdentity: () => this.getUnifiedIdentity(),\n });\n\n // Initialize transaction parser for human-readable summaries (Issue #26)\n this.transactionParser = new TransactionParser({\n defaultChainId: this.chain.getConfig().wormholeChainId,\n // TODO: Integrate ENS resolution via relayer when available\n // resolveEnsName: async (address) => { ... }\n // TODO: Integrate price oracle when available\n // getTokenPrice: async (token, chainId) => { ... }\n });\n\n // Initialize recovery manager (ADR-0040) — only on recovery-capable chains\n try {\n this.recovery = new RecoveryManager({\n passkey: this.passkey,\n chain: this.chain,\n });\n } catch {\n this.recovery = null;\n }\n\n // Initialize multisig manager (ADR-0037) — only on multisig-capable chains\n try {\n this.multisig = new MultisigManager({\n passkey: this.passkey,\n chain: this.chain,\n });\n } catch {\n this.multisig = null;\n }\n\n // Initialize spending limits manager (Issue #27)\n this.spendingLimits = new SpendingLimitsManager({\n defaultDecimals: 18,\n defaultSymbol: this.chain.getConfig().name.includes('Solana') ? 'SOL' : 'ETH',\n rpcUrls: config.chainRpcUrls ?? {},\n cacheTtl: 10000, // 10 seconds\n });\n\n // Initialize balance watcher (polling-based subscription)\n this.balanceWatcher = new BalanceWatcher(\n async (chainId, address) => {\n return this.balance.getPortfolioBalance(chainId, address, false);\n },\n );\n\n // Configurable TTL for prepared transfers (clamped to MAX)\n this.preparedTransferTtl = Math.min(\n config.preparedTransferTtl ?? DEFAULT_PREPARED_TRANSFER_TTL,\n MAX_PREPARED_TRANSFER_TTL,\n );\n }\n\n getChainConfig() {\n return this.chain.getConfig();\n }\n\n getChainClient(): ChainClient {\n return this.chain;\n }\n\n /**\n * Returns a capability matrix for the current chain, useful for integrator\n * UIs to understand what operations the platform supports.\n */\n getCapabilityMatrix(platformInfo?: {\n webauthnSupported: boolean;\n conditionalUISupported: boolean;\n platformAuthenticatorAvailable: boolean;\n }): PlatformCapabilityMatrix {\n const config = this.chain.getConfig();\n const platform = platformInfo ?? {\n webauthnSupported: typeof globalThis !== 'undefined' && 'PublicKeyCredential' in globalThis,\n conditionalUISupported: false,\n platformAuthenticatorAvailable: false,\n };\n return buildCapabilityMatrix(config.name.toLowerCase(), platform, !!this.relayer);\n }\n\n /**\n * Check if a specific feature is supported on the current chain.\n *\n * Unlike `getCapabilityMatrix()` which returns the full matrix, this is a\n * simple boolean check for the most common per-chain capability queries.\n *\n * @param feature - Feature name to check\n * @returns `true` if fully or partially supported; `false` if unsupported\n *\n * @example\n * ```typescript\n * if (sdk.supportsFeature('recovery')) {\n * // Show recovery UI\n * }\n * ```\n */\n supportsFeature(feature: keyof ChainCapabilities): boolean {\n const chainType = this.chain.getConfig().name.toLowerCase();\n // Resolve the canonical chain type string used in CHAIN_CAPABILITIES\n const type = this.resolveChainType(chainType);\n const caps = CHAIN_CAPABILITIES[type];\n if (!caps) return false;\n return caps[feature] !== 'unsupported';\n }\n\n /**\n * Resolve a chain name to its CHAIN_CAPABILITIES key.\n */\n private resolveChainType(chainName: string): string {\n // Direct match\n if (CHAIN_CAPABILITIES[chainName]) return chainName;\n // Common renames\n if (chainName.includes('base') || chainName.includes('optimism') || chainName.includes('arbitrum') || chainName.includes('ethereum') || chainName.includes('polygon') || chainName.includes('celo')) return 'evm';\n if (chainName.includes('avalanche') || chainName.includes('fuji')) return 'avalanche';\n if (chainName.includes('solana')) return 'solana';\n if (chainName.includes('aptos')) return 'aptos';\n if (chainName.includes('sui')) return 'sui';\n if (chainName.includes('starknet')) return 'starknet';\n if (chainName.includes('stacks')) return 'stacks';\n return 'evm'; // safe default\n }\n\n /**\n * Watch for balance changes on a vault.\n *\n * Uses polling under the hood; the returned function stops the watcher.\n *\n * @example\n * ```typescript\n * const unsub = sdk.watchBalance(\n * (event) => console.log('Balance changed:', event.changes),\n * { intervalMs: 10_000 },\n * );\n *\n * // later\n * unsub();\n * ```\n */\n watchBalance(\n onChange: BalanceChangeCallback,\n options?: BalanceWatcherOptions,\n onError?: BalanceErrorCallback,\n ): Unsubscribe {\n const chainConfig = this.chain.getConfig();\n const vaultAddress = this.getVaultAddress();\n return this.balanceWatcher.watch(\n chainConfig.wormholeChainId,\n vaultAddress,\n onChange,\n options,\n onError,\n );\n }\n\n async getNonce(): Promise<bigint> {\n const credential = this.passkey.getCredential();\n if (!credential) {\n throw new VeridexError(VeridexErrorCode.NO_CREDENTIAL);\n }\n return await this.chain.getNonce(credential.keyHash);\n }\n\n async getMessageFee(): Promise<bigint> {\n return await this.chain.getMessageFee();\n }\n\n async buildTransferPayload(params: TransferParams): Promise<string> {\n return await this.chain.buildTransferPayload(params);\n }\n\n async buildExecutePayload(params: ExecuteParams): Promise<string> {\n return await this.chain.buildExecutePayload(params);\n }\n\n async buildBridgePayload(params: BridgeParams): Promise<string> {\n return await this.chain.buildBridgePayload(params);\n }\n\n async transfer(params: TransferParams, signer: any): Promise<DispatchResult> {\n const credential = this.passkey.getCredential();\n if (!credential) {\n throw new VeridexError(VeridexErrorCode.NO_CREDENTIAL);\n }\n\n // ADR-0037: Block direct dispatch if multisig policy protects transfers\n await this.multisig?.assertDirectDispatchAllowed('transfer');\n\n try {\n const actionPayload = await this.buildTransferPayload(params);\n const nonce = await this.getNonce();\n const challenge = buildChallenge(\n credential.keyHash,\n params.targetChain,\n nonce,\n actionPayload\n );\n\n const signature = await this.passkey.sign(challenge);\n\n return await this.chain.dispatch(\n signature,\n credential.publicKeyX,\n credential.publicKeyY,\n params.targetChain,\n actionPayload,\n nonce,\n signer\n );\n } catch (err) {\n throw normalizeError(err, this.chain.getConfig().name);\n }\n }\n\n async execute(params: ExecuteParams, signer: any): Promise<DispatchResult> {\n const credential = this.passkey.getCredential();\n if (!credential) {\n throw new VeridexError(VeridexErrorCode.NO_CREDENTIAL);\n }\n\n // ADR-0037: Block direct dispatch if multisig policy protects executions\n await this.multisig?.assertDirectDispatchAllowed('execute');\n\n try {\n const actionPayload = await this.buildExecutePayload(params);\n const nonce = await this.getNonce();\n const challenge = buildChallenge(\n credential.keyHash,\n params.targetChain,\n nonce,\n actionPayload\n );\n\n const signature = await this.passkey.sign(challenge);\n\n return await this.chain.dispatch(\n signature,\n credential.publicKeyX,\n credential.publicKeyY,\n params.targetChain,\n actionPayload,\n nonce,\n signer\n );\n } catch (err) {\n throw normalizeError(err, this.chain.getConfig().name);\n }\n }\n\n async bridge(params: BridgeParams, signer: any): Promise<DispatchResult> {\n const credential = this.passkey.getCredential();\n if (!credential) {\n throw new VeridexError(VeridexErrorCode.NO_CREDENTIAL);\n }\n\n // ADR-0037: Block direct dispatch if multisig policy protects bridge operations\n await this.multisig?.assertDirectDispatchAllowed('bridge');\n\n try {\n const actionPayload = await this.buildBridgePayload(params);\n const nonce = await this.getNonce();\n\n const challenge = buildChallenge(\n credential.keyHash,\n params.sourceChain,\n nonce,\n actionPayload\n );\n\n const signature = await this.passkey.sign(challenge);\n\n return await this.chain.dispatch(\n signature,\n credential.publicKeyX,\n credential.publicKeyY,\n params.sourceChain,\n actionPayload,\n nonce,\n signer\n );\n } catch (err) {\n throw normalizeError(err, this.chain.getConfig().name);\n }\n }\n\n // ========================================================================\n // Phase 3: Cross-Chain Transfers\n // ========================================================================\n\n /**\n * Prepare a bridge/cross-chain transfer with fee estimation\n * \n * @param params - Bridge parameters\n * @returns PreparedBridge with fee estimates\n */\n async prepareBridge(params: BridgeParams): Promise<PreparedBridge> {\n const credential = this.passkey.getCredential();\n if (!credential) {\n throw new VeridexError(VeridexErrorCode.NO_CREDENTIAL);\n }\n\n // Build payload and get nonce\n const actionPayload = await this.buildBridgePayload(params);\n const nonce = await this.getNonce();\n \n // Build challenge\n const challenge = buildChallenge(\n credential.keyHash,\n params.sourceChain,\n nonce,\n actionPayload\n );\n\n // Get chain config\n const chainConfig = this.chain.getConfig();\n\n // Estimate fees using CrossChainManager\n const evmClient = this.chain as any;\n const provider = evmClient.provider ?? evmClient.getProvider?.();\n \n let fees: CrossChainFees = {\n sourceGas: 300_000n * 1_000_000_000n, // Default estimate\n messageFee: 0n,\n relayerFee: 0n,\n totalCost: 300_000n * 1_000_000_000n,\n formattedTotal: '0.0003 ETH',\n currency: 'ETH',\n };\n\n if (provider) {\n try {\n fees = await this.crossChain.estimateFees(params, chainConfig, provider);\n } catch (e) {\n console.warn('Fee estimation failed, using defaults:', e);\n }\n }\n\n return {\n params,\n actionPayload,\n nonce,\n challenge,\n fees,\n sourceChain: params.sourceChain,\n destinationChain: params.destinationChain,\n preparedAt: Date.now(),\n expiresAt: Date.now() + this.preparedTransferTtl,\n };\n }\n\n /**\n * Execute a prepared bridge with full cross-chain tracking\n * \n * @param prepared - PreparedBridge from prepareBridge()\n * @param signer - Signer to pay for gas\n * @param onProgress - Optional callback for progress updates\n * @returns BridgeResult with cross-chain tracking info\n */\n async executeBridge(\n prepared: PreparedBridge,\n signer: any,\n onProgress?: CrossChainProgressCallback\n ): Promise<BridgeResult> {\n const credential = this.passkey.getCredential();\n if (!credential) {\n throw new VeridexError(VeridexErrorCode.NO_CREDENTIAL);\n }\n\n // ADR-0037: Block direct dispatch if multisig policy protects bridge operations\n await this.multisig?.assertDirectDispatchAllowed('bridge');\n\n // Check expiration\n if (Date.now() > prepared.expiresAt) {\n throw new VeridexError(VeridexErrorCode.EXPIRED);\n }\n\n const startTime = Date.now();\n const chainConfig = this.chain.getConfig();\n const hubEmitter = normalizeEmitterAddress(chainConfig.contracts.hub ?? '');\n\n // Step 1: Sign with passkey\n onProgress?.({\n status: 'signing',\n step: 1,\n totalSteps: 6,\n message: 'Sign with your passkey...',\n });\n\n const signature = await this.passkey.sign(prepared.challenge);\n\n // Step 2: Dispatch transaction\n onProgress?.({\n status: 'dispatching',\n step: 2,\n totalSteps: 6,\n message: 'Submitting transaction to blockchain...',\n });\n\n const dispatchResult = await this.chain.dispatch(\n signature,\n credential.publicKeyX,\n credential.publicKeyY,\n prepared.params.sourceChain,\n prepared.actionPayload,\n prepared.nonce,\n signer\n );\n\n // Step 3: Wait for confirmations\n onProgress?.({\n status: 'waiting_confirmations',\n step: 3,\n totalSteps: 6,\n message: 'Waiting for block confirmations...',\n details: { txHash: dispatchResult.transactionHash },\n });\n\n // Track the cross-chain transfer\n this.crossChain.trackTransfer(\n dispatchResult.transactionHash,\n prepared.sourceChain,\n prepared.destinationChain,\n dispatchResult.sequence,\n hubEmitter\n );\n\n // Track in transaction tracker too\n this.transactions.track(\n dispatchResult.transactionHash,\n chainConfig.wormholeChainId,\n undefined,\n dispatchResult.sequence\n );\n\n // Step 4-5: Fetch VAA (CrossChainManager handles this)\n let vaa: string | undefined;\n try {\n vaa = await this.crossChain.fetchVAAByTxHash(\n dispatchResult.transactionHash,\n onProgress\n );\n \n this.crossChain.completeTransfer(\n dispatchResult.transactionHash,\n vaa\n );\n } catch (error) {\n // VAA fetch failed, but transaction was successful\n // User can retry VAA fetch later\n console.warn('VAA fetch failed:', error);\n }\n\n // Step 6: Submit to relayer (if configured)\n // The relayer auto-relays by observing hub Dispatch events; there is\n // currently no relay-job API to poll for destination tx hashes.\n let destinationTxHash: string | undefined;\n if (vaa && this.relayer) {\n onProgress?.({\n status: 'relaying',\n step: 6,\n totalSteps: 6,\n message: 'Relayer will submit to destination chain automatically...',\n });\n }\n\n onProgress?.({\n status: 'completed',\n step: 6,\n totalSteps: 6,\n message: 'Cross-chain transfer complete!',\n details: {\n txHash: dispatchResult.transactionHash,\n sequence: dispatchResult.sequence,\n vaaReady: !!vaa,\n destinationTxHash,\n },\n });\n\n // Schedule balance cache invalidation on confirmation\n const vaultAddress = this.getVaultAddress();\n this.transactions.track(\n dispatchResult.transactionHash,\n chainConfig.wormholeChainId,\n (state) => {\n if (state.status === 'confirmed' || state.status === 'failed') {\n this.balance.invalidateCache(chainConfig.wormholeChainId, vaultAddress);\n }\n },\n dispatchResult.sequence\n );\n\n return {\n ...dispatchResult,\n params: prepared.params,\n sourceChain: prepared.sourceChain,\n destinationChain: prepared.destinationChain,\n vaa,\n destinationTxHash,\n duration: Date.now() - startTime,\n timestamp: Date.now(),\n };\n }\n\n /**\n * Execute a gasless bridge using the relayer\n *\n * The relayer pays for the Hub transaction (and Wormhole fee), then observes\n * the resulting Dispatch event and relays the VAA to the destination spoke.\n */\n async bridgeViaRelayer(\n params: BridgeParams,\n onProgress?: CrossChainProgressCallback\n ): Promise<BridgeResult> {\n const credential = this.passkey.getCredential();\n if (!credential) {\n throw new VeridexError(VeridexErrorCode.NO_CREDENTIAL);\n }\n\n // ADR-0037: Block direct dispatch if multisig policy protects bridge operations\n await this.multisig?.assertDirectDispatchAllowed('bridge');\n\n if (!this.relayer) {\n throw new VeridexError(VeridexErrorCode.RELAYER_ERROR, 'Relayer not configured. Please provide relayerUrl in SDK config.');\n }\n\n const startTime = Date.now();\n\n onProgress?.({\n status: 'preparing',\n step: 0,\n totalSteps: 6,\n message: 'Preparing gasless bridge...',\n });\n\n // Bridge actions target the *sourceChain* (where the vault holds funds)\n const actionPayload = await this.buildBridgePayload(params);\n const nonce = await this.getNonce();\n const chainConfig = this.chain.getConfig();\n const hubChainId = chainConfig.hubChainId ?? chainConfig.wormholeChainId;\n\n onProgress?.({\n status: 'signing',\n step: 1,\n totalSteps: 6,\n message: 'Sign with your passkey...',\n });\n\n // BRIDGE actions target sourceChain (where funds are held)\n // The destinationChain is encoded in the actionPayload itself\n // The VAA will be executed on the SOURCE vault to initiate Token Bridge transfer\n const challenge = buildGaslessChallenge(\n params.sourceChain,\n actionPayload,\n nonce,\n hubChainId\n );\n const signature = await this.passkey.sign(challenge);\n\n onProgress?.({\n status: 'dispatching',\n step: 2,\n totalSteps: 6,\n message: 'Submitting gasless bridge to relayer...',\n });\n\n // Use full WebAuthn data for authenticateAndDispatch\n // For BRIDGE: targetChain = sourceChain (where funds are)\n // The destination is in the actionPayload\n const submitRequest: SubmitSignedActionRequest = {\n authenticatorData: signature.authenticatorData,\n clientDataJSON: signature.clientDataJSON,\n challengeIndex: signature.challengeIndex,\n typeIndex: signature.typeIndex,\n r: '0x' + signature.r.toString(16).padStart(64, '0'),\n s: '0x' + signature.s.toString(16).padStart(64, '0'),\n publicKeyX: '0x' + credential.publicKeyX.toString(16).padStart(64, '0'),\n publicKeyY: '0x' + credential.publicKeyY.toString(16).padStart(64, '0'),\n targetChain: params.sourceChain,\n actionPayload,\n nonce: Number(nonce),\n };\n\n const relayerResult = await this.relayer.submitSignedAction(submitRequest);\n if (!relayerResult.success) {\n throw new VeridexError(VeridexErrorCode.RELAYER_ERROR, `Relayer submission failed: ${relayerResult.error}`);\n }\n\n const txHash = relayerResult.txHash ?? '';\n const sequence = relayerResult.sequence ? BigInt(relayerResult.sequence) : 0n;\n\n if (txHash) {\n this.transactions.track(txHash, hubChainId, undefined, sequence || undefined);\n }\n\n // Try to fetch VAA for UI feedback (relayer will still execute even if this fails)\n let vaa: string | undefined;\n try {\n vaa = await this.crossChain.fetchVAAByTxHash(txHash, onProgress);\n } catch {\n // ignore: user can retry fetch later\n }\n\n onProgress?.({\n status: 'completed',\n step: 6,\n totalSteps: 6,\n message: 'Gasless bridge submitted. Relayer will complete execution.',\n details: {\n txHash,\n sequence,\n vaaReady: !!vaa,\n },\n });\n\n // For BRIDGE: targetChain (where VAA is executed) = sourceChain\n // The actual destination for funds is in destinationChain\n return {\n transactionHash: txHash,\n sequence,\n userKeyHash: credential.keyHash,\n targetChain: params.sourceChain,\n blockNumber: 0,\n params,\n sourceChain: params.sourceChain,\n destinationChain: params.destinationChain,\n vaa,\n destinationTxHash: undefined,\n duration: Date.now() - startTime,\n timestamp: Date.now(),\n };\n }\n\n /**\n * Execute a full bridge with automatic preparation\n * \n * @param params - Bridge parameters\n * @param signer - Signer to pay for gas\n * @param onProgress - Optional callback for progress updates\n * @returns BridgeResult with cross-chain tracking info\n */\n async bridgeWithTracking(\n params: BridgeParams,\n signer: any,\n onProgress?: CrossChainProgressCallback\n ): Promise<BridgeResult> {\n onProgress?.({\n status: 'preparing',\n step: 0,\n totalSteps: 6,\n message: 'Preparing cross-chain transfer...',\n });\n\n const prepared = await this.prepareBridge(params);\n return await this.executeBridge(prepared, signer, onProgress);\n }\n\n /**\n * Fetch VAA for a completed transaction\n * Use this if VAA fetch failed during bridge execution\n * \n * @param txHash - Source chain transaction hash\n * @returns VAA base64 string\n */\n async fetchVAAForTransaction(txHash: string): Promise<string> {\n return await this.crossChain.fetchVAAByTxHash(txHash);\n }\n\n /**\n * Get cross-chain transfer fees\n * \n * @param params - Bridge parameters\n * @returns CrossChainFees with breakdown\n */\n async getBridgeFees(params: BridgeParams): Promise<CrossChainFees> {\n const chainConfig = this.chain.getConfig();\n const evmClient = this.chain as any;\n const provider = evmClient.provider ?? evmClient.getProvider?.();\n\n if (!provider) {\n throw new VeridexError(VeridexErrorCode.RPC_ERROR, 'Provider not available');\n }\n\n return await this.crossChain.estimateFees(params, chainConfig, provider);\n }\n\n /**\n * Get all pending cross-chain transfers\n */\n getPendingBridges(): CrossChainResult[] {\n return this.crossChain.getAllPendingTransfers();\n }\n\n /**\n * Get Wormholescan explorer URL for a cross-chain transfer\n */\n getWormholeExplorerUrl(sequence: bigint): string {\n const chainConfig = this.chain.getConfig();\n const hubEmitter = chainConfig.contracts.hub ?? '';\n return this.crossChain.getWormholeExplorerUrl(\n chainConfig.wormholeChainId,\n hubEmitter,\n sequence\n );\n }\n\n // ========================================================================\n // Phase 2: Send & Receive Funds\n // ========================================================================\n\n /**\n * Prepare a transfer with gas estimation\n * Call this before transfer() to show user the cost\n * \n * @param params - Transfer parameters\n * @returns PreparedTransfer with gas estimates and challenge\n */\n async prepareTransfer(params: TransferParams): Promise<PreparedTransfer> {\n const credential = this.passkey.getCredential();\n if (!credential) {\n throw new VeridexError(VeridexErrorCode.NO_CREDENTIAL);\n }\n\n // Build payload and get nonce\n const actionPayload = await this.buildTransferPayload(params);\n const nonce = await this.getNonce();\n \n // Build challenge\n const challenge = buildChallenge(\n credential.keyHash,\n params.targetChain,\n nonce,\n actionPayload\n );\n\n // Get gas estimates - need to type cast for EVM-specific methods\n const evmClient = this.chain as any;\n let estimatedGas = 500000n; // Default\n let gasPrice = 0n;\n \n if (typeof evmClient.getGasPrice === 'function') {\n gasPrice = await evmClient.getGasPrice();\n }\n\n // Get message fee\n const messageFee = await this.getMessageFee();\n\n // Calculate total cost\n const gasCost = estimatedGas * gasPrice;\n const totalCost = gasCost + messageFee;\n const formattedCost = this.formatWei(totalCost);\n\n return {\n params,\n actionPayload,\n nonce,\n challenge,\n estimatedGas,\n gasPrice,\n messageFee,\n totalCost,\n formattedCost,\n preparedAt: Date.now(),\n expiresAt: Date.now() + this.preparedTransferTtl,\n };\n }\n\n /**\n * Get a human-readable summary of a prepared transfer (Issue #26)\n * \n * Use this to show users what they're signing before biometric authentication.\n * The summary includes:\n * - Action type (transfer, bridge, execute, config)\n * - Human-readable amounts (not wei)\n * - Recipient display (truncated address, ENS if available)\n * - Chain information\n * - Risk warnings for unusual transactions\n * - Gas cost breakdown\n * - Expiration countdown\n * \n * @example\n * ```typescript\n * const prepared = await sdk.prepareTransfer({\n * recipient: '0x123...',\n * amount: '1000000000000000000', // 1 ETH in wei\n * tokenAddress: NATIVE_TOKEN_ADDRESS,\n * targetChain: 10004, // Base Sepolia\n * });\n * \n * const summary = await sdk.getTransactionSummary(prepared);\n * console.log(summary.title); // \"Transfer\"\n * console.log(summary.description); // \"Send 1.0 ETH to 0x123...abc\"\n * console.log(summary.details.formattedAmount); // \"1.0\"\n * console.log(summary.risks); // [{ type: 'large_transaction', level: 'high', ... }]\n * ```\n * \n * @param prepared - PreparedTransfer or PreparedBridge from prepare methods\n * @returns Promise<TransactionSummary> with human-readable details\n */\n async getTransactionSummary(prepared: PreparedTransfer | PreparedBridge): Promise<TransactionSummary> {\n return this.transactionParser.parse(prepared);\n }\n\n // ============================================================================\n // Spending Limits (Issue #27)\n // ============================================================================\n\n /**\n * Get current spending limits for your vault\n * \n * @example\n * ```typescript\n * const limits = await sdk.getSpendingLimits();\n * console.log(`Daily remaining: ${limits.dailyRemaining}`);\n * console.log(`Resets in: ${limits.timeUntilReset}ms`);\n * ```\n * \n * @param chainId - Optional chain ID (defaults to current chain)\n * @returns Promise<SpendingLimits> with current limits and usage\n */\n async getSpendingLimits(chainId?: number): Promise<SpendingLimits> {\n const vaultAddress = this.getVaultAddress();\n const effectiveChainId = chainId ?? this.chain.getConfig().wormholeChainId;\n const rpcUrl = this.chainRpcUrls?.[effectiveChainId] ?? this.chain.getConfig().rpcUrl;\n \n return this.spendingLimits.getSpendingLimits(vaultAddress, effectiveChainId, rpcUrl);\n }\n\n /**\n * Get spending limits formatted for UI display\n * \n * @example\n * ```typescript\n * const formatted = await sdk.getFormattedSpendingLimits();\n * console.log(`${formatted.dailyUsedPercentage}% of daily limit used`);\n * console.log(`Resets in: ${formatted.timeUntilReset}`);\n * ```\n */\n async getFormattedSpendingLimits(chainId?: number): Promise<FormattedSpendingLimits> {\n const vaultAddress = this.getVaultAddress();\n const effectiveChainId = chainId ?? this.chain.getConfig().wormholeChainId;\n const rpcUrl = this.chainRpcUrls?.[effectiveChainId] ?? this.chain.getConfig().rpcUrl;\n \n return this.spendingLimits.getFormattedSpendingLimits(vaultAddress, effectiveChainId, { rpcUrl });\n }\n\n /**\n * Check if a transaction amount is within spending limits\n * \n * @example\n * ```typescript\n * const check = await sdk.checkSpendingLimit(ethers.parseEther(\"1.0\"));\n * if (!check.allowed) {\n * console.log(check.message);\n * console.log('Suggestions:', check.suggestions);\n * }\n * ```\n * \n * @param amount - Amount to check (in wei/base units)\n * @param chainId - Optional chain ID\n * @returns LimitCheckResult with allowed status and suggestions\n */\n async checkSpendingLimit(amount: bigint, chainId?: number): Promise<LimitCheckResult> {\n const vaultAddress = this.getVaultAddress();\n const effectiveChainId = chainId ?? this.chain.getConfig().wormholeChainId;\n const rpcUrl = this.chainRpcUrls?.[effectiveChainId] ?? this.chain.getConfig().rpcUrl;\n \n return this.spendingLimits.checkTransactionLimit(vaultAddress, effectiveChainId, amount, { rpcUrl });\n }\n\n /**\n * Prepare a transaction to update the daily spending limit\n * Returns a PreparedTransfer that can be signed and executed\n * \n * @example\n * ```typescript\n * // Set daily limit to 5 ETH\n * const prepared = await sdk.prepareSetDailyLimit(ethers.parseEther(\"5.0\"));\n * const result = await sdk.executeTransfer(prepared, signer);\n * ```\n * \n * @param newLimit - New daily limit (0 = unlimited)\n * @returns PreparedTransfer for signing\n */\n async prepareSetDailyLimit(newLimit: bigint): Promise<PreparedTransfer> {\n const credential = this.passkey.getCredential();\n if (!credential) {\n throw new VeridexError(VeridexErrorCode.NO_CREDENTIAL);\n }\n\n const actionPayload = this.spendingLimits.prepareDailyLimitUpdate(newLimit);\n const nonce = await this.getNonce();\n const targetChain = this.chain.getConfig().wormholeChainId;\n const challenge = buildChallenge(credential.keyHash, targetChain, nonce, actionPayload);\n const messageFee = await this.getMessageFee();\n \n return {\n params: {\n targetChain,\n token: 'native',\n recipient: this.getVaultAddress(),\n amount: 0n,\n },\n actionPayload,\n nonce,\n challenge,\n estimatedGas: 0n,\n gasPrice: 0n,\n messageFee,\n totalCost: messageFee,\n formattedCost: '0',\n preparedAt: Date.now(),\n expiresAt: Date.now() + this.preparedTransferTtl,\n };\n }\n\n /**\n * Prepare a transaction to pause the vault (emergency stop)\n * Pausing prevents all withdrawals until unpaused\n * \n * @example\n * ```typescript\n * const prepared = await sdk.preparePauseVault();\n * const result = await sdk.executeTransfer(prepared, signer);\n * ```\n */\n async preparePauseVault(): Promise<PreparedTransfer> {\n const credential = this.passkey.getCredential();\n if (!credential) {\n throw new VeridexError(VeridexErrorCode.NO_CREDENTIAL);\n }\n\n const actionPayload = this.spendingLimits.preparePauseVault();\n const nonce = await this.getNonce();\n const targetChain = this.chain.getConfig().wormholeChainId;\n const challenge = buildChallenge(credential.keyHash, targetChain, nonce, actionPayload);\n const messageFee = await this.getMessageFee();\n \n return {\n params: {\n targetChain,\n token: 'native',\n recipient: this.getVaultAddress(),\n amount: 0n,\n },\n actionPayload,\n nonce,\n challenge,\n estimatedGas: 0n,\n gasPrice: 0n,\n messageFee,\n totalCost: messageFee,\n formattedCost: '0',\n preparedAt: Date.now(),\n expiresAt: Date.now() + this.preparedTransferTtl,\n };\n }\n\n /**\n * Prepare a transaction to unpause the vault\n * \n * @example\n * ```typescript\n * const prepared = await sdk.prepareUnpauseVault();\n * const result = await sdk.executeTransfer(prepared, signer);\n * ```\n */\n async prepareUnpauseVault(): Promise<PreparedTransfer> {\n const credential = this.passkey.getCredential();\n if (!credential) {\n throw new VeridexError(VeridexErrorCode.NO_CREDENTIAL);\n }\n\n const actionPayload = this.spendingLimits.prepareUnpauseVault();\n const nonce = await this.getNonce();\n const targetChain = this.chain.getConfig().wormholeChainId;\n const challenge = buildChallenge(credential.keyHash, targetChain, nonce, actionPayload);\n const messageFee = await this.getMessageFee();\n \n return {\n params: {\n targetChain,\n token: 'native',\n recipient: this.getVaultAddress(),\n amount: 0n,\n },\n actionPayload,\n nonce,\n challenge,\n estimatedGas: 0n,\n gasPrice: 0n,\n messageFee,\n totalCost: messageFee,\n formattedCost: '0',\n preparedAt: Date.now(),\n expiresAt: Date.now() + this.preparedTransferTtl,\n };\n }\n\n /**\n * Execute a prepared transfer\n * Use this after prepareTransfer() for better UX\n * \n * @param prepared - PreparedTransfer from prepareTransfer()\n * @param signer - Signer to pay for gas\n * @returns TransferResult with tracking info\n */\n async executeTransfer(\n prepared: PreparedTransfer, \n signer: any\n ): Promise<TransferResult> {\n const credential = this.passkey.getCredential();\n if (!credential) {\n throw new VeridexError(VeridexErrorCode.NO_CREDENTIAL);\n }\n\n // ADR-0037: Block direct dispatch if multisig policy protects transfers\n await this.multisig?.assertDirectDispatchAllowed('transfer');\n\n // Check if prepared transfer has expired\n if (Date.now() > prepared.expiresAt) {\n throw new VeridexError(VeridexErrorCode.EXPIRED);\n }\n\n try {\n // Sign with passkey\n const signature = await this.passkey.sign(prepared.challenge);\n\n // Dispatch the transaction\n const result = await this.chain.dispatch(\n signature,\n credential.publicKeyX,\n credential.publicKeyY,\n prepared.params.targetChain,\n prepared.actionPayload,\n prepared.nonce,\n signer\n );\n\n // Track the transaction with cache invalidation on confirmation\n const vaultAddress = this.getVaultAddress();\n const chainConfig = this.chain.getConfig();\n if (result.transactionHash) {\n this.transactions.track(\n result.transactionHash,\n chainConfig.wormholeChainId,\n (state) => {\n if (state.status === 'confirmed' || state.status === 'failed') {\n this.balance.invalidateCache(chainConfig.wormholeChainId, vaultAddress);\n }\n },\n result.sequence\n );\n }\n\n return {\n ...result,\n params: prepared.params,\n timestamp: Date.now(),\n };\n } catch (err) {\n throw normalizeError(err, this.chain.getConfig().name);\n }\n }\n\n /**\n * Enhanced transfer with automatic tracking\n * \n * @param params - Transfer parameters\n * @param signer - Signer to pay for gas\n * @param onStatusChange - Optional callback for transaction status updates\n * @returns TransferResult with tracking info\n */\n async transferWithTracking(\n params: TransferParams,\n signer: any,\n onStatusChange?: TransactionCallback\n ): Promise<TransferResult> {\n const credential = this.passkey.getCredential();\n if (!credential) {\n throw new VeridexError(VeridexErrorCode.NO_CREDENTIAL);\n }\n\n // ADR-0037: Block direct dispatch if multisig policy protects transfers\n await this.multisig?.assertDirectDispatchAllowed('transfer');\n\n try {\n // Execute the transfer\n const actionPayload = await this.buildTransferPayload(params);\n const nonce = await this.getNonce();\n const challenge = buildChallenge(\n credential.keyHash,\n params.targetChain,\n nonce,\n actionPayload\n );\n\n const signature = await this.passkey.sign(challenge);\n\n const result = await this.chain.dispatch(\n signature,\n credential.publicKeyX,\n credential.publicKeyY,\n params.targetChain,\n actionPayload,\n nonce,\n signer\n );\n\n // Track the transaction with cache invalidation on confirmation\n const vaultAddress = this.getVaultAddress();\n const chainConfig = this.chain.getConfig();\n if (result.transactionHash) {\n this.transactions.track(\n result.transactionHash,\n chainConfig.wormholeChainId,\n (state) => {\n if (state.status === 'confirmed' || state.status === 'failed') {\n this.balance.invalidateCache(chainConfig.wormholeChainId, vaultAddress);\n }\n onStatusChange?.(state);\n },\n result.sequence\n );\n }\n\n return {\n ...result,\n params,\n timestamp: Date.now(),\n };\n } catch (err) {\n throw normalizeError(err, this.chain.getConfig().name);\n }\n }\n\n /**\n * Execute a gasless transfer using the relayer\n * \n * This method allows users to send funds without paying gas themselves.\n * The relayer service submits the transaction to the Hub and pays the gas.\n * The relayer then automatically relays the VAA to the destination spoke chain.\n * \n * @param params - Transfer parameters (to, amount, token, targetChain)\n * @param onStatusChange - Optional callback for transaction status updates\n * @returns TransferResult with Hub tx hash and tracking info\n */\n async transferViaRelayer(\n params: TransferParams,\n onStatusChange?: TransactionCallback\n ): Promise<TransferResult> {\n const credential = this.passkey.getCredential();\n if (!credential) {\n throw new VeridexError(VeridexErrorCode.NO_CREDENTIAL);\n }\n\n // ADR-0037: Block direct dispatch if multisig policy protects transfers\n await this.multisig?.assertDirectDispatchAllowed('transfer');\n\n // Ensure relayer is available\n if (!this.relayer) {\n throw new VeridexError(VeridexErrorCode.RELAYER_ERROR, 'Relayer not configured. Please provide relayerUrl in SDK config.');\n }\n\n const chainConfig = this.chain.getConfig();\n\n // Build the action payload (canonical encoding from the active chain client)\n const actionPayload = await this.buildTransferPayload(params);\n\n // Client-first preparation:\n // - fetch Guardian-attested nonce via Wormhole Queries when possible\n // - fall back to hub RPC nonce lookup\n // - prompt user to sign once\n const { authenticateAndPrepare } = await import('../auth/prepareAuth.js');\n const prepared = await authenticateAndPrepare(\n {\n credential,\n targetChain: params.targetChain,\n actionPayload,\n },\n this.queryApiKey ?? ''\n );\n\n const submitRequest = JSON.parse(new TextDecoder().decode(prepared.serializedTx)) as SubmitSignedActionRequest;\n\n // Ensure the request body uses our canonical payload (defensive)\n (submitRequest as any).actionPayload = actionPayload;\n\n const relayerResult = await this.relayer.submitSignedAction(submitRequest);\n\n if (!relayerResult.success) {\n throw new VeridexError(VeridexErrorCode.RELAYER_ERROR, `Relayer submission failed: ${relayerResult.error}`);\n }\n\n // Track the Hub transaction with cache invalidation on confirmation\n const vaultAddress = this.getVaultAddress();\n if (relayerResult.txHash) {\n const hubChainId = chainConfig.hubChainId ?? chainConfig.wormholeChainId;\n this.transactions.track(\n relayerResult.txHash,\n hubChainId,\n (state) => {\n if (state.status === 'confirmed' || state.status === 'failed') {\n this.balance.invalidateCache(chainConfig.wormholeChainId, vaultAddress);\n }\n onStatusChange?.(state);\n },\n relayerResult.sequence ? BigInt(relayerResult.sequence) : undefined\n );\n }\n\n return {\n transactionHash: relayerResult.txHash ?? '',\n sequence: relayerResult.sequence ? BigInt(relayerResult.sequence) : 0n,\n userKeyHash: credential.keyHash,\n targetChain: params.targetChain,\n blockNumber: 0, // Hub tx block number not returned by relayer\n params,\n timestamp: Date.now(),\n };\n }\n\n /**\n * Wait for a transaction to confirm\n * \n * @param hash - Transaction hash\n * @returns TransactionState when confirmed\n */\n async waitForTransaction(hash: string): Promise<TransactionState> {\n const chainConfig = this.chain.getConfig();\n return await this.transactions.waitForConfirmation(hash, chainConfig.wormholeChainId);\n }\n\n // ========================================================================\n // Balance Methods\n // ========================================================================\n\n /**\n * Get native token balance for the current vault\n * \n * @returns TokenBalance with native token balance\n */\n async getVaultNativeBalance(): Promise<TokenBalance> {\n const vaultAddress = this.getVaultAddress();\n const chainConfig = this.chain.getConfig();\n return await this.balance.getNativeBalance(chainConfig.wormholeChainId, vaultAddress);\n }\n\n /**\n * Get all token balances for the current vault\n * \n * @param includeZeroBalances - Whether to include tokens with 0 balance\n * @returns PortfolioBalance with all token balances\n */\n async getVaultBalances(includeZeroBalances: boolean = false): Promise<PortfolioBalance> {\n const vaultAddress = this.getVaultAddress();\n const chainConfig = this.chain.getConfig();\n\n // Prefer Wormhole Queries when possible (faster, Guardian-attested), but preserve\n // existing behavior as a fallback.\n const credential = this.passkey.getCredential();\n if (credential && this.queryApiKey) {\n try {\n const wormholeChainId = chainConfig.wormholeChainId;\n const tokenList = getAllTokens(wormholeChainId);\n const erc20Tokens = tokenList\n .filter((t) => !isNativeToken(t.address))\n .map((t) => t.address);\n\n const { queryPortfolio } = await import('../queries/portfolio.js');\n const result = await queryPortfolio(credential.keyHash, this.queryApiKey, {\n network: this.testnet ? 'testnet' : 'mainnet',\n vaultAddresses: { [wormholeChainId]: vaultAddress },\n evmTokenAddresses: { [wormholeChainId]: erc20Tokens },\n rpcUrls: { [wormholeChainId]: chainConfig.rpcUrl },\n maxAge: 60,\n // Testnet Query Proxy can be slow; use a more forgiving timeout.\n timeout: this.testnet ? 15_000 : 10_000,\n maxAttempts: this.testnet ? 3 : 2,\n });\n\n const chain = result.chains.find((c) => c.wormholeChainId === wormholeChainId);\n if (chain && !chain.error) {\n const byAssetId = new Map(chain.balances.map((b) => [b.assetId.toLowerCase(), b] as const));\n const tokens = tokenList.map((t) => {\n if (isNativeToken(t.address)) {\n return null;\n }\n const found = byAssetId.get(t.address.toLowerCase());\n const amount = found?.amount ?? 0n;\n const formatted = ethers.formatUnits(amount, t.decimals);\n return {\n token: t,\n balance: amount,\n formatted,\n usdValue: found?.usdValue,\n };\n }).filter((t): t is NonNullable<typeof t> => !!t);\n\n // Add native token via RPC (Queries don't support native ETH balance).\n const native = await this.balance.getNativeBalance(wormholeChainId, vaultAddress);\n const merged = [native, ...tokens];\n\n const filtered = includeZeroBalances ? merged : merged.filter((t) => t.balance > 0n);\n const totalUsdValue = filtered.reduce((sum, t) => sum + (t.usdValue ?? 0), 0);\n\n return {\n wormholeChainId,\n chainName: chainConfig.name,\n address: vaultAddress,\n tokens: filtered,\n totalUsdValue: totalUsdValue || undefined,\n lastUpdated: Date.now(),\n };\n }\n } catch {\n // Fall back to the existing RPC-based balance logic.\n }\n }\n\n return await this.balance.getPortfolioBalance(chainConfig.wormholeChainId, vaultAddress, includeZeroBalances);\n }\n\n /**\n * Get token balance for a specific token\n * \n * @param tokenAddress - Token contract address or 'native'\n * @returns TokenBalance for the specified token\n */\n async getVaultTokenBalance(tokenAddress: string): Promise<TokenBalance> {\n const vaultAddress = this.getVaultAddress();\n const chainConfig = this.chain.getConfig();\n return await this.balance.getBalance(\n chainConfig.wormholeChainId,\n vaultAddress,\n tokenAddress\n );\n }\n\n /**\n * Get balances across multiple chains\n * \n * @param chainIds - Array of Wormhole chain IDs to check\n * @returns Array of PortfolioBalance for each chain\n */\n async getMultiChainBalances(chainIds: number[]): Promise<PortfolioBalance[]> {\n const credential = this.passkey.getCredential();\n if (!credential) {\n throw new VeridexError(VeridexErrorCode.NO_CREDENTIAL);\n }\n\n // Derive an address per chain and query balances accordingly.\n const results: PortfolioBalance[] = [];\n\n for (const wormholeChainId of chainIds) {\n const chainConfig = this.chainDetector.getChainConfig(wormholeChainId);\n\n // If unknown, skip with a warning.\n if (!chainConfig) {\n // eslint-disable-next-line no-console\n console.warn(`Unknown chainId for balances: ${wormholeChainId}`);\n continue;\n }\n\n // Resolve vault address\n const derived = this.chainDetector.deriveVaultAddress(credential, wormholeChainId);\n const address = derived?.address ?? (wormholeChainId === this.chain.getConfig().wormholeChainId\n ? this.getVaultAddress()\n : credential.keyHash);\n\n if (chainConfig.isEvm) {\n try {\n const portfolio = await this.balance.getPortfolioBalance(wormholeChainId, address, false);\n results.push(portfolio);\n } catch (error) {\n // eslint-disable-next-line no-console\n console.warn(`Failed to fetch EVM balances for chain ${wormholeChainId}:`, error);\n }\n continue;\n }\n\n // Non-EVM: fetch native balance via chain-specific client\n try {\n const client: any = this.chainDetector.createClient(wormholeChainId);\n if (typeof client.getNativeBalance !== 'function') {\n // eslint-disable-next-line no-console\n console.warn(`No native balance support for chain ${wormholeChainId}`);\n continue;\n }\n\n const native = await client.getNativeBalance(address);\n const meta = this.chainDetector.getNonEvmNativeTokenMeta(wormholeChainId);\n\n const decimals = meta?.decimals ?? 0;\n const formatted = decimals > 0 ? ethers.formatUnits(native, decimals) : native.toString();\n\n results.push({\n wormholeChainId,\n chainName: chainConfig.name,\n address,\n tokens: [\n {\n token: {\n symbol: meta?.symbol ?? 'NATIVE',\n name: meta?.name ?? 'Native Token',\n address: 'native',\n decimals,\n isNative: true,\n },\n balance: native,\n formatted,\n },\n ],\n lastUpdated: Date.now(),\n });\n } catch (error) {\n // eslint-disable-next-line no-console\n console.warn(`Failed to fetch non-EVM balances for chain ${wormholeChainId}:`, error);\n }\n }\n\n return results;\n }\n\n /**\n * Get token list for a chain\n */\n getTokenList(wormholeChainId?: number): TokenInfo[] {\n const chainId = wormholeChainId ?? this.chain.getConfig().wormholeChainId;\n return getAllTokens(chainId);\n }\n\n /**\n * Get token by symbol\n */\n getTokenBySymbol(symbol: string, wormholeChainId?: number): TokenInfo | null {\n const chainId = wormholeChainId ?? this.chain.getConfig().wormholeChainId;\n return getTokenBySymbol(chainId, symbol);\n }\n\n // ========================================================================\n // Multi-Chain Convenience Methods\n // ========================================================================\n\n /**\n * Get vault addresses across all supported chains at once.\n *\n * Unlike calling `getVaultAddressForChain()` in a loop, this returns a\n * structured map that frontends can render directly.\n *\n * @example\n * ```typescript\n * const addresses = sdk.getMultiChainAddresses();\n * for (const [chainId, addr] of Object.entries(addresses)) {\n * console.log(`Chain ${chainId}: ${addr}`);\n * }\n * ```\n */\n getMultiChainAddresses(): Record<number, string> {\n const credential = this.passkey.getCredential();\n if (!credential) {\n throw new VeridexError(VeridexErrorCode.NO_CREDENTIAL);\n }\n\n const supportedChains = this.sponsor.getSupportedChains();\n const addresses: Record<number, string> = {};\n\n // Always include the current chain\n const currentChainId = this.chain.getConfig().wormholeChainId;\n addresses[currentChainId] = this.chain.computeVaultAddress(credential.keyHash);\n\n for (const chain of supportedChains) {\n if (addresses[chain.wormholeChainId]) continue;\n const addr = this.getVaultAddressForChain(chain.wormholeChainId, credential.keyHash);\n if (addr) {\n addresses[chain.wormholeChainId] = addr;\n }\n }\n\n return addresses;\n }\n\n /**\n * Get a combined portfolio view across multiple chains.\n *\n * Returns vault address + balances per chain, suitable for a dashboard or\n * portfolio summary screen.\n *\n * @example\n * ```typescript\n * const portfolio = await sdk.getMultiChainPortfolio();\n * for (const entry of portfolio) {\n * console.log(`${entry.chainName}: ${entry.tokens.length} tokens`);\n * }\n * ```\n *\n * @param chainIds - Optional array of Wormhole chain IDs. Defaults to all sponsored chains.\n */\n async getMultiChainPortfolio(chainIds?: number[]): Promise<PortfolioBalance[]> {\n const credential = this.passkey.getCredential();\n if (!credential) {\n throw new VeridexError(VeridexErrorCode.NO_CREDENTIAL);\n }\n\n // Default to all sponsored chains plus the current chain\n const ids = chainIds ?? [\n this.chain.getConfig().wormholeChainId,\n ...this.sponsor.getSupportedChains()\n .map(c => c.wormholeChainId)\n .filter(id => id !== this.chain.getConfig().wormholeChainId),\n ];\n\n return this.getMultiChainBalances(ids);\n }\n\n // ========================================================================\n // Receive Address Methods\n // ========================================================================\n\n /**\n * Get receive address information for sharing\n * Use this to generate QR codes or share your vault address\n * \n * @returns ReceiveAddress with address and sharing info\n */\n getReceiveAddress(): ReceiveAddress {\n const vaultAddress = this.getVaultAddress();\n const chainConfig = this.chain.getConfig();\n \n // Create a deep link for wallet apps (EIP-681 format for EVM)\n const deepLink = chainConfig.isEvm \n ? `ethereum:${vaultAddress}@${chainConfig.chainId}`\n : undefined;\n\n // Create copy-friendly text\n const copyText = `${vaultAddress}`;\n\n return {\n address: vaultAddress,\n chainName: chainConfig.name,\n wormholeChainId: chainConfig.wormholeChainId,\n deepLink,\n copyText,\n };\n }\n\n /**\n * Generate receive address with amount (for payment requests)\n * \n * @param amount - Amount to request\n * @param tokenAddress - Token address or 'native'\n * @param tokenDecimals - Token decimals\n * @returns ReceiveAddress with payment request info\n */\n getPaymentRequest(\n amount: bigint,\n tokenAddress: string = 'native',\n tokenDecimals: number = 18\n ): ReceiveAddress {\n const vaultAddress = this.getVaultAddress();\n const chainConfig = this.chain.getConfig();\n \n // Format amount\n const formattedAmount = this.formatUnits(amount, tokenDecimals);\n \n // Create EIP-681 payment request for EVM\n let deepLink: string | undefined;\n if (chainConfig.isEvm) {\n if (isNativeToken(tokenAddress)) {\n deepLink = `ethereum:${vaultAddress}@${chainConfig.chainId}?value=${amount.toString()}`;\n } else {\n // ERC20 transfer\n deepLink = `ethereum:${tokenAddress}@${chainConfig.chainId}/transfer?address=${vaultAddress}&uint256=${amount.toString()}`;\n }\n }\n\n return {\n address: vaultAddress,\n chainName: chainConfig.name,\n wormholeChainId: chainConfig.wormholeChainId,\n deepLink,\n copyText: `${vaultAddress} (${formattedAmount})`,\n };\n }\n\n // ========================================================================\n // Utility Methods\n // ========================================================================\n\n /**\n * Format wei to ether string\n */\n private formatWei(wei: bigint): string {\n // Simple formatter - 18 decimals\n const ether = Number(wei) / 1e18;\n return `${ether.toFixed(6)} ETH`;\n }\n\n /**\n * Format units based on decimals\n */\n private formatUnits(amount: bigint, decimals: number): string {\n const divisor = BigInt(10 ** decimals);\n const whole = amount / divisor;\n const remainder = amount % divisor;\n const remainderStr = remainder.toString().padStart(decimals, '0');\n const trimmed = remainderStr.slice(0, 4).replace(/0+$/, '') || '0';\n return `${whole}.${trimmed}`;\n }\n\n\n async getVaultInfo(targetChainId?: number): Promise<VaultInfo | null> {\n const credential = this.passkey.getCredential();\n if (!credential) {\n throw new VeridexError(VeridexErrorCode.NO_CREDENTIAL);\n }\n\n const chainConfig = this.chain.getConfig();\n const checkChainId = targetChainId ?? chainConfig.wormholeChainId;\n\n if (checkChainId !== chainConfig.wormholeChainId) {\n throw new VeridexError(VeridexErrorCode.UNSUPPORTED_FEATURE, 'Cross-chain vault queries not yet supported. Please create a client for the target chain.');\n }\n\n const vaultAddress = await this.chain.getVaultAddress(credential.keyHash);\n const exists = await this.chain.vaultExists(credential.keyHash);\n\n if (!vaultAddress || !exists) {\n return null;\n }\n\n return {\n address: vaultAddress,\n ownerKeyHash: credential.keyHash,\n chain: chainConfig.name,\n wormholeChainId: chainConfig.wormholeChainId,\n exists,\n };\n }\n\n // ========================================================================\n // Wallet & Identity Methods\n // ========================================================================\n\n /**\n * Get the deterministic vault address for the current credential\n * This computes the address off-chain without requiring the vault to exist\n * \n * @returns The vault address that will be used when vault is created\n */\n getVaultAddress(): string {\n const credential = this.passkey.getCredential();\n if (!credential) {\n throw new VeridexError(VeridexErrorCode.NO_CREDENTIAL);\n }\n\n return this.chain.computeVaultAddress(credential.keyHash);\n }\n\n /**\n * Get the vault address for a specific key hash\n * \n * @param keyHash - The user's key hash\n * @returns The deterministic vault address\n */\n getVaultAddressForKeyHash(keyHash: string): string {\n return this.chain.computeVaultAddress(keyHash);\n }\n\n /**\n * Get the vault address for a specific chain\n * Each EVM chain has its own factory contract, so vault addresses are chain-specific.\n * \n * @param wormholeChainId - The Wormhole chain ID\n * @param keyHash - Optional key hash (defaults to current credential)\n * @returns The deterministic vault address for that chain, or null if chain not supported\n */\n getVaultAddressForChain(wormholeChainId: number, keyHash?: string): string | null {\n const hash = keyHash ?? this.passkey.getCredential()?.keyHash;\n if (!hash) {\n throw new VeridexError(VeridexErrorCode.NO_CREDENTIAL, 'No credential set and no keyHash provided');\n }\n\n const credential = { keyHash: hash } as PasskeyCredential;\n const derived = this.chainDetector.deriveVaultAddress(credential, wormholeChainId);\n return derived?.address ?? null;\n }\n\n /**\n * Get vault balances for a specific chain\n * Unlike getVaultBalances() which uses the hub chain, this fetches for any EVM chain.\n * \n * @param wormholeChainId - The Wormhole chain ID\n * @param includeZeroBalances - Whether to include tokens with 0 balance\n * @returns PortfolioBalance with all token balances for that chain\n */\n async getVaultBalancesForChain(\n wormholeChainId: number,\n includeZeroBalances: boolean = false\n ): Promise<PortfolioBalance> {\n const credential = this.passkey.getCredential();\n if (!credential) {\n throw new VeridexError(VeridexErrorCode.NO_CREDENTIAL);\n }\n\n // Get the correct vault address for this chain\n const vaultAddress = this.getVaultAddressForChain(wormholeChainId, credential.keyHash);\n if (!vaultAddress) {\n throw new VeridexError(VeridexErrorCode.VAULT_NOT_FOUND, `Cannot derive vault address for chain ${wormholeChainId}`);\n }\n\n const chainConfig = this.chainDetector.getChainConfig(wormholeChainId);\n if (!chainConfig) {\n throw new VeridexError(VeridexErrorCode.UNSUPPORTED_FEATURE, `Unknown chain ${wormholeChainId}`);\n }\n\n // Try Wormhole Queries first for faster, attested results\n if (this.queryApiKey) {\n try {\n const tokenList = getAllTokens(wormholeChainId);\n const erc20Tokens = tokenList\n .filter((t) => !isNativeToken(t.address))\n .map((t) => t.address);\n\n const rpcUrl = this.chainRpcUrls?.[wormholeChainId] ?? chainConfig.rpcUrl;\n \n const { queryPortfolio } = await import('../queries/portfolio.js');\n const result = await queryPortfolio(credential.keyHash, this.queryApiKey, {\n network: this.testnet ? 'testnet' : 'mainnet',\n vaultAddresses: { [wormholeChainId]: vaultAddress },\n evmTokenAddresses: { [wormholeChainId]: erc20Tokens },\n rpcUrls: { [wormholeChainId]: rpcUrl },\n maxAge: 60,\n timeout: this.testnet ? 15_000 : 10_000,\n maxAttempts: this.testnet ? 3 : 2,\n });\n\n const chain = result.chains.find((c) => c.wormholeChainId === wormholeChainId);\n if (chain && !chain.error) {\n const byAssetId = new Map(chain.balances.map((b) => [b.assetId.toLowerCase(), b] as const));\n const tokens = tokenList.map((t) => {\n if (isNativeToken(t.address)) {\n return null;\n }\n const found = byAssetId.get(t.address.toLowerCase());\n const amount = found?.amount ?? 0n;\n const formatted = ethers.formatUnits(amount, t.decimals);\n return {\n token: t,\n balance: amount,\n formatted,\n usdValue: found?.usdValue,\n };\n }).filter((t): t is NonNullable<typeof t> => !!t);\n\n // Add native token via RPC\n const native = await this.balance.getNativeBalance(wormholeChainId, vaultAddress);\n const merged = [native, ...tokens];\n\n const filtered = includeZeroBalances ? merged : merged.filter((t) => t.balance > 0n);\n const totalUsdValue = filtered.reduce((sum, t) => sum + (t.usdValue ?? 0), 0);\n\n return {\n wormholeChainId,\n chainName: chainConfig.name,\n address: vaultAddress,\n tokens: filtered,\n totalUsdValue: totalUsdValue || undefined,\n lastUpdated: Date.now(),\n };\n }\n } catch {\n // Fall back to RPC-based balance fetching\n }\n }\n\n // Fallback to RPC-based balance fetching\n return await this.balance.getPortfolioBalance(wormholeChainId, vaultAddress, includeZeroBalances);\n }\n\n /**\n * Get unified identity with addresses across chains\n * \n * @returns UnifiedIdentity containing credential info and chain addresses\n */\n async getUnifiedIdentity(): Promise<UnifiedIdentity> {\n const credential = this.passkey.getCredential();\n if (!credential) {\n throw new VeridexError(VeridexErrorCode.NO_CREDENTIAL);\n }\n\n // Check if we have cached identity\n if (this.unifiedIdentity && this.unifiedIdentity.keyHash === credential.keyHash) {\n return this.unifiedIdentity;\n }\n\n // Try to load from storage first\n const storedIdentity = this.wallet.loadIdentityFromStorage(credential.keyHash);\n if (storedIdentity) {\n this.unifiedIdentity = storedIdentity;\n // Update deployment status from chain\n await this.updateDeploymentStatus();\n return this.unifiedIdentity;\n }\n\n // Build new identity\n const chainConfig = this.chain.getConfig();\n const addresses: ChainAddress[] = [];\n\n // Compute address for current chain\n try {\n const address = this.chain.computeVaultAddress(credential.keyHash);\n const deployed = await this.chain.vaultExists(credential.keyHash);\n \n addresses.push({\n wormholeChainId: chainConfig.wormholeChainId,\n chainName: chainConfig.name,\n address,\n isEvm: chainConfig.isEvm,\n deployed,\n derivationType: 'create2',\n });\n } catch (error) {\n console.warn('Could not compute vault address for current chain:', error);\n }\n\n this.unifiedIdentity = {\n keyHash: credential.keyHash,\n publicKeyX: credential.publicKeyX,\n publicKeyY: credential.publicKeyY,\n credentialId: credential.credentialId,\n addresses,\n createdAt: Date.now(),\n updatedAt: Date.now(),\n };\n\n return this.unifiedIdentity;\n }\n\n /**\n * Get the current chain address from unified identity\n */\n async getCurrentChainAddress(): Promise<ChainAddress | null> {\n const identity = await this.getUnifiedIdentity();\n const chainConfig = this.chain.getConfig();\n \n return identity.addresses.find(\n a => a.wormholeChainId === chainConfig.wormholeChainId\n ) ?? null;\n }\n\n /**\n * Update deployment status for cached identity\n */\n private async updateDeploymentStatus(): Promise<void> {\n if (!this.unifiedIdentity) return;\n\n const chainConfig = this.chain.getConfig();\n const address = this.unifiedIdentity.addresses.find(\n a => a.wormholeChainId === chainConfig.wormholeChainId\n );\n\n if (address) {\n try {\n const deployed = await this.chain.vaultExists(this.unifiedIdentity.keyHash);\n address.deployed = deployed;\n this.unifiedIdentity.updatedAt = Date.now();\n } catch (error) {\n console.warn('Could not update deployment status:', error);\n }\n }\n }\n\n /**\n * Add a chain address to the unified identity\n * Used when configuring multiple chains\n */\n addChainAddress(address: ChainAddress): void {\n if (!this.unifiedIdentity) {\n throw new VeridexError(VeridexErrorCode.NO_CREDENTIAL, 'No identity loaded. Call getUnifiedIdentity() first.');\n }\n\n const existing = this.unifiedIdentity.addresses.findIndex(\n a => a.wormholeChainId === address.wormholeChainId\n );\n\n if (existing >= 0) {\n this.unifiedIdentity.addresses[existing] = address;\n } else {\n this.unifiedIdentity.addresses.push(address);\n }\n\n this.unifiedIdentity.updatedAt = Date.now();\n }\n\n // ========================================================================\n // Vault Creation Methods\n // ========================================================================\n\n /**\n * Create a vault for the current credential\n * \n * @param signer - The signer to pay for gas\n * @returns VaultCreationResult with address and transaction details\n */\n async createVault(signer: any): Promise<VaultCreationResult> {\n const credential = this.passkey.getCredential();\n if (!credential) {\n throw new VeridexError(VeridexErrorCode.NO_CREDENTIAL);\n }\n\n const result = await this.chain.createVault(credential.keyHash, signer);\n\n // Update cached identity if available\n if (this.unifiedIdentity) {\n const chainConfig = this.chain.getConfig();\n const address = this.unifiedIdentity.addresses.find(\n a => a.wormholeChainId === chainConfig.wormholeChainId\n );\n\n if (address) {\n address.deployed = true;\n address.deploymentTxHash = result.transactionHash;\n } else {\n this.unifiedIdentity.addresses.push({\n wormholeChainId: chainConfig.wormholeChainId,\n chainName: chainConfig.name,\n address: result.address,\n isEvm: chainConfig.isEvm,\n deployed: true,\n deploymentTxHash: result.transactionHash,\n derivationType: 'create2',\n });\n }\n\n this.unifiedIdentity.updatedAt = Date.now();\n }\n\n return result;\n }\n\n /**\n * Create a vault with sponsored gas (Veridex pays for gas)\n * \n * Uses the sponsor wallet configured in SDK initialization.\n * If no sponsor is configured, throws an error.\n * \n * @param wormholeChainId - Optional chain ID for multi-chain creation\n * @returns VaultCreationResult with address and transaction details\n */\n async createVaultSponsored(wormholeChainId?: number): Promise<VaultCreationResult> {\n const credential = this.passkey.getCredential();\n if (!credential) {\n throw new VeridexError(VeridexErrorCode.NO_CREDENTIAL);\n }\n\n if (!this.sponsorPrivateKey) {\n throw new VeridexError(VeridexErrorCode.UNSUPPORTED_FEATURE, 'No sponsor wallet configured. Set sponsorPrivateKey in SDK config.');\n }\n\n // Check if chain client supports sponsored creation\n if (!this.chain.createVaultSponsored) {\n throw new VeridexError(VeridexErrorCode.UNSUPPORTED_FEATURE, 'Current chain client does not support sponsored vault creation');\n }\n\n // Get the appropriate RPC URL for the chain\n const chainConfig = this.chain.getConfig();\n const targetChainId = wormholeChainId ?? chainConfig.wormholeChainId;\n const rpcUrl = this.chainRpcUrls?.[targetChainId] ?? chainConfig.rpcUrl;\n\n const result = await this.chain.createVaultSponsored(\n credential.keyHash,\n this.sponsorPrivateKey,\n rpcUrl\n );\n\n // Update cached identity if available\n if (this.unifiedIdentity) {\n const address = this.unifiedIdentity.addresses.find(\n a => a.wormholeChainId === targetChainId\n );\n\n if (address) {\n address.deployed = true;\n address.deploymentTxHash = result.transactionHash;\n } else {\n this.unifiedIdentity.addresses.push({\n wormholeChainId: targetChainId,\n chainName: chainConfig.name,\n address: result.address,\n isEvm: chainConfig.isEvm,\n deployed: true,\n deploymentTxHash: result.transactionHash,\n derivationType: 'create2',\n });\n }\n\n this.unifiedIdentity.updatedAt = Date.now();\n }\n\n return result;\n }\n\n /**\n * Check if sponsored vault creation is available\n */\n hasSponsoredVaultCreation(): boolean {\n return !!this.sponsorPrivateKey && !!this.chain.createVaultSponsored;\n }\n\n /**\n * Ensure vault exists, creating with sponsor if available\n * Falls back to requiring a signer if no sponsor configured\n * \n * @param signer - Optional signer (only required if no sponsor configured)\n * @returns The vault address\n */\n async ensureVaultAuto(signer?: any): Promise<string> {\n const credential = this.passkey.getCredential();\n if (!credential) {\n throw new VeridexError(VeridexErrorCode.NO_CREDENTIAL);\n }\n\n const exists = await this.chain.vaultExists(credential.keyHash);\n if (exists) {\n return this.getVaultAddress();\n }\n\n // Try sponsored creation first\n if (this.hasSponsoredVaultCreation()) {\n const result = await this.createVaultSponsored();\n return result.address;\n }\n\n // Fall back to signer-based creation\n if (!signer) {\n throw new VeridexError(VeridexErrorCode.UNSUPPORTED_FEATURE, 'No sponsor configured and no signer provided for vault creation');\n }\n\n const result = await this.createVault(signer);\n return result.address;\n }\n\n /**\n * Ensure vault exists, creating if necessary\n * \n * @param signer - The signer to pay for gas (only used if creation needed)\n * @returns The vault address\n */\n async ensureVault(signer: any): Promise<string> {\n const credential = this.passkey.getCredential();\n if (!credential) {\n throw new VeridexError(VeridexErrorCode.NO_CREDENTIAL);\n }\n\n const exists = await this.chain.vaultExists(credential.keyHash);\n if (exists) {\n return this.getVaultAddress();\n }\n\n const result = await this.createVault(signer);\n return result.address;\n }\n\n /**\n * Estimate gas for vault creation\n */\n async estimateVaultCreationGas(): Promise<bigint> {\n const credential = this.passkey.getCredential();\n if (!credential) {\n throw new VeridexError(VeridexErrorCode.NO_CREDENTIAL);\n }\n\n return await this.chain.estimateVaultCreationGas(credential.keyHash);\n }\n\n async vaultExists(): Promise<boolean> {\n const credential = this.passkey.getCredential();\n if (!credential) {\n throw new VeridexError(VeridexErrorCode.NO_CREDENTIAL);\n }\n\n return await this.chain.vaultExists(credential.keyHash);\n }\n\n // ========================================================================\n // Sponsored Vault Creation (Gasless)\n // ========================================================================\n\n /**\n * Check if gas sponsorship is configured\n * \n * @returns true if a sponsor is configured (relayer, integrator, or Veridex)\n */\n isSponsorshipAvailable(): boolean {\n return this.sponsor.isConfigured();\n }\n\n /**\n * Get the active sponsorship source\n * \n * Priority order:\n * 1. 'relayer' - Remote relayer service (future primary)\n * 2. 'integrator' - Platform-provided sponsor key\n * 3. 'veridex' - Veridex default sponsor (fallback)\n * 4. 'none' - No sponsorship available\n * \n * @returns The active sponsorship source\n */\n getSponsorshipSource(): 'relayer' | 'integrator' | 'veridex' | 'none' {\n return this.sponsor.getSponsorshipSource();\n }\n\n /**\n * Get supported chains for sponsored vault creation\n * \n * @returns Array of chain configurations\n */\n getSponsoredChains(): ChainDeploymentConfig[] {\n return this.sponsor.getSupportedChains();\n }\n\n /**\n * Create a vault on a specific chain using gas sponsorship\n * User doesn't need to pay gas - Veridex pays\n * \n * @param wormholeChainId - The Wormhole chain ID to create vault on\n * @returns Result with vault address\n */\n async createSponsoredVault(wormholeChainId: number): Promise<SponsoredVaultResult> {\n const credential = this.passkey.getCredential();\n if (!credential) {\n throw new VeridexError(VeridexErrorCode.NO_CREDENTIAL);\n }\n\n if (!this.sponsor.isConfigured()) {\n throw new VeridexError(VeridexErrorCode.UNSUPPORTED_FEATURE, 'Gas sponsorship not configured. Set sponsorPrivateKey in SDK config.');\n }\n\n const result = await this.sponsor.createVaultOnChain(credential.keyHash, wormholeChainId);\n\n // Update cached identity if successful\n if (result.success && result.vaultAddress && this.unifiedIdentity) {\n const existingAddress = this.unifiedIdentity.addresses.find(\n a => a.wormholeChainId === wormholeChainId\n );\n\n if (existingAddress) {\n existingAddress.deployed = true;\n existingAddress.deploymentTxHash = result.transactionHash;\n existingAddress.address = result.vaultAddress;\n } else {\n this.unifiedIdentity.addresses.push({\n wormholeChainId,\n chainName: result.chain,\n address: result.vaultAddress,\n isEvm: true,\n deployed: true,\n deploymentTxHash: result.transactionHash,\n derivationType: 'create2',\n });\n }\n\n this.unifiedIdentity.updatedAt = Date.now();\n }\n\n return result;\n }\n\n /**\n * Create vaults on all supported chains using gas sponsorship\n * User doesn't need to pay gas - Veridex pays\n * \n * @returns Multi-chain result with all vault addresses\n */\n async createSponsoredVaultsOnAllChains(): Promise<MultiChainVaultResult> {\n const credential = this.passkey.getCredential();\n if (!credential) {\n throw new VeridexError(VeridexErrorCode.NO_CREDENTIAL);\n }\n\n if (!this.sponsor.isConfigured()) {\n throw new VeridexError(VeridexErrorCode.UNSUPPORTED_FEATURE, 'Gas sponsorship not configured. Set sponsorPrivateKey in SDK config.');\n }\n\n const result = await this.sponsor.createVaultsOnAllChains(credential.keyHash);\n\n // Update cached identity with all successful vaults\n if (this.unifiedIdentity) {\n for (const vaultResult of result.results) {\n if (vaultResult.success && vaultResult.vaultAddress) {\n const existingAddress = this.unifiedIdentity.addresses.find(\n a => a.wormholeChainId === vaultResult.wormholeChainId\n );\n\n if (existingAddress) {\n existingAddress.deployed = true;\n existingAddress.deploymentTxHash = vaultResult.transactionHash;\n existingAddress.address = vaultResult.vaultAddress;\n } else {\n this.unifiedIdentity.addresses.push({\n wormholeChainId: vaultResult.wormholeChainId,\n chainName: vaultResult.chain,\n address: vaultResult.vaultAddress,\n isEvm: true,\n deployed: true,\n deploymentTxHash: vaultResult.transactionHash,\n derivationType: 'create2',\n });\n }\n }\n }\n\n this.unifiedIdentity.updatedAt = Date.now();\n }\n\n return result;\n }\n\n /**\n * Check if vaults exist on all supported chains\n * \n * @returns Map of chain ID to vault status\n */\n async checkVaultsOnAllChains(): Promise<Record<number, { exists: boolean; address: string }>> {\n const credential = this.passkey.getCredential();\n if (!credential) {\n throw new VeridexError(VeridexErrorCode.NO_CREDENTIAL);\n }\n\n return await this.sponsor.checkVaultsOnAllChains(credential.keyHash);\n }\n\n /**\n * Ensure vaults exist on all chains, creating if necessary (sponsored)\n * \n * @returns Result with all vault addresses\n */\n async ensureSponsoredVaultsOnAllChains(): Promise<MultiChainVaultResult> {\n const credential = this.passkey.getCredential();\n if (!credential) {\n throw new VeridexError(VeridexErrorCode.NO_CREDENTIAL);\n }\n\n // First check which vaults exist\n const existing = await this.checkVaultsOnAllChains();\n \n // Find chains that need vault creation\n const supportedChains = this.sponsor.getSupportedChains();\n const needsCreation = supportedChains.filter(\n chain => !existing[chain.wormholeChainId]?.exists\n );\n\n if (needsCreation.length === 0) {\n // All vaults exist\n const vaultAddresses: Record<number, string> = {};\n const results: SponsoredVaultResult[] = [];\n\n for (const chain of supportedChains) {\n const status = existing[chain.wormholeChainId];\n vaultAddresses[chain.wormholeChainId] = status?.address || '';\n results.push({\n success: true,\n chain: chain.name,\n wormholeChainId: chain.wormholeChainId,\n vaultAddress: status?.address,\n alreadyExists: true,\n });\n }\n\n return {\n keyHash: credential.keyHash,\n results,\n allSuccessful: true,\n vaultAddresses,\n };\n }\n\n // Create missing vaults\n return await this.createSponsoredVaultsOnAllChains();\n }\n\n // ==========================================================================\n // Backup Passkey / Multi-Key Identity Methods (Issue #22)\n // ==========================================================================\n\n /**\n * Get the identity state for the current passkey\n * Returns information about the identity including key count and root status\n * \n * @returns Identity state or null if no credential set\n */\n async getIdentityState(): Promise<IdentityState | null> {\n const credential = this.passkey.getCredential();\n if (!credential) {\n return null;\n }\n\n const evmClient = this.chain as any;\n if (typeof evmClient.getIdentityState !== 'function') {\n throw new VeridexError(VeridexErrorCode.UNSUPPORTED_FEATURE, 'Identity management not supported on this chain client');\n }\n\n return await evmClient.getIdentityState(credential.keyHash);\n }\n\n /**\n * Get all authorized passkeys for the current identity\n * \n * @returns Array of authorized keys with root status, or null if no credential\n */\n async listAuthorizedPasskeys(): Promise<AuthorizedKey[] | null> {\n const credential = this.passkey.getCredential();\n if (!credential) {\n return null;\n }\n\n const evmClient = this.chain as any;\n if (typeof evmClient.getIdentityState !== 'function') {\n throw new VeridexError(VeridexErrorCode.UNSUPPORTED_FEATURE, 'Identity management not supported on this chain client');\n }\n\n // Get the identity for this key\n const state = await evmClient.getIdentityState(credential.keyHash);\n if (!state.identity || state.identity === ethers.ZeroHash) {\n // Key not registered, return just this key as pending\n return [];\n }\n\n // Get all authorized keys for this identity\n const keyHashes: string[] = await evmClient.getAuthorizedKeys(state.identity);\n \n // Map to AuthorizedKey with root status\n return keyHashes.map(keyHash => ({\n keyHash,\n isRoot: keyHash === state.identity,\n }));\n }\n\n /**\n * Check if the current identity has backup passkeys registered\n * Returns false if only one passkey (the root) is registered\n * \n * @returns True if backup passkeys exist, false otherwise\n */\n async hasBackupPasskeys(): Promise<boolean> {\n const state = await this.getIdentityState();\n if (!state || state.keyCount === 0) {\n return false;\n }\n return state.keyCount > 1;\n }\n\n /**\n * Register a backup passkey for the current identity\n * The backup passkey can be used to recover access if the primary is lost\n * \n * @param newCredential The new passkey credential to add as backup\n * @param signer Ethereum signer to pay gas (optional, uses relayer if not provided)\n * @returns Result with transaction hash and sequence for cross-chain sync\n */\n async addBackupPasskey(\n newCredential: PasskeyCredential,\n signer?: any\n ): Promise<AddBackupKeyResult> {\n const credential = this.passkey.getCredential();\n if (!credential) {\n throw new VeridexError(VeridexErrorCode.NO_CREDENTIAL);\n }\n\n const evmClient = this.chain as any;\n if (typeof evmClient.addBackupKey !== 'function') {\n throw new VeridexError(VeridexErrorCode.UNSUPPORTED_FEATURE, 'Backup passkey management not supported on this chain client');\n }\n\n // Get identity state to ensure we're within limits\n const state = await evmClient.getIdentityState(credential.keyHash);\n if (state.keyCount >= state.maxKeys) {\n throw new VeridexError(VeridexErrorCode.UNAUTHORIZED, `Maximum keys (${state.maxKeys}) already registered for this identity`);\n }\n\n // Check if the new key is already authorized\n const isAlreadyAuthorized = await evmClient.isAuthorizedForIdentity(\n state.identity,\n newCredential.keyHash\n );\n if (isAlreadyAuthorized) {\n throw new VeridexError(VeridexErrorCode.INVALID_ACTION, 'This passkey is already authorized for this identity');\n }\n\n if (!state.identity || state.identity === ethers.ZeroHash) {\n throw new VeridexError(VeridexErrorCode.VAULT_NOT_FOUND, 'Identity not registered. Call registerIdentity() first.');\n }\n\n // Nonce for key-management is stored on the *identity* (not necessarily the signing key)\n const nonce = await this.chain.getNonce(state.identity);\n\n // Challenge = abi.encodePacked(\"VERIDEX_ADD_KEY\", identityKeyHash, newKeyHash, nonce)\n const packedChallenge = ethers.solidityPacked(\n ['string', 'bytes32', 'bytes32', 'uint256'],\n ['VERIDEX_ADD_KEY', state.identity, newCredential.keyHash, nonce]\n );\n\n const signature = await this.passkey.sign(ethers.getBytes(packedChallenge));\n\n if (!signer) {\n throw new VeridexError(VeridexErrorCode.INVALID_ACTION, 'Signer required for backup key registration');\n }\n\n // Call Hub contract to add backup key\n const { receipt, sequence } = await evmClient.addBackupKey(\n signature,\n credential.publicKeyX,\n credential.publicKeyY,\n newCredential.publicKeyX,\n newCredential.publicKeyY,\n nonce,\n signer\n );\n\n // Get updated key count\n const updatedState = await evmClient.getIdentityState(credential.keyHash);\n\n return {\n transactionHash: receipt.hash,\n sequence,\n identity: state.identity,\n newKeyHash: newCredential.keyHash,\n keyCount: updatedState.keyCount,\n };\n }\n\n /**\n * Remove a passkey from the current identity\n * Cannot remove the last remaining passkey\n * \n * @param keyToRemove Hash of the passkey to remove\n * @param signer Ethereum signer to pay gas\n * @returns Result with transaction hash and sequence for cross-chain sync\n */\n async removePasskey(\n keyToRemove: string,\n signer: any\n ): Promise<RemoveKeyResult> {\n const credential = this.passkey.getCredential();\n if (!credential) {\n throw new VeridexError(VeridexErrorCode.NO_CREDENTIAL);\n }\n\n const evmClient = this.chain as any;\n if (typeof evmClient.removeKey !== 'function') {\n throw new VeridexError(VeridexErrorCode.UNSUPPORTED_FEATURE, 'Backup passkey management not supported on this chain client');\n }\n\n // Get identity state\n const state = await evmClient.getIdentityState(credential.keyHash);\n if (state.keyCount <= 1) {\n throw new VeridexError(VeridexErrorCode.INVALID_ACTION, 'Cannot remove the last passkey. At least one must remain.');\n }\n\n // Check if the key to remove is actually authorized\n const isAuthorized = await evmClient.isAuthorizedForIdentity(\n state.identity,\n keyToRemove\n );\n if (!isAuthorized) {\n throw new VeridexError(VeridexErrorCode.UNAUTHORIZED, 'The specified passkey is not authorized for this identity');\n }\n\n if (!state.identity || state.identity === ethers.ZeroHash) {\n throw new VeridexError(VeridexErrorCode.VAULT_NOT_FOUND, 'Identity not registered. Call registerIdentity() first.');\n }\n\n // Nonce for key-management is stored on the *identity*\n const nonce = await this.chain.getNonce(state.identity);\n\n // Challenge = abi.encodePacked(\"VERIDEX_REMOVE_KEY\", identityKeyHash, keyToRemove, nonce)\n const packedChallenge = ethers.solidityPacked(\n ['string', 'bytes32', 'bytes32', 'uint256'],\n ['VERIDEX_REMOVE_KEY', state.identity, keyToRemove, nonce]\n );\n\n const signature = await this.passkey.sign(ethers.getBytes(packedChallenge));\n\n // Call Hub contract to remove key\n const { receipt, sequence } = await evmClient.removeKey(\n signature,\n credential.publicKeyX,\n credential.publicKeyY,\n keyToRemove,\n nonce,\n signer\n );\n\n // Get updated key count\n const updatedState = await evmClient.getIdentityState(credential.keyHash);\n\n return {\n transactionHash: receipt.hash,\n sequence,\n identity: state.identity,\n removedKeyHash: keyToRemove,\n keyCount: updatedState.keyCount,\n };\n }\n\n /**\n * Check if a specific passkey is authorized for the current identity\n * \n * @param keyHash Hash of the passkey to check\n * @returns True if authorized, false otherwise\n */\n async isPasskeyAuthorized(keyHash: string): Promise<boolean> {\n const credential = this.passkey.getCredential();\n if (!credential) {\n return false;\n }\n\n const evmClient = this.chain as any;\n if (typeof evmClient.getIdentityState !== 'function') {\n throw new VeridexError(VeridexErrorCode.UNSUPPORTED_FEATURE, 'Identity management not supported on this chain client');\n }\n\n const state = await evmClient.getIdentityState(credential.keyHash);\n if (!state.identity || state.identity === ethers.ZeroHash) {\n return false;\n }\n\n return await evmClient.isAuthorizedForIdentity(state.identity, keyHash);\n }\n\n /**\n * Get the identity hash for the current passkey\n * This is the keyHash of the first/root passkey registered\n * \n * @returns Identity hash or null if no credential/identity\n */\n async getIdentity(): Promise<string | null> {\n const credential = this.passkey.getCredential();\n if (!credential) {\n return null;\n }\n\n const evmClient = this.chain as any;\n if (typeof evmClient.getIdentityForKey !== 'function') {\n // Fallback: return keyHash as identity (single-key mode)\n return credential.keyHash;\n }\n\n const identity = await evmClient.getIdentityForKey(credential.keyHash);\n if (identity === ethers.ZeroHash) {\n // Not registered yet, return current keyHash\n return credential.keyHash;\n }\n\n return identity;\n }\n\n getCredential(): PasskeyCredential | null {\n return this.passkey.getCredential();\n }\n\n setCredential(credential: PasskeyCredential): void {\n this.passkey.setCredential(credential);\n }\n\n hasCredential(): boolean {\n return this.passkey.getCredential() !== null;\n }\n\n clearCredential(): void {\n this.passkey.clearCredential();\n }\n}\n","/**\n * Gas Sponsor Module\n * \n * Handles sponsored (gasless) vault creation for Veridex users.\n * Uses a Veridex-owned wallet to pay gas fees on behalf of users.\n * \n * This is a temporary solution until the full relayer is built.\n * In the future, this will be handled by:\n * - ERC-4337 Account Abstraction with Paymasters\n * - Dedicated Relayer service\n */\n\nimport { ethers } from 'ethers';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface ChainDeploymentConfig {\n name: string;\n chainId: number;\n wormholeChainId: number;\n rpcUrl: string;\n vaultFactory?: string;\n hubAddress?: string;\n isHub?: boolean;\n}\n\nexport interface SponsoredVaultResult {\n success: boolean;\n chain: string;\n wormholeChainId: number;\n vaultAddress?: string;\n transactionHash?: string;\n error?: string;\n alreadyExists?: boolean;\n}\n\nexport interface MultiChainVaultResult {\n keyHash: string;\n results: SponsoredVaultResult[];\n allSuccessful: boolean;\n vaultAddresses: Record<number, string>; // wormholeChainId -> address\n}\n\nexport interface GasSponsorConfig {\n /** \n * Private key for the sponsor wallet (from env or secure storage)\n * This is the fallback when relayer is not available\n */\n sponsorPrivateKey?: string;\n \n /**\n * Integrator-provided sponsor key (for platforms using Veridex SDK)\n * Takes priority over Veridex default sponsorship\n */\n integratorSponsorKey?: string;\n \n /** \n * Relayer API endpoint for remote sponsorship (primary method)\n * When available, this takes priority over local wallet sponsorship\n */\n relayerUrl?: string;\n \n /** API key for relayer service authentication */\n relayerApiKey?: string;\n \n /** @deprecated Use relayerUrl instead */\n sponsorApiUrl?: string;\n /** @deprecated Use relayerApiKey instead */\n sponsorApiKey?: string;\n \n /** Whether to use testnet configurations */\n testnet?: boolean;\n /** Custom RPC URLs by wormhole chain ID */\n customRpcUrls?: Record<number, string>;\n}\n\n/** Sponsorship source type */\nexport type SponsorshipSource = 'relayer' | 'integrator' | 'veridex' | 'none';\n\n// ============================================================================\n// Constants\n// ============================================================================\n\n// Vault Factory ABI (minimal)\nconst VAULT_FACTORY_ABI = [\n 'function createVault(bytes32 ownerKeyHash) external returns (address)',\n 'function getVault(bytes32 ownerKeyHash) external view returns (address)',\n 'function vaultExists(bytes32 ownerKeyHash) external view returns (bool)',\n 'function computeVaultAddress(bytes32 ownerKeyHash) external view returns (address)',\n 'event VaultCreated(address indexed vault, bytes32 indexed ownerKeyHash, address creator)',\n];\n\n// Testnet chain configurations\nconst TESTNET_CHAINS: ChainDeploymentConfig[] = [\n {\n name: 'Base Sepolia',\n chainId: 84532,\n wormholeChainId: 10004,\n rpcUrl: 'https://sepolia.base.org',\n hubAddress: '0x23a39c294891703146c3607e1FEEB5Fe78F7F28d',\n vaultFactory: '0x31e8dc9428575334739754Ab2bdB0E8b9Dc707FD',\n isHub: true,\n },\n {\n name: 'Optimism Sepolia',\n chainId: 11155420,\n wormholeChainId: 10005,\n rpcUrl: 'https://sepolia.optimism.io',\n vaultFactory: '0x347feeaBB5655a7a80b56D8D554DA30BE6c28225',\n },\n {\n name: 'Arbitrum Sepolia',\n chainId: 421614,\n wormholeChainId: 10003,\n rpcUrl: 'https://sepolia-rollup.arbitrum.io/rpc',\n vaultFactory: '0x708eEE22621A64CDF51d98d3e8D97902D7dF52dD',\n },\n];\n\n// Mainnet chain configurations (for future use)\nconst MAINNET_CHAINS: ChainDeploymentConfig[] = [\n // Will be populated when mainnet is ready\n];\n\n// ============================================================================\n// GasSponsor Class\n// ============================================================================\n\n/**\n * Gas Sponsorship with layered fallback:\n * 1. Relayer (primary) - Remote relayer service handles gas\n * 2. Integrator wallet - Platform using SDK provides their own sponsor key\n * 3. Veridex wallet (fallback) - Veridex's default sponsor wallet\n */\nexport class GasSponsor {\n private config: GasSponsorConfig;\n private sponsorWallet?: ethers.Wallet;\n private integratorWallet?: ethers.Wallet;\n private chains: ChainDeploymentConfig[];\n\n constructor(config: GasSponsorConfig = {}) {\n this.config = config;\n this.chains = config.testnet !== false ? TESTNET_CHAINS : MAINNET_CHAINS;\n\n // Initialize integrator wallet if provided (takes priority)\n if (config.integratorSponsorKey) {\n this.integratorWallet = new ethers.Wallet(config.integratorSponsorKey);\n }\n\n // Initialize Veridex sponsor wallet as fallback\n if (config.sponsorPrivateKey) {\n this.sponsorWallet = new ethers.Wallet(config.sponsorPrivateKey);\n }\n }\n\n /**\n * Determine which sponsorship source is available\n * Priority: Relayer > Integrator > Veridex > None\n */\n getSponsorshipSource(): SponsorshipSource {\n // 1. Check relayer first (future primary method)\n if (this.config.relayerUrl || this.config.sponsorApiUrl) {\n return 'relayer';\n }\n \n // 2. Check integrator-provided wallet\n if (this.integratorWallet) {\n return 'integrator';\n }\n \n // 3. Check Veridex fallback wallet\n if (this.sponsorWallet) {\n return 'veridex';\n }\n \n return 'none';\n }\n\n /**\n * Get the active sponsor wallet (integrator takes priority)\n */\n private getActiveWallet(): ethers.Wallet | undefined {\n return this.integratorWallet || this.sponsorWallet;\n }\n\n /**\n * Get supported chains for vault deployment\n */\n getSupportedChains(): ChainDeploymentConfig[] {\n return this.chains.filter(c => c.vaultFactory);\n }\n\n /**\n * Get the hub chain configuration\n */\n getHubChain(): ChainDeploymentConfig | undefined {\n return this.chains.find(c => c.isHub);\n }\n\n /**\n * Check if sponsor is configured (has relayer, integrator key, or Veridex key)\n */\n isConfigured(): boolean {\n return this.getSponsorshipSource() !== 'none';\n }\n\n /**\n * Get sponsor wallet balance on a specific chain\n */\n async getSponsorBalance(wormholeChainId: number): Promise<bigint> {\n const chain = this.chains.find(c => c.wormholeChainId === wormholeChainId);\n const wallet = this.getActiveWallet();\n if (!chain || !wallet) {\n return BigInt(0);\n }\n\n const rpcUrl = this.config.customRpcUrls?.[wormholeChainId] || chain.rpcUrl;\n const provider = new ethers.JsonRpcProvider(rpcUrl);\n return await provider.getBalance(wallet.address);\n }\n\n /**\n * Check if a vault exists for a given key hash on a chain\n */\n async checkVaultExists(\n keyHash: string,\n wormholeChainId: number\n ): Promise<{ exists: boolean; address: string }> {\n const chain = this.chains.find(c => c.wormholeChainId === wormholeChainId);\n if (!chain || !chain.vaultFactory) {\n return { exists: false, address: ethers.ZeroAddress };\n }\n\n const rpcUrl = this.config.customRpcUrls?.[wormholeChainId] || chain.rpcUrl;\n const provider = new ethers.JsonRpcProvider(rpcUrl);\n const factory = new ethers.Contract(chain.vaultFactory, VAULT_FACTORY_ABI, provider);\n\n try {\n const address = await factory.getVault(keyHash);\n const exists = address !== ethers.ZeroAddress;\n return { exists, address };\n } catch (error) {\n console.error(`Error checking vault on ${chain.name}:`, error);\n return { exists: false, address: ethers.ZeroAddress };\n }\n }\n\n /**\n * Get predicted vault address for a key hash on a chain\n */\n async computeVaultAddress(\n keyHash: string,\n wormholeChainId: number\n ): Promise<string | null> {\n const chain = this.chains.find(c => c.wormholeChainId === wormholeChainId);\n if (!chain || !chain.vaultFactory) {\n return null;\n }\n\n const rpcUrl = this.config.customRpcUrls?.[wormholeChainId] || chain.rpcUrl;\n const provider = new ethers.JsonRpcProvider(rpcUrl);\n const factory = new ethers.Contract(chain.vaultFactory, VAULT_FACTORY_ABI, provider);\n\n try {\n return await factory.computeVaultAddress(keyHash);\n } catch (error) {\n console.error(`Error computing vault address on ${chain.name}:`, error);\n return null;\n }\n }\n\n /**\n * Create a vault on a specific chain (sponsored)\n * \n * Sponsorship priority:\n * 1. Relayer API (future - not yet implemented)\n * 2. Integrator wallet (if provided)\n * 3. Veridex sponsor wallet (fallback)\n */\n async createVaultOnChain(\n keyHash: string,\n wormholeChainId: number\n ): Promise<SponsoredVaultResult> {\n const chain = this.chains.find(c => c.wormholeChainId === wormholeChainId);\n \n if (!chain) {\n return {\n success: false,\n chain: 'Unknown',\n wormholeChainId,\n error: `Chain ${wormholeChainId} not found`,\n };\n }\n\n if (!chain.vaultFactory) {\n return {\n success: false,\n chain: chain.name,\n wormholeChainId,\n error: `No vault factory configured for ${chain.name}`,\n };\n }\n\n const source = this.getSponsorshipSource();\n\n // 1. Check if using relayer API (future primary method)\n if (source === 'relayer') {\n const relayerUrl = this.config.relayerUrl || this.config.sponsorApiUrl;\n if (relayerUrl) {\n return await this.createVaultViaRelayer(keyHash, chain, relayerUrl);\n }\n }\n\n // 2. Use local wallet (integrator or Veridex)\n const wallet = this.getActiveWallet();\n if (!wallet) {\n return {\n success: false,\n chain: chain.name,\n wormholeChainId,\n error: 'No sponsor configured. Set VERIDEX_SPONSOR_KEY or provide integratorSponsorKey.',\n };\n }\n\n const sponsorType = source === 'integrator' ? 'Integrator' : 'Veridex';\n\n try {\n const rpcUrl = this.config.customRpcUrls?.[wormholeChainId] || chain.rpcUrl;\n const provider = new ethers.JsonRpcProvider(rpcUrl);\n const signer = wallet.connect(provider);\n const factory = new ethers.Contract(chain.vaultFactory, VAULT_FACTORY_ABI, signer);\n\n // Check if vault already exists\n const existingVault = await factory.getVault(keyHash);\n if (existingVault !== ethers.ZeroAddress) {\n return {\n success: true,\n chain: chain.name,\n wormholeChainId,\n vaultAddress: existingVault,\n alreadyExists: true,\n };\n }\n\n // Check sponsor balance\n const balance = await provider.getBalance(signer.address);\n if (balance < ethers.parseEther('0.001')) {\n return {\n success: false,\n chain: chain.name,\n wormholeChainId,\n error: `Insufficient ${sponsorType} sponsor balance on ${chain.name}`,\n };\n }\n\n // Create vault\n console.log(`[GasSponsor] Creating vault on ${chain.name} (${sponsorType} sponsored)...`);\n const tx = await factory.createVault(keyHash);\n const receipt = await tx.wait();\n\n // Get vault address from event or direct query\n const vaultAddress = await factory.getVault(keyHash);\n\n console.log(`[GasSponsor] OK Vault created on ${chain.name}: ${vaultAddress}`);\n\n return {\n success: true,\n chain: chain.name,\n wormholeChainId,\n vaultAddress,\n transactionHash: receipt.hash,\n };\n } catch (error: any) {\n console.error(`[GasSponsor] Error creating vault on ${chain.name}:`, error);\n return {\n success: false,\n chain: chain.name,\n wormholeChainId,\n error: error.message || 'Unknown error',\n };\n }\n }\n\n /**\n * Create vault via relayer service (future primary method)\n * \n * The relayer handles:\n * - Gas payment on behalf of users\n * - Transaction submission and monitoring\n * - Rate limiting and abuse prevention\n */\n private async createVaultViaRelayer(\n keyHash: string,\n chain: ChainDeploymentConfig,\n relayerUrl: string\n ): Promise<SponsoredVaultResult> {\n try {\n const apiKey = this.config.relayerApiKey || this.config.sponsorApiKey;\n \n const response = await fetch(`${relayerUrl}/create-vault`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n ...(apiKey && {\n 'Authorization': `Bearer ${apiKey}`,\n }),\n },\n body: JSON.stringify({\n keyHash,\n wormholeChainId: chain.wormholeChainId,\n }),\n });\n\n if (!response.ok) {\n const error = await response.text();\n \n // If relayer fails, try fallback to local wallet\n console.warn(`[GasSponsor] Relayer failed, trying local wallet fallback...`);\n const wallet = this.getActiveWallet();\n if (wallet) {\n return await this.createVaultWithWallet(keyHash, chain, wallet);\n }\n \n throw new Error(`Relayer error: ${error}`);\n }\n\n const result = await response.json();\n return {\n success: true,\n chain: chain.name,\n wormholeChainId: chain.wormholeChainId,\n vaultAddress: result.vaultAddress,\n transactionHash: result.transactionHash,\n alreadyExists: result.alreadyExists,\n };\n } catch (error: any) {\n // Fallback to local wallet if relayer fails\n console.warn(`[GasSponsor] Relayer unavailable: ${error.message}`);\n const wallet = this.getActiveWallet();\n if (wallet) {\n console.log(`[GasSponsor] Falling back to local wallet sponsorship...`);\n return await this.createVaultWithWallet(keyHash, chain, wallet);\n }\n \n return {\n success: false,\n chain: chain.name,\n wormholeChainId: chain.wormholeChainId,\n error: error.message || 'Relayer request failed and no fallback available',\n };\n }\n }\n\n /**\n * Create vault with a specific wallet (internal helper)\n */\n private async createVaultWithWallet(\n keyHash: string,\n chain: ChainDeploymentConfig,\n wallet: ethers.Wallet\n ): Promise<SponsoredVaultResult> {\n if (!chain.vaultFactory) {\n return {\n success: false,\n chain: chain.name,\n wormholeChainId: chain.wormholeChainId,\n error: `No vault factory for ${chain.name}`,\n };\n }\n\n try {\n const rpcUrl = this.config.customRpcUrls?.[chain.wormholeChainId] || chain.rpcUrl;\n const provider = new ethers.JsonRpcProvider(rpcUrl);\n const signer = wallet.connect(provider);\n const factory = new ethers.Contract(chain.vaultFactory, VAULT_FACTORY_ABI, signer);\n\n // Check if vault already exists\n const existingVault = await factory.getVault(keyHash);\n if (existingVault !== ethers.ZeroAddress) {\n return {\n success: true,\n chain: chain.name,\n wormholeChainId: chain.wormholeChainId,\n vaultAddress: existingVault,\n alreadyExists: true,\n };\n }\n\n // Check balance\n const balance = await provider.getBalance(signer.address);\n if (balance < ethers.parseEther('0.001')) {\n return {\n success: false,\n chain: chain.name,\n wormholeChainId: chain.wormholeChainId,\n error: `Insufficient sponsor balance on ${chain.name}`,\n };\n }\n\n // Create vault\n const tx = await factory.createVault(keyHash);\n const receipt = await tx.wait();\n const vaultAddress = await factory.getVault(keyHash);\n\n return {\n success: true,\n chain: chain.name,\n wormholeChainId: chain.wormholeChainId,\n vaultAddress,\n transactionHash: receipt.hash,\n };\n } catch (error: any) {\n return {\n success: false,\n chain: chain.name,\n wormholeChainId: chain.wormholeChainId,\n error: error.message || 'Wallet creation failed',\n };\n }\n }\n\n /**\n * Create vaults on all supported chains (sponsored)\n */\n async createVaultsOnAllChains(keyHash: string): Promise<MultiChainVaultResult> {\n const supportedChains = this.getSupportedChains();\n const results: SponsoredVaultResult[] = [];\n const vaultAddresses: Record<number, string> = {};\n\n console.log(`[GasSponsor] Creating vaults on ${supportedChains.length} chains...`);\n\n // Create vaults in parallel (or sequentially for rate limiting)\n for (const chain of supportedChains) {\n const result = await this.createVaultOnChain(keyHash, chain.wormholeChainId);\n results.push(result);\n\n if (result.success && result.vaultAddress) {\n vaultAddresses[chain.wormholeChainId] = result.vaultAddress;\n }\n }\n\n const allSuccessful = results.every(r => r.success);\n\n return {\n keyHash,\n results,\n allSuccessful,\n vaultAddresses,\n };\n }\n\n /**\n * Check vault status on all chains\n */\n async checkVaultsOnAllChains(keyHash: string): Promise<Record<number, { exists: boolean; address: string }>> {\n const supportedChains = this.getSupportedChains();\n const results: Record<number, { exists: boolean; address: string }> = {};\n\n for (const chain of supportedChains) {\n results[chain.wormholeChainId] = await this.checkVaultExists(keyHash, chain.wormholeChainId);\n }\n\n return results;\n }\n}\n\n// ============================================================================\n// Factory Function\n// ============================================================================\n\n/**\n * Create a GasSponsor instance\n * \n * @example\n * ```ts\n * // With environment variable\n * const sponsor = createGasSponsor({\n * sponsorPrivateKey: process.env.VERIDEX_SPONSOR_KEY,\n * testnet: true,\n * });\n * \n * // Create vaults for a user\n * const result = await sponsor.createVaultsOnAllChains(userKeyHash);\n * ```\n */\nexport function createGasSponsor(config: GasSponsorConfig = {}): GasSponsor {\n return new GasSponsor(config);\n}\n\n// ============================================================================\n// Convenience Functions\n// ============================================================================\n\n/**\n * Quick check if gas sponsorship is available\n */\nexport function isSponsorshipAvailable(): boolean {\n return !!(\n typeof process !== 'undefined' &&\n (process.env?.VERIDEX_SPONSOR_KEY || process.env?.NEXT_PUBLIC_SPONSOR_API_URL)\n );\n}\n\n/**\n * Get chain configurations for display\n */\nexport function getSupportedChainConfigs(testnet: boolean = true): ChainDeploymentConfig[] {\n return (testnet ? TESTNET_CHAINS : MAINNET_CHAINS).filter(c => c.vaultFactory);\n}\n","/**\n * Veridex Protocol SDK - Simplified Initialization\n * \n * Factory functions for easy SDK creation with minimal configuration.\n * \n * @example\n * ```typescript\n * import { createSDK } from '@veridex/sdk';\n * \n * // Simplest usage - testnet by default\n * const sdk = await createSDK('base');\n * \n * // Register passkey and start using\n * await sdk.passkey.register('user@example.com', 'My Wallet');\n * const vault = await sdk.getVaultAddress();\n * ```\n */\n\nimport { VeridexSDK } from './core/VeridexSDK.js';\nimport { EVMClient } from './chains/evm/EVMClient.js';\nimport { AvalancheClient } from './chains/avalanche/AvalancheClient.js';\nimport { SolanaClient } from './chains/solana/SolanaClient.js';\nimport { AptosClient } from './chains/aptos/AptosClient.js';\nimport { SuiClient } from './chains/sui/SuiClient.js';\nimport { StarknetClient } from './chains/starknet/StarknetClient.js';\nimport { StacksClient } from './chains/stacks/StacksClient.js';\nimport {\n CHAIN_PRESETS,\n getChainConfig,\n getChainPreset,\n isHubChain,\n type ChainName,\n type NetworkType,\n} from './presets.js';\nimport { getEffectivePrimaryHub, isMultiHubEnabled } from './featureFlags.js';\nimport type { ChainClient } from './core/types.js';\n\n// ============================================================================\n// Simple Configuration Interface\n// ============================================================================\n\n/**\n * Simplified SDK configuration\n * Only specify what you need - everything else has sensible defaults\n */\nexport interface SimpleSDKConfig {\n /**\n * Network to connect to\n * @default 'testnet'\n */\n network?: NetworkType;\n\n /**\n * Custom RPC URL (optional - defaults to public endpoints)\n */\n rpcUrl?: string;\n\n /**\n * Relayer URL for gasless transactions (optional)\n */\n relayerUrl?: string;\n\n /**\n * Relayer API key (optional)\n */\n relayerApiKey?: string;\n\n /**\n * Sponsor private key for gasless vault creation (optional)\n * If not provided, users pay their own gas\n */\n sponsorPrivateKey?: string;\n\n /**\n * Integrator sponsor key (optional)\n * Allows platforms to pay for their users' transactions\n */\n integratorSponsorKey?: string;\n\n /**\n * Additional RPC URLs for multi-chain operations\n * Maps chain name to RPC URL\n */\n rpcUrls?: Partial<Record<ChainName, string>>;\n}\n\n/**\n * Session-specific configuration\n */\nexport interface SessionConfig {\n /**\n * Chain to use for sessions\n */\n chain: ChainName;\n\n /**\n * Network to connect to\n * @default 'testnet'\n */\n network?: NetworkType;\n\n /**\n * Session duration in seconds\n * @default 3600 (1 hour)\n */\n duration?: number;\n\n /**\n * Maximum value per transaction\n * @default BigInt(1e18) (1 token)\n */\n maxValue?: bigint;\n\n /**\n * Require user verification for session creation\n * @default true\n */\n requireUV?: boolean;\n}\n\n// ============================================================================\n// Chain Client Factory\n// ============================================================================\n\n/**\n * Create the appropriate chain client based on chain type.\n *\n * Exposed as a public API so integrators can instantiate chain clients\n * independently of the full VeridexSDK constructor (e.g. for testing\n * or for dynamic multi-chain client access).\n */\nexport function createChainClient(\n chain: ChainName,\n network: NetworkType,\n customRpcUrl?: string\n): ChainClient {\n const preset = getChainPreset(chain);\n const config = preset[network];\n const rpcUrl = customRpcUrl || config.rpcUrl;\n\n const requireString = (value: string | undefined, label: string): string => {\n if (!value) {\n throw new Error(`Missing ${label} for chain \"${chain}\" on network \"${network}\"`);\n }\n return value;\n };\n\n // Avalanche gets its own client with ACP-204 + ICM + Chainlink support\n if ((chain as string) === 'avalanche') {\n return new AvalancheClient({\n chainId: config.chainId,\n wormholeChainId: config.wormholeChainId,\n rpcUrl,\n hubContractAddress: requireString(config.contracts.hub, 'hub contract address'),\n wormholeCoreBridge: requireString(config.contracts.wormholeCoreBridge, 'Wormhole core bridge address'),\n vaultFactory: config.contracts.vaultFactory,\n vaultImplementation: config.contracts.vaultImplementation,\n tokenBridge: config.contracts.tokenBridge,\n name: config.name,\n explorerUrl: config.explorerUrl,\n p256VerifierAddress: (config.contracts as any).p256Verifier,\n icmSpokeAddress: (config.contracts as any).icmSpoke,\n chainlinkAvaxUsdFeed: (config.contracts as any).chainlinkAvaxUsd,\n chainlinkUsdcUsdFeed: (config.contracts as any).chainlinkUsdcUsd,\n chainlinkUsdtUsdFeed: (config.contracts as any).chainlinkUsdtUsd,\n });\n }\n\n switch (preset.type) {\n case 'evm':\n return new EVMClient({\n chainId: config.chainId,\n wormholeChainId: config.wormholeChainId,\n rpcUrl,\n hubContractAddress: requireString(config.contracts.hub, 'hub contract address'),\n wormholeCoreBridge: requireString(config.contracts.wormholeCoreBridge, 'Wormhole core bridge address'),\n vaultFactory: config.contracts.vaultFactory,\n vaultImplementation: config.contracts.vaultImplementation,\n tokenBridge: config.contracts.tokenBridge,\n name: config.name,\n explorerUrl: config.explorerUrl,\n });\n\n case 'solana':\n return new SolanaClient({\n rpcUrl,\n programId: requireString(config.contracts.hub, 'programId'),\n wormholeCoreBridge: requireString(config.contracts.wormholeCoreBridge, 'Wormhole core bridge address'),\n tokenBridge: requireString(config.contracts.tokenBridge, 'token bridge address'),\n wormholeChainId: config.wormholeChainId,\n network: network === 'testnet' ? 'devnet' : 'mainnet',\n });\n\n case 'aptos':\n return new AptosClient({\n rpcUrl,\n moduleAddress: requireString(config.contracts.hub, 'moduleAddress'),\n wormholeCoreBridge: requireString(config.contracts.wormholeCoreBridge, 'Wormhole core bridge address'),\n tokenBridge: requireString(config.contracts.tokenBridge, 'token bridge address'),\n wormholeChainId: config.wormholeChainId,\n network: network,\n });\n\n case 'sui':\n return new SuiClient({\n rpcUrl,\n packageId: requireString(config.contracts.hub, 'packageId'),\n wormholeCoreBridge: requireString(config.contracts.wormholeCoreBridge, 'Wormhole core bridge address'),\n wormholeChainId: config.wormholeChainId,\n network: network,\n });\n\n case 'starknet':\n return new StarknetClient({\n rpcUrl,\n spokeContractAddress: config.contracts.hub,\n bridgeContractAddress: config.contracts.wormholeCoreBridge,\n wormholeChainId: config.wormholeChainId,\n network: network === 'testnet' ? 'sepolia' : 'mainnet',\n });\n\n case 'stacks':\n return new StacksClient({\n rpcUrl,\n spokeContractAddress: config.contracts.hub || undefined,\n wormholeChainId: config.wormholeChainId,\n network: network,\n });\n\n case 'near':\n case 'cosmos':\n throw new Error(`Chain type \"${preset.type}\" is not yet supported. Coming soon!`);\n\n default:\n throw new Error(`Unknown chain type: ${preset.type}`);\n }\n}\n\n// ============================================================================\n// SDK Factory Functions\n// ============================================================================\n\n/**\n * Create a Veridex SDK instance with minimal configuration\n * \n * @param chain - Chain name (e.g., 'base', 'optimism', 'solana')\n * @param config - Optional configuration overrides\n * @returns Configured VeridexSDK instance\n * \n * @example\n * ```typescript\n * // Simplest usage - testnet by default\n * const sdk = await createSDK('base');\n * \n * // Use mainnet\n * const mainnetSdk = await createSDK('base', { network: 'mainnet' });\n * \n * // With custom RPC\n * const customSdk = await createSDK('base', { \n * rpcUrl: 'https://my-rpc.example.com' \n * });\n * \n * // With relayer for gasless transactions\n * const gaslessSdk = await createSDK('base', {\n * relayerUrl: 'https://relayer.veridex.network',\n * relayerApiKey: 'your-api-key',\n * });\n * ```\n */\nexport function createSDK(\n chain: ChainName,\n config: SimpleSDKConfig = {}\n): VeridexSDK {\n const network = config.network ?? 'testnet';\n\n // Validate chain exists\n if (!CHAIN_PRESETS[chain]) {\n const supportedChains = Object.keys(CHAIN_PRESETS).join(', ');\n throw new Error(\n `Unknown chain: \"${chain}\". Supported chains: ${supportedChains}`\n );\n }\n\n // Create chain client\n const chainClient = createChainClient(chain, network, config.rpcUrl);\n\n // Build RPC URLs map for multi-chain operations\n const chainRpcUrls: Record<number, string> = {};\n if (config.rpcUrls) {\n for (const [chainName, rpcUrl] of Object.entries(config.rpcUrls)) {\n if (rpcUrl && CHAIN_PRESETS[chainName as ChainName]) {\n const chainConfig = getChainConfig(chainName as ChainName, network);\n chainRpcUrls[chainConfig.wormholeChainId] = rpcUrl;\n }\n }\n }\n\n // Create SDK\n return new VeridexSDK({\n chain: chainClient,\n testnet: network === 'testnet',\n relayerUrl: config.relayerUrl,\n relayerApiKey: config.relayerApiKey,\n sponsorPrivateKey: config.sponsorPrivateKey,\n integratorSponsorKey: config.integratorSponsorKey,\n chainRpcUrls: Object.keys(chainRpcUrls).length > 0 ? chainRpcUrls : undefined,\n });\n}\n\n/**\n * Create SDK for the default hub chain.\n * \n * When multi-hub is disabled, always creates SDK for Base.\n * When enabled, uses the configured primary hub chain.\n * \n * @param config - Optional configuration\n * @returns SDK configured for the primary hub chain\n * \n * @example\n * ```typescript\n * const sdk = createHubSDK();\n * await sdk.passkey.register('user', 'My Wallet');\n * ```\n */\nexport function createHubSDK(config: SimpleSDKConfig = {}): VeridexSDK {\n const hubChain = getEffectivePrimaryHub();\n return createSDK(hubChain, config);\n}\n\n/**\n * Create SDK for testnet (convenience function)\n * \n * @param chain - Chain name\n * @param config - Optional configuration (network is forced to testnet)\n * @returns SDK configured for testnet\n */\nexport function createTestnetSDK(\n chain: ChainName = 'base',\n config: Omit<SimpleSDKConfig, 'network'> = {}\n): VeridexSDK {\n return createSDK(chain, { ...config, network: 'testnet' });\n}\n\n/**\n * Create SDK for mainnet (convenience function)\n * \n * @param chain - Chain name\n * @param config - Optional configuration (network is forced to mainnet)\n * @returns SDK configured for mainnet\n */\nexport function createMainnetSDK(\n chain: ChainName = 'base',\n config: Omit<SimpleSDKConfig, 'network'> = {}\n): VeridexSDK {\n return createSDK(chain, { ...config, network: 'mainnet' });\n}\n\n// ============================================================================\n// Session Factory (for Session Keys)\n// ============================================================================\n\n/**\n * Create a session-enabled SDK\n * \n * @param chain - Chain name\n * @param config - Session configuration\n * @returns SDK configured for session key usage\n * \n * @example\n * ```typescript\n * import { createSessionSDK, SessionManager } from '@veridex/sdk';\n * \n * const sdk = createSessionSDK('base');\n * const sessionManager = new SessionManager({ sdk });\n * \n * // Create a session (one passkey auth)\n * const session = await sessionManager.createSession({\n * duration: 3600,\n * maxValue: BigInt(1e18),\n * });\n * \n * // Execute multiple transactions without prompts\n * await sessionManager.executeWithSession(params, session);\n * ```\n */\nexport function createSessionSDK(\n chain: ChainName = 'base',\n config: SimpleSDKConfig = {}\n): VeridexSDK {\n // Sessions require hub chain with session key support\n if (!isHubChain(chain)) {\n const hubChain = getEffectivePrimaryHub();\n console.warn(\n `Chain \"${chain}\" is not an active hub chain. ` +\n `Consider using \"${hubChain}\" for full session capabilities.` +\n (isMultiHubEnabled() ? '' : ' Enable multi-hub to use other hub-capable chains.')\n );\n }\n\n return createSDK(chain, config);\n}\n\n// ============================================================================\n// Enterprise Factory\n// ============================================================================\n\n/**\n * Enterprise SDK configuration — extends SimpleSDKConfig with required sponsor/relayer keys.\n */\nexport interface EnterpriseSDKConfig extends SimpleSDKConfig {\n /**\n * Sponsor private key for gasless vault creation (required for batch ops)\n */\n sponsorPrivateKey: string;\n\n /**\n * Relayer URL (required for enterprise)\n */\n relayerUrl: string;\n\n /**\n * Relayer API key (required for enterprise)\n */\n relayerApiKey: string;\n}\n\n/**\n * Create an SDK pre-configured for enterprise / integrator back-end use.\n *\n * This factory requires `sponsorPrivateKey`, `relayerUrl`, and `relayerApiKey`\n * — features that enterprise environments always need.\n *\n * @param chain - Chain name (e.g., 'base')\n * @param config - Enterprise-specific configuration\n * @returns VeridexSDK ready for enterprise operations\n *\n * @example\n * ```typescript\n * import { createEnterpriseSDK, EnterpriseManager } from '@veridex/sdk';\n *\n * const sdk = createEnterpriseSDK('base', {\n * sponsorPrivateKey: process.env.SPONSOR_KEY!,\n * relayerUrl: 'https://relayer.veridex.network',\n * relayerApiKey: process.env.RELAYER_KEY!,\n * });\n *\n * const enterprise = new EnterpriseManager({ sdk });\n * ```\n */\nexport function createEnterpriseSDK(\n chain: ChainName,\n config: EnterpriseSDKConfig,\n): VeridexSDK {\n return createSDK(chain, config);\n}\n\n// ============================================================================\n// Type Exports\n// ============================================================================\n\nexport type { ChainName, NetworkType } from './presets.js';\nexport {\n CHAIN_NAMES,\n CHAIN_PRESETS,\n getChainConfig,\n getChainPreset,\n getSupportedChains,\n getHubChains,\n isChainSupported,\n isHubChain,\n getDefaultHub,\n} from './presets.js';\n\n// Feature Flags\nexport {\n getFeatureFlags,\n setFeatureFlags,\n resetFeatureFlags,\n isMultiHubEnabled,\n getEffectivePrimaryHub,\n} from './featureFlags.js';\nexport type { FeatureFlags } from './featureFlags.js';\n","/**\n * Veridex Protocol SDK - Browser Capabilities Detection\n *\n * Detects WebAuthn and passkey capabilities of the current browser/platform.\n * Used to drive UI branching (ROR vs Auth Portal fallback, conditional UI,\n * PRF availability, backup-state awareness, hybrid transport support).\n *\n * @example\n * ```typescript\n * import { detectCapabilities } from '@veridex/sdk';\n *\n * const caps = await detectCapabilities();\n * if (caps.relatedOrigins) {\n * // Direct cross-domain passkey usage\n * } else {\n * // Auth Portal popup/redirect fallback\n * }\n *\n * if (caps.prf) {\n * // Can use PRF extension for recovery vault encryption\n * }\n * ```\n */\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Complete browser capability report for passkey-related features.\n */\nexport interface BrowserCapabilities {\n /** Basic WebAuthn support (navigator.credentials + PublicKeyCredential) */\n webauthn: boolean;\n\n /** Platform authenticator available (Touch ID, Face ID, Windows Hello) */\n platformAuthenticator: boolean;\n\n /** Related Origin Requests (WebAuthn L3) — cross-domain passkey use */\n relatedOrigins: boolean;\n\n /** Conditional UI / autofill-assisted passkey selection */\n conditionalMediation: boolean;\n\n /** Hybrid transport (phone as authenticator via QR/BLE) */\n hybridTransport: boolean;\n\n /** PRF extension (pseudo-random function for key wrapping) */\n prf: boolean;\n\n /** User-verifying platform authenticator (biometric bound) */\n userVerification: boolean;\n\n /** Whether passkeys on this device are backed up / synced to cloud */\n backupEligible: boolean | null;\n\n /** Detected platform / ecosystem */\n platform: PlatformHint;\n\n /** Raw getClientCapabilities result (if available) */\n rawCapabilities: Record<string, boolean> | null;\n}\n\n/**\n * Platform hint for ecosystem-specific guidance.\n */\nexport type PlatformHint =\n | 'apple' // iCloud Keychain\n | 'google' // Google Password Manager\n | 'windows' // Windows Hello\n | 'android' // Android (could be Google PM or third-party)\n | 'linux'\n | 'unknown';\n\n/**\n * Recommendation for the best authentication strategy on this browser.\n */\nexport interface AuthStrategy {\n /** Primary method to attempt */\n primary: 'ror' | 'conditional' | 'portal-popup' | 'portal-redirect';\n /** Fallback if primary fails */\n fallback: 'portal-popup' | 'portal-redirect' | 'none';\n /** Whether hybrid transport is available as an additional option */\n hybridAvailable: boolean;\n /** Human-readable explanation */\n reason: string;\n}\n\n// ============================================================================\n// Platform Detection\n// ============================================================================\n\n/**\n * Detect the current platform/ecosystem from user agent and platform strings.\n */\nexport function detectPlatform(): PlatformHint {\n if (typeof navigator === 'undefined') return 'unknown';\n\n const ua = navigator.userAgent.toLowerCase();\n const platform = (navigator.platform || '').toLowerCase();\n\n if (/iphone|ipad|ipod|macintosh|macos/.test(ua) || /mac/.test(platform)) {\n return 'apple';\n }\n if (/android/.test(ua)) {\n return 'android';\n }\n if (/windows/.test(ua) || /win/.test(platform)) {\n return 'windows';\n }\n if (/cros/.test(ua)) {\n return 'google'; // ChromeOS uses Google Password Manager\n }\n if (/linux/.test(ua) || /linux/.test(platform)) {\n return 'linux';\n }\n\n return 'unknown';\n}\n\n// ============================================================================\n// Capability Detection\n// ============================================================================\n\n/**\n * Detect all browser capabilities related to passkeys and WebAuthn.\n *\n * This performs multiple async checks in parallel for efficiency.\n * Safe to call on any browser — returns sensible defaults for unsupported features.\n */\nexport async function detectCapabilities(): Promise<BrowserCapabilities> {\n // Quick bail for non-browser environments\n if (typeof window === 'undefined' || typeof navigator === 'undefined') {\n return {\n webauthn: false,\n platformAuthenticator: false,\n relatedOrigins: false,\n conditionalMediation: false,\n hybridTransport: false,\n prf: false,\n userVerification: false,\n backupEligible: null,\n platform: 'unknown',\n rawCapabilities: null,\n };\n }\n\n const hasWebAuthn = !!(window.PublicKeyCredential);\n if (!hasWebAuthn) {\n return {\n webauthn: false,\n platformAuthenticator: false,\n relatedOrigins: false,\n conditionalMediation: false,\n hybridTransport: false,\n prf: false,\n userVerification: false,\n backupEligible: null,\n platform: detectPlatform(),\n rawCapabilities: null,\n };\n }\n\n // Run independent checks in parallel\n const [\n platformAuth,\n conditionalUI,\n clientCaps,\n ] = await Promise.all([\n detectPlatformAuthenticator(),\n detectConditionalMediation(),\n detectClientCapabilities(),\n ]);\n\n const platform = detectPlatform();\n\n return {\n webauthn: true,\n platformAuthenticator: platformAuth,\n relatedOrigins: clientCaps?.relatedOrigins ?? false,\n conditionalMediation: conditionalUI,\n hybridTransport: clientCaps?.hybridTransport ?? false,\n prf: clientCaps?.prf ?? false,\n userVerification: platformAuth, // UV requires platform authenticator\n backupEligible: inferBackupEligibility(platform),\n platform,\n rawCapabilities: clientCaps?.raw ?? null,\n };\n}\n\n/**\n * Get the recommended authentication strategy based on detected capabilities.\n */\nexport async function getAuthStrategy(): Promise<AuthStrategy> {\n const caps = await detectCapabilities();\n\n if (caps.relatedOrigins) {\n return {\n primary: 'ror',\n fallback: 'portal-popup',\n hybridAvailable: caps.hybridTransport,\n reason: 'Browser supports Related Origin Requests — direct cross-domain passkey use.',\n };\n }\n\n if (caps.conditionalMediation) {\n return {\n primary: 'conditional',\n fallback: 'portal-popup',\n hybridAvailable: caps.hybridTransport,\n reason: 'Browser supports conditional UI — passkey autofill available, with portal fallback.',\n };\n }\n\n // No ROR or conditional UI — use portal\n if (caps.webauthn && caps.platformAuthenticator) {\n return {\n primary: 'portal-popup',\n fallback: 'portal-redirect',\n hybridAvailable: caps.hybridTransport,\n reason: 'Browser lacks ROR/conditional UI — using Auth Portal popup flow.',\n };\n }\n\n return {\n primary: 'portal-redirect',\n fallback: 'none',\n hybridAvailable: false,\n reason: 'Limited WebAuthn support — using Auth Portal redirect flow.',\n };\n}\n\n// ============================================================================\n// Internal Detection Helpers\n// ============================================================================\n\nasync function detectPlatformAuthenticator(): Promise<boolean> {\n try {\n return await PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable();\n } catch {\n return false;\n }\n}\n\nasync function detectConditionalMediation(): Promise<boolean> {\n try {\n if ('isConditionalMediationAvailable' in PublicKeyCredential) {\n const isAvailable = (PublicKeyCredential as unknown as {\n isConditionalMediationAvailable: () => Promise<boolean>;\n }).isConditionalMediationAvailable;\n return await isAvailable();\n }\n } catch {\n // Not supported\n }\n return false;\n}\n\ninterface ClientCapabilities {\n relatedOrigins: boolean;\n hybridTransport: boolean;\n prf: boolean;\n raw: Record<string, boolean>;\n}\n\nasync function detectClientCapabilities(): Promise<ClientCapabilities | null> {\n try {\n if ('getClientCapabilities' in PublicKeyCredential) {\n const getCapabilities = (PublicKeyCredential as unknown as {\n getClientCapabilities: () => Promise<Record<string, boolean>>;\n }).getClientCapabilities;\n const capabilities = await getCapabilities();\n\n return {\n relatedOrigins: capabilities?.['relatedOrigins'] === true,\n hybridTransport: capabilities?.['hybridTransport'] === true,\n prf: capabilities?.['prf'] === true,\n raw: capabilities ?? {},\n };\n }\n } catch {\n // getClientCapabilities not supported\n }\n return null;\n}\n\n/**\n * Infer backup eligibility based on platform.\n * Returns null if we can't determine (backup state is only available\n * from the authenticator response during registration/authentication).\n */\nfunction inferBackupEligibility(platform: PlatformHint): boolean | null {\n switch (platform) {\n case 'apple':\n return true; // iCloud Keychain syncs passkeys\n case 'google':\n case 'android':\n return true; // Google Password Manager syncs passkeys\n case 'windows':\n return true; // Windows Hello supports passkey backup (Windows 11+)\n case 'linux':\n return false; // No native passkey sync on Linux\n default:\n return null;\n }\n}\n","/**\n * Veridex Protocol SDK - Credential Manager\n *\n * First-class credential inventory management: list, rename, track usage,\n * detect device/platform hints, revoke, and add-backup flows.\n *\n * This module sits on top of PasskeyManager and provides the account-management\n * layer that PasskeyManager's low-level credential storage doesn't cover.\n *\n * @example\n * ```typescript\n * import { CredentialManager } from '@veridex/sdk';\n *\n * const manager = new CredentialManager({ relayerUrl: '...' });\n *\n * // List all credentials with metadata\n * const credentials = manager.listCredentials();\n *\n * // Rename a credential\n * manager.renameCredential(credentialId, 'MacBook Pro');\n *\n * // Check which credential was used most recently\n * const recent = manager.getMostRecentCredential();\n * ```\n */\n\nimport type { PasskeyCredential } from './PasskeyManager.js';\nimport { detectPlatform, type PlatformHint } from './BrowserCapabilities.js';\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Extended credential metadata stored alongside the base PasskeyCredential.\n */\nexport interface CredentialMetadata {\n /** User-assigned display name (e.g., \"MacBook Pro\", \"iPhone 15\") */\n displayName: string;\n\n /** When this credential was first registered (ISO 8601) */\n createdAt: string;\n\n /** When this credential was last used for authentication (ISO 8601) */\n lastUsedAt: string | null;\n\n /** Number of times this credential has been used */\n useCount: number;\n\n /** Platform/ecosystem hint from registration context */\n platformHint: PlatformHint;\n\n /** User agent string at registration time (for device identification) */\n registrationUserAgent: string;\n\n /** Whether the authenticator indicated backup eligibility */\n backupEligible: boolean | null;\n\n /** Whether the authenticator indicated the credential is currently backed up */\n backupState: boolean | null;\n\n /** Whether this is the root (first) credential for the identity */\n isRoot: boolean;\n\n /** Credential status */\n status: 'active' | 'revoked';\n}\n\n/**\n * A credential entry combining the base credential with metadata.\n */\nexport interface ManagedCredential {\n /** Base passkey credential (credentialId, publicKey, keyHash) */\n credential: PasskeyCredential;\n\n /** Extended metadata */\n metadata: CredentialMetadata;\n}\n\n/**\n * Options for adding a credential to the inventory.\n */\nexport interface AddCredentialOptions {\n /** Display name for this credential */\n displayName?: string;\n\n /** Whether this is the root credential */\n isRoot?: boolean;\n\n /** Backup eligibility from authenticator response */\n backupEligible?: boolean;\n\n /** Backup state from authenticator response */\n backupState?: boolean;\n}\n\nexport interface CredentialManagerConfig {\n /** localStorage key for credential metadata */\n storageKey?: string;\n\n /** Relayer URL for remote credential metadata sync */\n relayerUrl?: string;\n}\n\n// ============================================================================\n// Constants\n// ============================================================================\n\nconst DEFAULT_STORAGE_KEY = 'veridex_credential_metadata';\n\n// ============================================================================\n// CredentialManager Class\n// ============================================================================\n\nexport class CredentialManager {\n private config: Required<CredentialManagerConfig>;\n\n constructor(config: CredentialManagerConfig = {}) {\n this.config = {\n storageKey: config.storageKey ?? DEFAULT_STORAGE_KEY,\n relayerUrl: config.relayerUrl ?? '',\n };\n }\n\n // ========================================================================\n // Credential Inventory\n // ========================================================================\n\n /**\n * List all credentials with their metadata.\n * Merges base credentials (from PasskeyManager storage) with metadata.\n */\n listCredentials(): ManagedCredential[] {\n const metadataMap = this.loadMetadataMap();\n const baseCredentials = this.loadBaseCredentials();\n\n return baseCredentials.map(credential => {\n const metadata = metadataMap[credential.credentialId];\n return {\n credential,\n metadata: metadata ?? this.createDefaultMetadata(credential.credentialId),\n };\n });\n }\n\n /**\n * Get a single credential by ID with metadata.\n */\n getCredential(credentialId: string): ManagedCredential | null {\n const all = this.listCredentials();\n return all.find(c => c.credential.credentialId === credentialId) ?? null;\n }\n\n /**\n * Get the most recently used credential.\n */\n getMostRecentCredential(): ManagedCredential | null {\n const all = this.listCredentials();\n if (all.length === 0) return null;\n\n return all.reduce((latest, current) => {\n const latestTime = latest.metadata.lastUsedAt ? new Date(latest.metadata.lastUsedAt).getTime() : 0;\n const currentTime = current.metadata.lastUsedAt ? new Date(current.metadata.lastUsedAt).getTime() : 0;\n return currentTime > latestTime ? current : latest;\n });\n }\n\n /**\n * Get the root (first) credential for the identity.\n */\n getRootCredential(): ManagedCredential | null {\n const all = this.listCredentials();\n return all.find(c => c.metadata.isRoot) ?? null;\n }\n\n /**\n * Get count of active credentials.\n */\n getActiveCount(): number {\n return this.listCredentials().filter(c => c.metadata.status === 'active').length;\n }\n\n // ========================================================================\n // Credential Lifecycle\n // ========================================================================\n\n /**\n * Add a newly registered credential to the inventory with metadata.\n * Call this after PasskeyManager.register() to track the credential.\n */\n addCredential(credential: PasskeyCredential, options: AddCredentialOptions = {}): ManagedCredential {\n const now = new Date().toISOString();\n const existingCredentials = this.listCredentials();\n const isFirst = existingCredentials.length === 0;\n\n const metadata: CredentialMetadata = {\n displayName: options.displayName ?? this.generateDisplayName(),\n createdAt: now,\n lastUsedAt: now,\n useCount: 0,\n platformHint: detectPlatform(),\n registrationUserAgent: typeof navigator !== 'undefined' ? navigator.userAgent : '',\n backupEligible: options.backupEligible ?? null,\n backupState: options.backupState ?? null,\n isRoot: options.isRoot ?? isFirst,\n status: 'active',\n };\n\n this.saveMetadata(credential.credentialId, metadata);\n\n return { credential, metadata };\n }\n\n /**\n * Record that a credential was used for authentication.\n */\n recordUsage(credentialId: string): void {\n const metadataMap = this.loadMetadataMap();\n const metadata = metadataMap[credentialId];\n if (!metadata) return;\n\n metadata.lastUsedAt = new Date().toISOString();\n metadata.useCount += 1;\n this.saveMetadataMap(metadataMap);\n }\n\n /**\n * Rename a credential's display name.\n */\n renameCredential(credentialId: string, displayName: string): boolean {\n const metadataMap = this.loadMetadataMap();\n const metadata = metadataMap[credentialId];\n if (!metadata) return false;\n\n metadata.displayName = displayName;\n this.saveMetadataMap(metadataMap);\n return true;\n }\n\n /**\n * Mark a credential as revoked (local metadata only).\n * Actual on-chain revocation happens through VeridexHub.removeKey().\n */\n markRevoked(credentialId: string): boolean {\n const metadataMap = this.loadMetadataMap();\n const metadata = metadataMap[credentialId];\n if (!metadata) return false;\n\n if (metadata.isRoot) {\n throw new Error('Cannot revoke the root credential. Use identity migration instead.');\n }\n\n metadata.status = 'revoked';\n this.saveMetadataMap(metadataMap);\n return true;\n }\n\n /**\n * Update backup state flags (call after authenticator response provides these).\n */\n updateBackupState(credentialId: string, backupEligible: boolean, backupState: boolean): void {\n const metadataMap = this.loadMetadataMap();\n const metadata = metadataMap[credentialId];\n if (!metadata) return;\n\n metadata.backupEligible = backupEligible;\n metadata.backupState = backupState;\n this.saveMetadataMap(metadataMap);\n }\n\n /**\n * Remove a credential's metadata from local storage.\n * Does NOT remove the base credential from PasskeyManager storage.\n */\n removeMetadata(credentialId: string): void {\n const metadataMap = this.loadMetadataMap();\n delete metadataMap[credentialId];\n this.saveMetadataMap(metadataMap);\n }\n\n // ========================================================================\n // Remote Metadata Sync\n // ========================================================================\n\n /**\n * Sync credential metadata to the relayer for cross-device availability.\n * Only syncs public metadata (display name, platform, timestamps), never keys.\n */\n async syncToRelayer(credentialId: string): Promise<boolean> {\n if (!this.config.relayerUrl) return false;\n\n const managed = this.getCredential(credentialId);\n if (!managed) return false;\n\n try {\n const response = await fetch(`${this.config.relayerUrl}/api/v1/credential/metadata`, {\n method: 'PUT',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n keyHash: managed.credential.keyHash,\n credentialId: managed.credential.credentialId,\n displayName: managed.metadata.displayName,\n platformHint: managed.metadata.platformHint,\n backupEligible: managed.metadata.backupEligible,\n backupState: managed.metadata.backupState,\n isRoot: managed.metadata.isRoot,\n status: managed.metadata.status,\n }),\n });\n\n return response.ok;\n } catch {\n return false;\n }\n }\n\n /**\n * Fetch credential metadata from the relayer (for cross-device restore).\n */\n async fetchFromRelayer(keyHash: string): Promise<ManagedCredential[] | null> {\n if (!this.config.relayerUrl) return null;\n\n try {\n const response = await fetch(\n `${this.config.relayerUrl}/api/v1/credential/metadata?keyHash=${encodeURIComponent(keyHash)}`\n );\n\n if (!response.ok) return null;\n\n const data = await response.json();\n if (!Array.isArray(data.credentials)) return null;\n\n return data.credentials.map((item: Record<string, unknown>) => ({\n credential: {\n credentialId: item.credentialId as string,\n publicKeyX: BigInt(item.publicKeyX as string),\n publicKeyY: BigInt(item.publicKeyY as string),\n keyHash: item.keyHash as string,\n },\n metadata: {\n displayName: (item.displayName as string) || 'Unknown Device',\n createdAt: (item.createdAt as string) || new Date().toISOString(),\n lastUsedAt: (item.lastUsedAt as string) || null,\n useCount: (item.useCount as number) || 0,\n platformHint: (item.platformHint as PlatformHint) || 'unknown',\n registrationUserAgent: '',\n backupEligible: (item.backupEligible as boolean) ?? null,\n backupState: (item.backupState as boolean) ?? null,\n isRoot: (item.isRoot as boolean) ?? false,\n status: (item.status as 'active' | 'revoked') ?? 'active',\n },\n }));\n } catch {\n return null;\n }\n }\n\n // ========================================================================\n // Migration Helpers\n // ========================================================================\n\n /**\n * Get a summary suitable for migration/device-addition flows.\n * Returns what the user should see when deciding to add another device.\n */\n getMigrationSummary(): {\n totalCredentials: number;\n activeCredentials: number;\n platforms: PlatformHint[];\n hasBackup: boolean;\n rootDevice: string | null;\n } {\n const all = this.listCredentials();\n const active = all.filter(c => c.metadata.status === 'active');\n const root = all.find(c => c.metadata.isRoot);\n\n return {\n totalCredentials: all.length,\n activeCredentials: active.length,\n platforms: [...new Set(active.map(c => c.metadata.platformHint))],\n hasBackup: active.some(c => c.metadata.backupState === true),\n rootDevice: root?.metadata.displayName ?? null,\n };\n }\n\n // ========================================================================\n // Internal Storage\n // ========================================================================\n\n private loadMetadataMap(): Record<string, CredentialMetadata> {\n if (typeof window === 'undefined') return {};\n\n try {\n const stored = localStorage.getItem(this.config.storageKey);\n if (!stored) return {};\n return JSON.parse(stored);\n } catch {\n return {};\n }\n }\n\n private saveMetadataMap(map: Record<string, CredentialMetadata>): void {\n if (typeof window === 'undefined') return;\n localStorage.setItem(this.config.storageKey, JSON.stringify(map));\n }\n\n private saveMetadata(credentialId: string, metadata: CredentialMetadata): void {\n const map = this.loadMetadataMap();\n map[credentialId] = metadata;\n this.saveMetadataMap(map);\n }\n\n private loadBaseCredentials(): PasskeyCredential[] {\n if (typeof window === 'undefined') return [];\n\n try {\n const stored = localStorage.getItem('veridex_credentials');\n if (!stored) return [];\n const data = JSON.parse(stored);\n if (!Array.isArray(data)) return [];\n\n return data.map((item: Record<string, unknown>) => ({\n credentialId: item.credentialId as string,\n publicKeyX: BigInt(item.publicKeyX as string),\n publicKeyY: BigInt(item.publicKeyY as string),\n keyHash: item.keyHash as string,\n }));\n } catch {\n return [];\n }\n }\n\n private generateDisplayName(): string {\n const platform = detectPlatform();\n\n const platformNames: Record<PlatformHint, string> = {\n apple: 'Apple Device',\n google: 'Chrome OS',\n android: 'Android Device',\n windows: 'Windows PC',\n linux: 'Linux Device',\n unknown: 'Unknown Device',\n };\n\n const baseName = platformNames[platform];\n const existing = this.listCredentials().filter(\n c => c.metadata.displayName.startsWith(baseName)\n );\n\n if (existing.length === 0) return baseName;\n return `${baseName} (${existing.length + 1})`;\n }\n\n private createDefaultMetadata(_credentialId: string): CredentialMetadata {\n return {\n displayName: this.generateDisplayName(),\n createdAt: new Date().toISOString(),\n lastUsedAt: null,\n useCount: 0,\n platformHint: detectPlatform(),\n registrationUserAgent: typeof navigator !== 'undefined' ? navigator.userAgent : '',\n backupEligible: false,\n backupState: false,\n isRoot: this.listCredentials().length === 0,\n status: 'active',\n };\n }\n}\n","/**\n * Veridex Protocol SDK - Cross-Origin Authentication\n * \n * Enables passkey sharing across different domains using WebAuthn Related Origin Requests.\n * \n * There are two approaches for cross-domain passkey usage:\n * \n * 1. **Related Origin Requests (Recommended)** - W3C Standard\n * - Host a `.well-known/webauthn` file at veridex.network\n * - Third-party apps use rpId: 'veridex.network' directly\n * - Requires browser support for Related Origin Requests\n * - No popup needed, seamless UX\n * \n * 2. **Auth Portal Flow (Fallback)** - Popup/Redirect Pattern\n * - User is redirected to auth.veridex.network\n * - Signs with their passkey at veridex.network\n * - Returns a session token to the third-party app\n * - Works on all browsers, but requires popup/redirect\n * \n * @example Related Origins (Recommended)\n * ```typescript\n * import { createCrossOriginAuth } from '@veridex/sdk';\n * \n * const auth = createCrossOriginAuth();\n * \n * // Check if browser supports Related Origin Requests\n * if (await auth.supportsRelatedOrigins()) {\n * // Direct passkey usage with veridex.network rpId\n * const credential = await auth.authenticate();\n * } else {\n * // Fallback to Auth Portal\n * const session = await auth.authenticateViaPortal();\n * }\n * ```\n * \n * @example Auth Portal Flow\n * ```typescript\n * const auth = createCrossOriginAuth({\n * authPortalUrl: 'https://auth.veridex.network',\n * mode: 'popup', // or 'redirect'\n * });\n * \n * const session = await auth.connectWithVeridex();\n * // session contains: { address, sessionKey, expiresAt }\n * ```\n */\n\nimport { PasskeyManager, type PasskeyCredential, type WebAuthnSignature } from './PasskeyManager.js';\n\n// ============================================================================\n// Constants\n// ============================================================================\n\n// Re-export VERIDEX_RP_ID from PasskeyManager for consistency\nimport { VERIDEX_RP_ID } from './PasskeyManager.js';\nexport { VERIDEX_RP_ID };\n\n/** Default auth portal URL */\nexport const DEFAULT_AUTH_PORTAL_URL = 'https://auth.veridex.network';\n\n/** Default relayer API URL for server-side session tokens */\nexport const DEFAULT_RELAYER_URL = 'https://amused-kameko-veridex-demo-37453117.koyeb.app/api/v1';\n\n/** Message types for postMessage communication */\nexport const AUTH_MESSAGE_TYPES = {\n AUTH_REQUEST: 'VERIDEX_AUTH_REQUEST',\n AUTH_RESPONSE: 'VERIDEX_AUTH_RESPONSE',\n AUTH_ERROR: 'VERIDEX_AUTH_ERROR',\n} as const;\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface CrossOriginAuthConfig {\n /** The Veridex RP ID (defaults to veridex.network) */\n rpId?: string;\n\n /** Auth portal URL for popup/redirect flow */\n authPortalUrl?: string;\n\n /** Relayer API URL for server-side session tokens */\n relayerUrl?: string;\n\n /** Authentication mode: popup or redirect */\n mode?: 'popup' | 'redirect';\n\n /** Popup window features */\n popupFeatures?: string;\n\n /** Timeout for auth operations (ms) */\n timeout?: number;\n\n /** Callback URL for redirect mode */\n redirectUri?: string;\n}\n\nexport interface CrossOriginSession {\n /** User's vault address */\n address: string;\n\n /** Session key public key (for signing transactions) */\n sessionPublicKey: string;\n\n /** Session key (encrypted, stored on client) */\n encryptedSessionKey?: string;\n\n /** When the session expires */\n expiresAt: number;\n\n /** Proof of passkey ownership */\n signature: WebAuthnSignature;\n\n /** The credential used */\n credential: PasskeyCredential;\n\n /** Server-validated session token ID (from relayer) */\n serverSessionId?: string;\n\n /** Relayer-issued challenge binding for server session creation */\n serverChallengeId?: string;\n}\n\n/** Server-side session token returned by the relayer */\nexport interface ServerSessionToken {\n id: string;\n keyHash: string;\n appOrigin: string;\n permissions: string[];\n expiresAt: number;\n createdAt: number;\n}\n\ninterface ServerSessionChallenge {\n id: string;\n value: string;\n expiresAt: number;\n}\n\nexport interface AuthPortalMessage {\n type: typeof AUTH_MESSAGE_TYPES[keyof typeof AUTH_MESSAGE_TYPES];\n payload: CrossOriginSession | { error: string; code: string };\n origin: string;\n}\n\n// ============================================================================\n// CrossOriginAuth Class\n// ============================================================================\n\n/**\n * Manages cross-origin passkey authentication for third-party apps.\n * \n * Third-party developers can use this to enable Veridex passkey authentication\n * in their own applications without users having to create new passkeys.\n */\nexport class CrossOriginAuth {\n private config: Required<CrossOriginAuthConfig>;\n\n constructor(config: CrossOriginAuthConfig = {}) {\n this.config = {\n rpId: config.rpId ?? VERIDEX_RP_ID,\n authPortalUrl: config.authPortalUrl ?? DEFAULT_AUTH_PORTAL_URL,\n relayerUrl: config.relayerUrl ?? DEFAULT_RELAYER_URL,\n mode: config.mode ?? 'popup',\n popupFeatures: config.popupFeatures ?? 'width=500,height=600,left=100,top=100',\n timeout: config.timeout ?? 120000, // 2 minutes\n redirectUri: config.redirectUri ?? (typeof window !== 'undefined' ? window.location.href : ''),\n };\n }\n\n // ========================================================================\n // Browser Capability Detection\n // ========================================================================\n\n /**\n * Check if the browser supports Related Origin Requests.\n * This is a WebAuthn Level 3 feature that allows using passkeys across different domains.\n */\n async supportsRelatedOrigins(): Promise<boolean> {\n if (typeof window === 'undefined' || !window.PublicKeyCredential) {\n return false;\n }\n\n // Check for getClientCapabilities (WebAuthn L3)\n if ('getClientCapabilities' in PublicKeyCredential) {\n try {\n const getCapabilities = (PublicKeyCredential as unknown as { getClientCapabilities: () => Promise<{ relatedOrigins?: boolean }> }).getClientCapabilities;\n const capabilities = await getCapabilities();\n return capabilities?.relatedOrigins === true;\n } catch {\n return false;\n }\n }\n\n return false;\n }\n\n /**\n * Check if WebAuthn is supported at all.\n */\n isSupported(): boolean {\n return PasskeyManager.isSupported();\n }\n\n // ========================================================================\n // Related Origin Requests (Direct Method)\n // ========================================================================\n\n /**\n * Authenticate using Related Origin Requests.\n * This allows using a passkey registered at veridex.network from any origin\n * listed in the /.well-known/webauthn file.\n * \n * @throws If browser doesn't support Related Origin Requests\n * @throws If the current origin isn't listed in veridex.network's well-known file\n */\n async authenticate(challenge?: Uint8Array): Promise<{\n credential: PasskeyCredential;\n signature: WebAuthnSignature;\n }> {\n // Create PasskeyManager with veridex.network as rpId\n const manager = new PasskeyManager({\n rpId: this.config.rpId,\n rpName: 'Veridex Protocol',\n });\n\n // Use discoverable credential flow (passkey autofill)\n return manager.authenticate(challenge);\n }\n\n /**\n * Register a new passkey with veridex.network as the RP.\n * This should only be called from veridex.network origins.\n */\n async register(username: string, displayName: string): Promise<PasskeyCredential> {\n const manager = new PasskeyManager({\n rpId: this.config.rpId,\n rpName: 'Veridex Protocol',\n });\n\n return manager.register(username, displayName);\n }\n\n // ========================================================================\n // Auth Portal Flow (Popup/Redirect)\n // ========================================================================\n\n /**\n * Authenticate via the Veridex Auth Portal.\n * Opens a popup or redirects to auth.veridex.network where the user\n * signs with their passkey, then returns a session to the calling app.\n */\n async connectWithVeridex(options?: {\n sessionChallengeId?: string;\n sessionChallenge?: string;\n register?: boolean;\n username?: string;\n displayName?: string;\n }): Promise<CrossOriginSession> {\n if (this.config.mode === 'popup') {\n return this.authenticateViaPopup(options);\n } else {\n return this.initiateRedirectAuth(options);\n }\n }\n\n /**\n * Popup-based authentication flow.\n */\n private async authenticateViaPopup(options?: {\n sessionChallengeId?: string;\n sessionChallenge?: string;\n register?: boolean;\n username?: string;\n displayName?: string;\n }): Promise<CrossOriginSession> {\n return new Promise((resolve, reject) => {\n const state = this.generateState();\n const authUrl = new URL('/auth', this.config.authPortalUrl);\n authUrl.searchParams.set('state', state);\n authUrl.searchParams.set('origin', window.location.origin);\n authUrl.searchParams.set('callback', 'postMessage');\n if (options?.sessionChallengeId) {\n authUrl.searchParams.set('challenge_id', options.sessionChallengeId);\n }\n if (options?.sessionChallenge) {\n authUrl.searchParams.set('challenge', options.sessionChallenge);\n }\n if (options?.register) {\n authUrl.searchParams.set('register', 'true');\n }\n if (options?.username) {\n authUrl.searchParams.set('username', options.username);\n }\n if (options?.displayName) {\n authUrl.searchParams.set('display_name', options.displayName);\n }\n\n // Open popup\n const popup = window.open(\n authUrl.toString(),\n 'veridex-auth',\n this.config.popupFeatures\n );\n\n if (!popup) {\n reject(new Error('Failed to open auth popup. Please allow popups for this site.'));\n return;\n }\n\n // Set timeout\n const timeoutId = setTimeout(() => {\n popup.close();\n window.removeEventListener('message', messageHandler);\n reject(new Error('Authentication timed out'));\n }, this.config.timeout);\n\n // Listen for response\n const messageHandler = (event: MessageEvent<AuthPortalMessage>) => {\n // Validate origin\n if (!event.origin.includes('veridex.network')) {\n return;\n }\n\n const { type, payload } = event.data;\n\n if (type === AUTH_MESSAGE_TYPES.AUTH_RESPONSE) {\n clearTimeout(timeoutId);\n window.removeEventListener('message', messageHandler);\n popup.close();\n resolve(payload as CrossOriginSession);\n } else if (type === AUTH_MESSAGE_TYPES.AUTH_ERROR) {\n clearTimeout(timeoutId);\n window.removeEventListener('message', messageHandler);\n popup.close();\n const error = payload as { error: string; code: string };\n reject(new Error(error.error));\n }\n };\n\n window.addEventListener('message', messageHandler);\n });\n }\n\n /**\n * Redirect-based authentication flow.\n * Stores state in sessionStorage and redirects to auth portal.\n */\n private async initiateRedirectAuth(options?: {\n sessionChallengeId?: string;\n sessionChallenge?: string;\n register?: boolean;\n username?: string;\n displayName?: string;\n }): Promise<CrossOriginSession> {\n const state = this.generateState();\n\n // Store state for verification after redirect\n sessionStorage.setItem('veridex_auth_state', state);\n sessionStorage.setItem('veridex_auth_redirect', this.config.redirectUri);\n\n const authUrl = new URL('/auth', this.config.authPortalUrl);\n authUrl.searchParams.set('state', state);\n authUrl.searchParams.set('redirect_uri', this.config.redirectUri);\n authUrl.searchParams.set('origin', window.location.origin);\n if (options?.sessionChallengeId) {\n authUrl.searchParams.set('challenge_id', options.sessionChallengeId);\n }\n if (options?.sessionChallenge) {\n authUrl.searchParams.set('challenge', options.sessionChallenge);\n }\n if (options?.register) {\n authUrl.searchParams.set('register', 'true');\n }\n if (options?.username) {\n authUrl.searchParams.set('username', options.username);\n }\n if (options?.displayName) {\n authUrl.searchParams.set('display_name', options.displayName);\n }\n\n // Redirect - this will not resolve, page navigates away\n window.location.href = authUrl.toString();\n\n // This promise never resolves as page navigates\n return new Promise(() => { });\n }\n\n /**\n * Complete redirect-based authentication.\n * Call this on your callback page to extract the session from URL params.\n */\n completeRedirectAuth(): CrossOriginSession | null {\n const params = new URLSearchParams(window.location.search);\n const session = params.get('session');\n const state = params.get('state');\n const error = params.get('error');\n\n // Verify state\n const storedState = sessionStorage.getItem('veridex_auth_state');\n if (state !== storedState) {\n throw new Error('Invalid auth state - possible CSRF attack');\n }\n\n // Clean up\n sessionStorage.removeItem('veridex_auth_state');\n sessionStorage.removeItem('veridex_auth_redirect');\n\n // Clear URL params\n window.history.replaceState({}, '', window.location.pathname);\n\n if (error) {\n throw new Error(error);\n }\n\n if (!session) {\n return null;\n }\n\n return JSON.parse(atob(session)) as CrossOriginSession;\n }\n\n // ========================================================================\n // Utility Methods\n // ========================================================================\n\n /**\n * Generate a random state string for CSRF protection.\n */\n private generateState(): string {\n const array = new Uint8Array(32);\n crypto.getRandomValues(array);\n return Array.from(array, b => b.toString(16).padStart(2, '0')).join('');\n }\n\n private decodeBase64Url(value: string): Uint8Array {\n const base64 = value.replace(/-/g, '+').replace(/_/g, '/');\n const padded = base64 + '='.repeat((4 - (base64.length % 4)) % 4);\n const binary = atob(padded);\n const bytes = new Uint8Array(binary.length);\n\n for (let index = 0; index < binary.length; index++) {\n bytes[index] = binary.charCodeAt(index);\n }\n\n return bytes;\n }\n\n private async requestServerSessionChallenge(options?: {\n keyHash?: string;\n sessionPublicKey?: string;\n permissions?: string[];\n expiresInMs?: number;\n }): Promise<ServerSessionChallenge> {\n const response = await fetch(`${this.config.relayerUrl}/session/challenge`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n keyHash: options?.keyHash,\n appOrigin: typeof window !== 'undefined' ? window.location.origin : '',\n sessionPublicKey: options?.sessionPublicKey ?? '',\n permissions: options?.permissions ?? ['read', 'transfer'],\n expiresInMs: options?.expiresInMs ?? 3600000,\n }),\n });\n\n if (!response.ok) {\n const data = await response.json().catch(() => ({ error: 'Unknown error' }));\n throw new Error(data.error || `Failed to issue server session challenge: ${response.status}`);\n }\n\n const data = await response.json();\n return data.challenge as ServerSessionChallenge;\n }\n\n /**\n * Get the RP ID being used.\n */\n getRpId(): string {\n return this.config.rpId;\n }\n\n /**\n * Get the auth portal URL.\n */\n getAuthPortalUrl(): string {\n return this.config.authPortalUrl;\n }\n\n // ========================================================================\n // Server-Side Session Tokens (ADR-0018)\n // ========================================================================\n\n /**\n * Create a server-validated session token via the relayer.\n * Call this after authenticating (via ROR or auth portal) to get a\n * server-side session that the relayer can verify on subsequent requests.\n */\n async createServerSession(session: CrossOriginSession): Promise<ServerSessionToken> {\n const keyHash = session.credential?.keyHash;\n if (!keyHash) {\n throw new Error('Session must include credential with keyHash');\n }\n if (!session.serverChallengeId) {\n throw new Error('Session must include a relayer-issued serverChallengeId');\n }\n\n const response = await fetch(`${this.config.relayerUrl}/session/create`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n keyHash,\n appOrigin: typeof window !== 'undefined' ? window.location.origin : '',\n sessionPublicKey: session.sessionPublicKey || '',\n challengeId: session.serverChallengeId,\n signature: session.signature,\n }),\n });\n\n if (!response.ok) {\n const data = await response.json().catch(() => ({ error: 'Unknown error' }));\n throw new Error(data.error || `Failed to create server session: ${response.status}`);\n }\n\n const data = await response.json();\n return data.session as ServerSessionToken;\n }\n\n /**\n * Validate an existing server session token.\n * Returns the session details if valid, null if expired/revoked.\n */\n async validateServerSession(sessionId: string): Promise<ServerSessionToken | null> {\n const response = await fetch(`${this.config.relayerUrl}/session/${encodeURIComponent(sessionId)}`);\n\n if (!response.ok) {\n return null;\n }\n\n const data = await response.json();\n if (!data.valid) {\n return null;\n }\n\n return data.session as ServerSessionToken;\n }\n\n /**\n * Revoke a server session token.\n */\n async revokeServerSession(sessionId: string): Promise<boolean> {\n const response = await fetch(`${this.config.relayerUrl}/session/${encodeURIComponent(sessionId)}`, {\n method: 'DELETE',\n });\n return response.ok;\n }\n\n /**\n * Full authentication flow: authenticate + create server session.\n * Automatically detects ROR support and falls back to auth portal.\n */\n async authenticateAndCreateSession(options?: {\n permissions?: string[];\n expiresInMs?: number;\n }): Promise<{ session: CrossOriginSession; serverSession: ServerSessionToken }> {\n let session: CrossOriginSession;\n\n if (await this.supportsRelatedOrigins()) {\n const bootstrap = await this.authenticate();\n const challenge = await this.requestServerSessionChallenge({\n keyHash: bootstrap.credential.keyHash,\n sessionPublicKey: '',\n permissions: options?.permissions,\n expiresInMs: options?.expiresInMs,\n });\n const result = await this.authenticate(this.decodeBase64Url(challenge.value));\n session = {\n address: '',\n sessionPublicKey: '',\n expiresAt: Date.now() + (options?.expiresInMs ?? 3600000),\n signature: result.signature,\n credential: result.credential,\n serverChallengeId: challenge.id,\n };\n } else {\n const bootstrap = await this.connectWithVeridex();\n const challenge = await this.requestServerSessionChallenge({\n keyHash: bootstrap.credential.keyHash,\n sessionPublicKey: bootstrap.sessionPublicKey,\n permissions: options?.permissions,\n expiresInMs: options?.expiresInMs,\n });\n session = await this.connectWithVeridex({\n sessionChallengeId: challenge.id,\n sessionChallenge: challenge.value,\n });\n session.serverChallengeId = challenge.id;\n }\n\n const serverSession = await this.createServerSession(session);\n session.serverSessionId = serverSession.id;\n\n return { session, serverSession };\n }\n}\n\n// ============================================================================\n// Factory Function\n// ============================================================================\n\n/**\n * Create a CrossOriginAuth instance for third-party app integration.\n * \n * @example\n * ```typescript\n * const auth = createCrossOriginAuth();\n * \n * // Check for Related Origin support\n * if (await auth.supportsRelatedOrigins()) {\n * const { credential, signature } = await auth.authenticate();\n * } else {\n * const session = await auth.connectWithVeridex();\n * }\n * ```\n */\nexport function createCrossOriginAuth(config?: CrossOriginAuthConfig): CrossOriginAuth {\n return new CrossOriginAuth(config);\n}\n\n// ============================================================================\n// Auth Portal Helper (for veridex.network auth page)\n// ============================================================================\n\n/**\n * Helper for the auth portal page to send results back to the calling app.\n * Only used on auth.veridex.network, not in third-party apps.\n */\nexport function sendAuthResponse(\n session: CrossOriginSession,\n targetOrigin: string\n): void {\n if (window.opener) {\n // Popup mode\n window.opener.postMessage({\n type: AUTH_MESSAGE_TYPES.AUTH_RESPONSE,\n payload: session,\n origin: window.location.origin,\n }, targetOrigin);\n } else {\n // Redirect mode - encode session in URL\n const redirectUri = new URLSearchParams(window.location.search).get('redirect_uri');\n const state = new URLSearchParams(window.location.search).get('state');\n\n if (redirectUri) {\n const url = new URL(redirectUri);\n url.searchParams.set('session', btoa(JSON.stringify(session)));\n url.searchParams.set('state', state || '');\n window.location.href = url.toString();\n }\n }\n}\n\n/**\n * Helper for the auth portal to send an error back to the calling app.\n */\nexport function sendAuthError(\n error: string,\n code: string,\n targetOrigin: string\n): void {\n if (window.opener) {\n window.opener.postMessage({\n type: AUTH_MESSAGE_TYPES.AUTH_ERROR,\n payload: { error, code },\n origin: window.location.origin,\n }, targetOrigin);\n } else {\n const redirectUri = new URLSearchParams(window.location.search).get('redirect_uri');\n const state = new URLSearchParams(window.location.search).get('state');\n\n if (redirectUri) {\n const url = new URL(redirectUri);\n url.searchParams.set('error', error);\n url.searchParams.set('error_code', code);\n url.searchParams.set('state', state || '');\n window.location.href = url.toString();\n }\n }\n}\n","/**\n * Veridex Protocol SDK — Injected Wallet Adapter\n *\n * Provides a standardized adapter for browser-injected EIP-1193 wallets\n * (MetaMask, Rabby, Coinbase Wallet, etc.). Used as the on-chain signer\n * for Veridex SDK operations that require a funded EOA for gas payment.\n *\n * Capabilities beyond basic connect:\n * - EIP-1193 event forwarding (accountsChanged, chainChanged, disconnect)\n * - Connection state tracking\n * - Clean disconnect with listener teardown\n * - Static availability detection\n *\n * ADR-0040 compliance: This adapter never touches passkey material.\n * It only provides an ethers.Signer for on-chain transaction submission.\n *\n * @module InjectedWalletAdapter\n */\n\nimport { ethers } from 'ethers';\n\ntype Eip1193Provider = {\n request(args: { method: string; params?: unknown[] | object }): Promise<unknown>;\n on?(event: string, handler: (...args: unknown[]) => void): void;\n removeListener?(event: string, handler: (...args: unknown[]) => void): void;\n};\n\ntype WindowWithEthereum = Window & {\n ethereum?: Eip1193Provider;\n};\n\nexport interface InjectedWalletConnection {\n provider: ethers.BrowserProvider;\n signer: ethers.JsonRpcSigner;\n address: string;\n chainId: number;\n}\n\nexport type WalletEvent =\n | { type: 'accountsChanged'; accounts: string[] }\n | { type: 'chainChanged'; chainId: number }\n | { type: 'disconnect'; error?: unknown };\n\nexport type WalletEventCallback = (event: WalletEvent) => void;\n\nexport interface InjectedWalletAdapterConfig {\n expectedChainId?: number;\n autoSwitchChain?: boolean;\n}\n\nexport class InjectedWalletAdapter {\n private readonly config: InjectedWalletAdapterConfig;\n private eventCallbacks: WalletEventCallback[] = [];\n private ethereum: Eip1193Provider | null = null;\n private boundAccountsChanged: ((accounts: unknown) => void) | null = null;\n private boundChainChanged: ((chainId: unknown) => void) | null = null;\n private boundDisconnect: ((error: unknown) => void) | null = null;\n private connection: InjectedWalletConnection | null = null;\n\n constructor(config: InjectedWalletAdapterConfig = {}) {\n this.config = {\n autoSwitchChain: config.autoSwitchChain ?? true,\n expectedChainId: config.expectedChainId,\n };\n }\n\n private getEthereum(): Eip1193Provider {\n if (typeof window === 'undefined') {\n throw new Error('Injected wallet access is only available in the browser.');\n }\n\n const { ethereum } = window as WindowWithEthereum;\n if (!ethereum) {\n throw new Error('No injected EIP-1193 wallet found.');\n }\n\n return ethereum;\n }\n\n isAvailable(): boolean {\n if (typeof window === 'undefined') {\n return false;\n }\n\n return Boolean((window as WindowWithEthereum).ethereum);\n }\n\n /** Returns the current active connection, or null. */\n getConnection(): InjectedWalletConnection | null {\n return this.connection;\n }\n\n async connect(expectedChainId = this.config.expectedChainId): Promise<InjectedWalletConnection> {\n const ethereum = this.getEthereum();\n this.ethereum = ethereum;\n const provider = new ethers.BrowserProvider(ethereum);\n\n await ethereum.request({ method: 'eth_requestAccounts' });\n\n if (expectedChainId && this.config.autoSwitchChain) {\n await this.switchChain(expectedChainId);\n }\n\n const signer = await provider.getSigner();\n const address = await signer.getAddress();\n const network = await provider.getNetwork();\n\n this.connection = {\n provider,\n signer,\n address,\n chainId: Number(network.chainId),\n };\n\n // Start listening for wallet events\n this.attachEventListeners(ethereum);\n\n return this.connection;\n }\n\n /** Disconnect: clears local state and removes event listeners. */\n disconnect(): void {\n this.detachEventListeners();\n this.connection = null;\n this.ethereum = null;\n this.emit({ type: 'disconnect' });\n }\n\n async switchChain(chainId: number): Promise<void> {\n const ethereum = this.getEthereum();\n await ethereum.request({\n method: 'wallet_switchEthereumChain',\n params: [{ chainId: `0x${chainId.toString(16)}` }],\n });\n }\n\n async getCurrentChainId(): Promise<number> {\n const provider = new ethers.BrowserProvider(this.getEthereum());\n const network = await provider.getNetwork();\n return Number(network.chainId);\n }\n\n // ========================================================================\n // Event system\n // ========================================================================\n\n /** Subscribe to wallet events (accountsChanged, chainChanged, disconnect). */\n on(callback: WalletEventCallback): () => void {\n this.eventCallbacks.push(callback);\n return () => {\n this.eventCallbacks = this.eventCallbacks.filter(cb => cb !== callback);\n };\n }\n\n private emit(event: WalletEvent): void {\n for (const cb of this.eventCallbacks) {\n try { cb(event); } catch { /* consumer error — swallow */ }\n }\n }\n\n private attachEventListeners(ethereum: Eip1193Provider): void {\n if (!ethereum.on) return;\n\n this.boundAccountsChanged = (accounts: unknown) => {\n const accts = accounts as string[];\n this.emit({ type: 'accountsChanged', accounts: accts });\n // If accounts empty, the user disconnected inside the wallet\n if (accts.length === 0) {\n this.connection = null;\n }\n };\n\n this.boundChainChanged = (chainId: unknown) => {\n const id = typeof chainId === 'string' ? parseInt(chainId, 16) : Number(chainId);\n if (this.connection) {\n this.connection.chainId = id;\n }\n this.emit({ type: 'chainChanged', chainId: id });\n };\n\n this.boundDisconnect = (error: unknown) => {\n this.connection = null;\n this.emit({ type: 'disconnect', error });\n };\n\n ethereum.on('accountsChanged', this.boundAccountsChanged);\n ethereum.on('chainChanged', this.boundChainChanged);\n ethereum.on('disconnect', this.boundDisconnect);\n }\n\n private detachEventListeners(): void {\n const ethereum = this.ethereum;\n if (!ethereum?.removeListener) return;\n\n if (this.boundAccountsChanged) {\n ethereum.removeListener('accountsChanged', this.boundAccountsChanged);\n }\n if (this.boundChainChanged) {\n ethereum.removeListener('chainChanged', this.boundChainChanged);\n }\n if (this.boundDisconnect) {\n ethereum.removeListener('disconnect', this.boundDisconnect);\n }\n\n this.boundAccountsChanged = null;\n this.boundChainChanged = null;\n this.boundDisconnect = null;\n }\n}\n\nexport function createInjectedWalletAdapter(config?: InjectedWalletAdapterConfig): InjectedWalletAdapter {\n return new InjectedWalletAdapter(config);\n}","/**\n * Veridex Protocol SDK - Session Manager\n * \n * Manages ephemeral session keys for fast, native L1-speed transactions\n * after initial biometric authentication.\n * \n * Key Features:\n * - One-time Passkey auth to create session\n * - Instant software-backed signing for subsequent transactions\n * - Query-based validation on Spokes (no VAA wait)\n * - ~400ms transactions after initial setup\n * - Secure encrypted storage (AES-GCM)\n * - Auto-refresh before expiry\n * - Per-session value limits\n */\n\nimport { ethers } from 'ethers';\nimport type {\n SessionKey,\n SessionConfig,\n SessionSignature,\n SessionManagerConfig,\n SessionStorage,\n SessionEvent,\n SessionEventCallback,\n ActionParams,\n SessionSignedAction,\n} from './types.js';\nimport { SessionError, SessionErrorCode } from './types.js';\nimport {\n generateSecp256k1KeyPair,\n computeSessionKeyHash,\n signWithSessionKey,\n hashAction,\n validateSessionConfig,\n DEFAULT_SESSION_DURATION,\n DEFAULT_REFRESH_BUFFER,\n} from './crypto.js';\nimport { createSessionStorage } from './storage.js';\nimport type { PasskeyCredential } from '../core/PasskeyManager.js';\nimport type { RegisterSessionParams, RevokeSessionParams } from '../types.js';\n\n// ============================================================================\n// Hub Client Interface\n// ============================================================================\n\n/**\n * Interface for Hub contract interactions\n * \n * This should be implemented by chain clients (e.g., EVMHubClientAdapter).\n */\ninterface HubClient {\n /**\n * Register a session on the Hub\n * \n * @param params Registration parameters with Passkey signature\n * @returns Promise that resolves when registration completes\n */\n registerSession(params: RegisterSessionParams): Promise<void>;\n \n /**\n * Revoke a session on the Hub\n * \n * @param params Revocation parameters with Passkey signature\n * @returns Promise that resolves when revocation completes\n */\n revokeSession(params: RevokeSessionParams): Promise<void>;\n\n /**\n * Revoke all sessions for an identity on the Hub (emergency wipe).\n * \n * @param params WebAuthn-signed revocation covering all sessions.\n * @returns Number of sessions revoked.\n */\n revokeAllSessions?(params: RevokeSessionParams): Promise<number>;\n}\n\n// ============================================================================\n// Session Manager Class\n// ============================================================================\n\n/**\n * Manages session key lifecycle and signing operations\n * \n * Usage:\n * ```typescript\n * const manager = new SessionManager(credential, hubClient, passkeySign, config);\n * \n * // Create session (requires biometric)\n * const session = await manager.createSession();\n * \n * // Sign actions instantly (no biometric)\n * const signature = await manager.signWithSession(action);\n * \n * // Revoke session (requires biometric)\n * await manager.revokeSession();\n * ```\n */\nclass SessionManager {\n private currentSession: SessionKey | null = null;\n private storage: SessionStorage;\n private config: Required<SessionConfig>;\n private refreshTimer: NodeJS.Timeout | null = null;\n private eventCallbacks: SessionEventCallback[] = [];\n private debug: boolean;\n \n /**\n * @param credential User's Passkey credential (for Hub interaction)\n * @param hubClient Hub client for on-chain session operations\n * @param passkeySign Function to sign challenges with Passkey\n * @param config Session configuration\n * @param managerConfig SessionManager configuration\n */\n constructor(\n private credential: PasskeyCredential,\n private hubClient: HubClient,\n private passkeySign: (challenge: Uint8Array) => Promise<any>,\n config: Partial<SessionConfig>,\n managerConfig?: SessionManagerConfig\n ) {\n // Validate and set configuration\n this.config = {\n duration: config.duration ?? DEFAULT_SESSION_DURATION,\n maxValue: config.maxValue ?? 0n,\n autoRefresh: config.autoRefresh ?? true,\n refreshBuffer: config.refreshBuffer ?? DEFAULT_REFRESH_BUFFER,\n chainScopes: config.chainScopes ?? [],\n };\n \n validateSessionConfig(this.config);\n \n this.debug = managerConfig?.debug ?? false;\n \n // Initialize storage\n this.storage = managerConfig?.encryptionKey\n ? createSessionStorage(credential.credentialId)\n : createSessionStorage(\n credential.credentialId,\n managerConfig?.storageBackend\n );\n }\n \n // ========================================================================\n // Session Lifecycle\n // ========================================================================\n \n /**\n * Create a new session (requires biometric authentication)\n * \n * Steps:\n * 1. Generate ephemeral secp256k1 key pair\n * 2. Sign session registration with Passkey\n * 3. Register session on Hub contract\n * 4. Store session securely (encrypted)\n * 5. Start auto-refresh timer (if enabled)\n * \n * @returns Created session key\n * @throws SessionError if registration fails\n */\n async createSession(): Promise<SessionKey> {\n try {\n this.log('Creating new session...');\n \n // 1. Generate ephemeral key pair\n const keyPair = generateSecp256k1KeyPair();\n const keyHash = computeSessionKeyHash(keyPair.publicKey);\n \n this.log('Generated session key:', keyHash);\n \n // 2. Prepare challenge for Passkey signing\n const challenge = ethers.solidityPacked(\n ['string', 'bytes32', 'uint256', 'uint256'],\n ['registerSession', keyHash, this.config.duration, this.config.maxValue]\n );\n \n this.log('Challenge prepared, requesting Passkey signature...');\n \n // 3. Sign with Passkey (this triggers biometric prompt)\n const signature = await this.passkeySign(ethers.getBytes(challenge));\n \n this.log('Passkey signature obtained, registering on Hub...');\n \n // 4. Register session on Hub\n const registerParams: RegisterSessionParams = {\n signature,\n publicKeyX: this.credential.publicKeyX,\n publicKeyY: this.credential.publicKeyY,\n sessionKeyHash: keyHash,\n duration: this.config.duration,\n maxValue: this.config.maxValue,\n requireUV: true,\n };\n \n await this.hubClient.registerSession(registerParams);\n \n this.log('Session registered on Hub');\n \n // 5. Create session object\n const expiry = Date.now() + this.config.duration * 1000;\n \n this.currentSession = {\n publicKey: keyPair.publicKey,\n privateKey: keyPair.privateKey,\n keyHash,\n expiry,\n maxValue: this.config.maxValue,\n chainScopes: this.config.chainScopes,\n userKeyHash: this.credential.keyHash,\n };\n \n // 6. Store securely\n await this.storage.save(this.currentSession);\n \n this.log('Session stored securely');\n \n // 7. Start auto-refresh\n if (this.config.autoRefresh) {\n this.scheduleRefresh();\n }\n \n // 8. Emit event\n this.emit({ type: 'session-created', session: this.currentSession });\n \n return this.currentSession;\n \n } catch (error) {\n const sessionError = error instanceof SessionError\n ? error\n : new SessionError(\n 'Failed to create session',\n SessionErrorCode.REGISTRATION_FAILED,\n error\n );\n \n this.emit({ type: 'session-error', error: sessionError });\n throw sessionError;\n }\n }\n \n /**\n * Load existing session from storage\n * \n * @returns Loaded session or null if no valid session exists\n */\n async loadSession(): Promise<SessionKey | null> {\n try {\n this.log('Loading session from storage...');\n \n const session = await this.storage.load();\n \n if (!session) {\n this.log('No session found in storage');\n return null;\n }\n \n // Verify session is not expired\n if (session.expiry <= Date.now()) {\n this.log('Session expired, clearing...');\n await this.storage.clear();\n return null;\n }\n \n this.currentSession = session;\n this.log('Session loaded:', session.keyHash);\n \n // Start auto-refresh if enabled\n if (this.config.autoRefresh) {\n this.scheduleRefresh();\n }\n \n this.emit({ type: 'session-loaded', session });\n \n return session;\n \n } catch (error) {\n this.log('Failed to load session:', error);\n await this.storage.clear();\n return null;\n }\n }\n \n /**\n * Revoke the current session (requires biometric authentication)\n * \n * @throws SessionError if no active session or revocation fails\n */\n async revokeSession(): Promise<void> {\n if (!this.currentSession) {\n throw new SessionError(\n 'No active session to revoke',\n SessionErrorCode.NO_ACTIVE_SESSION\n );\n }\n \n try {\n this.log('Revoking session:', this.currentSession.keyHash);\n \n // 1. Prepare challenge for revocation\n const challenge = ethers.solidityPacked(\n ['string', 'bytes32'],\n ['revokeSession', this.currentSession.keyHash]\n );\n \n // 2. Sign with Passkey (biometric prompt)\n const signature = await this.passkeySign(ethers.getBytes(challenge));\n \n this.log('Passkey signature obtained, revoking on Hub...');\n \n // 3. Revoke on Hub\n const revokeParams: RevokeSessionParams = {\n signature,\n publicKeyX: this.credential.publicKeyX,\n publicKeyY: this.credential.publicKeyY,\n sessionKeyHash: this.currentSession.keyHash,\n requireUV: true,\n };\n \n await this.hubClient.revokeSession(revokeParams);\n \n this.log('Session revoked on Hub');\n \n // 4. Clear local storage\n await this.storage.clear();\n \n // 5. Cancel refresh timer\n if (this.refreshTimer) {\n clearTimeout(this.refreshTimer);\n this.refreshTimer = null;\n }\n \n const revokedKeyHash = this.currentSession.keyHash;\n this.currentSession = null;\n \n // 6. Emit event\n this.emit({ type: 'session-revoked', keyHash: revokedKeyHash });\n \n this.log('Session revoked successfully');\n \n } catch (error) {\n const sessionError = error instanceof SessionError\n ? error\n : new SessionError(\n 'Failed to revoke session',\n SessionErrorCode.REVOCATION_FAILED,\n error\n );\n \n this.emit({ type: 'session-error', error: sessionError });\n throw sessionError;\n }\n }\n\n /**\n * Revoke **all** sessions for this identity (emergency wipe).\n *\n * Requires a WebAuthn biometric prompt. If the Hub client does not\n * support batch revocation the method falls back to revoking the\n * local session only and throws so the caller knows the on-chain\n * wipe did not happen.\n */\n async revokeAllSessions(): Promise<number> {\n if (!this.hubClient.revokeAllSessions) {\n // If the current session is active, revoke it individually\n if (this.currentSession) {\n await this.revokeSession();\n }\n throw new SessionError(\n 'Hub client does not support batch session revocation. Only the local session was revoked.',\n SessionErrorCode.BATCH_REVOCATION_FAILED,\n );\n }\n\n try {\n this.log('Revoking ALL sessions...');\n\n // Build a challenge that is clearly distinct from single-revoke\n const challenge = ethers.solidityPacked(\n ['string'],\n ['revokeAllSessions'],\n );\n\n const signature = await this.passkeySign(ethers.getBytes(challenge));\n\n this.log('Passkey signature obtained, batch revoking on Hub...');\n\n const revokeParams: RevokeSessionParams = {\n signature,\n publicKeyX: this.credential.publicKeyX,\n publicKeyY: this.credential.publicKeyY,\n sessionKeyHash: ethers.ZeroHash, // sentinel: revoke all\n requireUV: true,\n };\n\n const count = await this.hubClient.revokeAllSessions(revokeParams);\n\n // Clear local state\n await this.storage.clear();\n if (this.refreshTimer) {\n clearTimeout(this.refreshTimer);\n this.refreshTimer = null;\n }\n this.currentSession = null;\n\n this.emit({ type: 'all-sessions-revoked', count });\n this.log(`All sessions revoked (${count} on-chain)`);\n return count;\n\n } catch (error) {\n if (error instanceof SessionError) throw error;\n const sessionError = new SessionError(\n 'Failed to revoke all sessions',\n SessionErrorCode.BATCH_REVOCATION_FAILED,\n error,\n );\n this.emit({ type: 'session-error', error: sessionError });\n throw sessionError;\n }\n }\n \n // ========================================================================\n // Session Signing\n // ========================================================================\n \n /**\n * Sign an action with the session key (instant, no biometric)\n * \n * @param action Action parameters to sign\n * @returns Session signature\n * @throws SessionError if no active session, expired, or value exceeds limit\n */\n async signWithSession(action: ActionParams): Promise<SessionSignature> {\n if (!this.currentSession) {\n throw new SessionError(\n 'No active session available',\n SessionErrorCode.NO_ACTIVE_SESSION\n );\n }\n \n const now = Date.now();\n if (now >= this.currentSession.expiry) {\n this.emit({ type: 'session-expired', keyHash: this.currentSession.keyHash });\n throw new SessionError(\n 'Session has expired',\n SessionErrorCode.SESSION_EXPIRED\n );\n }\n \n if (this.currentSession.maxValue > 0n && action.value > this.currentSession.maxValue) {\n throw new SessionError(\n `Transaction value (${action.value}) exceeds session limit (${this.currentSession.maxValue})`,\n SessionErrorCode.VALUE_EXCEEDS_LIMIT,\n { value: action.value, limit: this.currentSession.maxValue }\n );\n }\n \n if (\n this.currentSession.chainScopes.length > 0 &&\n !this.currentSession.chainScopes.includes(action.targetChain)\n ) {\n throw new SessionError(\n `Chain ${action.targetChain} not in session scope`,\n SessionErrorCode.CHAIN_NOT_ALLOWED,\n { chain: action.targetChain, allowedChains: this.currentSession.chainScopes }\n );\n }\n \n this.log('Signing action with session key...');\n \n const messageHash = hashAction(action);\n const { signature } = signWithSessionKey(\n this.currentSession.privateKey,\n messageHash\n );\n \n const sessionSignature: SessionSignature = {\n signature,\n sessionKeyHash: this.currentSession.keyHash,\n userKeyHash: this.currentSession.userKeyHash,\n timestamp: now,\n nonce: action.nonce,\n };\n \n this.log('Action signed successfully');\n \n return sessionSignature;\n }\n \n /**\n * Sign an action and prepare for submission\n * \n * @param action Action parameters\n * @returns Session-signed action ready for submission\n */\n async signAction(action: ActionParams): Promise<SessionSignedAction> {\n const signature = await this.signWithSession(action);\n \n return {\n action,\n signature,\n readyToSubmit: true,\n };\n }\n \n // ========================================================================\n // Session State\n // ========================================================================\n \n /**\n * Check if a session is currently active\n * \n * @returns True if an active, non-expired session exists\n */\n isActive(): boolean {\n if (!this.currentSession) {\n return false;\n }\n return Date.now() < this.currentSession.expiry;\n }\n \n /**\n * Get current session information (if active)\n * \n * @returns Current session or null\n */\n getSession(): SessionKey | null {\n if (!this.isActive()) {\n return null;\n }\n return this.currentSession;\n }\n \n /**\n * Get time remaining until session expiry (in seconds)\n * \n * @returns Seconds until expiry, or 0 if no active session\n */\n getTimeRemaining(): number {\n if (!this.currentSession) {\n return 0;\n }\n const remaining = Math.floor((this.currentSession.expiry - Date.now()) / 1000);\n return Math.max(0, remaining);\n }\n \n // ========================================================================\n // Auto-Refresh\n // ========================================================================\n \n /**\n * Schedule automatic session refresh\n */\n private scheduleRefresh(): void {\n if (!this.currentSession || !this.config.autoRefresh) {\n return;\n }\n \n if (this.refreshTimer) {\n clearTimeout(this.refreshTimer);\n }\n \n const timeUntilRefresh = this.currentSession.expiry - Date.now() - (this.config.refreshBuffer * 1000);\n \n if (timeUntilRefresh <= 0) {\n this.log('Session expiring soon, refreshing now...');\n this.refreshSession().catch(error => {\n this.log('Auto-refresh failed:', error);\n this.emit({ type: 'session-error', error });\n });\n return;\n }\n \n this.log(`Scheduling refresh in ${Math.floor(timeUntilRefresh / 1000)}s`);\n \n this.refreshTimer = setTimeout(() => {\n this.refreshSession().catch(error => {\n this.log('Auto-refresh failed:', error);\n this.emit({ type: 'session-error', error });\n });\n }, timeUntilRefresh);\n }\n \n /**\n * Refresh the current session (creates a new session)\n * \n * @returns New session key\n */\n async refreshSession(): Promise<SessionKey> {\n this.log('Refreshing session...');\n const newSession = await this.createSession();\n this.emit({ type: 'session-refreshed', session: newSession });\n return newSession;\n }\n \n // ========================================================================\n // Event Handling\n // ========================================================================\n \n /**\n * Register an event callback\n */\n on(callback: SessionEventCallback): void {\n this.eventCallbacks.push(callback);\n }\n \n /**\n * Unregister an event callback\n */\n off(callback: SessionEventCallback): void {\n this.eventCallbacks = this.eventCallbacks.filter(cb => cb !== callback);\n }\n \n /**\n * Emit a session event\n */\n private emit(event: SessionEvent): void {\n for (const callback of this.eventCallbacks) {\n try {\n callback(event);\n } catch (error) {\n console.error('Session event callback error:', error);\n }\n }\n }\n \n // ========================================================================\n // Utilities\n // ========================================================================\n \n /**\n * Log debug message (if debug enabled)\n */\n private log(...args: any[]): void {\n if (this.debug) {\n console.log('[SessionManager]', ...args);\n }\n }\n \n /**\n * Cleanup resources\n */\n dispose(): void {\n if (this.refreshTimer) {\n clearTimeout(this.refreshTimer);\n this.refreshTimer = null;\n }\n this.eventCallbacks = [];\n this.currentSession = null;\n }\n}\n\n// ============================================================================\n// Exports\n// ============================================================================\n\nexport { SessionManager };\nexport type { HubClient };\nexport * from './types.js';\nexport * from './crypto.js';\nexport * from './storage.js';","/**\n * Veridex Protocol SDK - Session Key Management Types\n * \n * Type definitions for ephemeral session keys that enable\n * native L1-speed transactions after initial biometric auth.\n */\n\n// ============================================================================\n// Core Session Types\n// ============================================================================\n\n/**\n * Ephemeral session key for fast software-backed signing\n * \n * Security model:\n * - Private key encrypted at rest (AES-GCM)\n * - Max 24-hour duration enforced on-chain\n * - Value limits prevent unlimited spending\n * - Chain scopes restrict cross-chain usage\n */\nexport interface SessionKey {\n /** Public key of the session (secp256k1) */\n publicKey: Uint8Array;\n \n /** Private key (MUST be encrypted before storage) */\n privateKey: Uint8Array;\n \n /** Keccak256 hash of public key (on-chain identifier) */\n keyHash: string;\n \n /** Unix timestamp when session expires (milliseconds) */\n expiry: number;\n \n /** Maximum transaction value allowed (in token's base units) */\n maxValue: bigint;\n \n /** Wormhole chain IDs where this session is valid */\n chainScopes: number[];\n \n /** User's Passkey key hash (binds session to user) */\n userKeyHash: string;\n}\n\n/**\n * Configuration for session creation and lifecycle\n */\nexport interface SessionConfig {\n /** Session duration in seconds (default: 3600 = 1 hour, max: 86400 = 24 hours) */\n duration: number;\n \n /** Maximum transaction value in base units (0 = unlimited, but NOT RECOMMENDED) */\n maxValue: bigint;\n \n /** Auto-refresh session before expiry (default: true) */\n autoRefresh: boolean;\n \n /** Refresh buffer time in seconds (refresh this many seconds before expiry, default: 300 = 5 min) */\n refreshBuffer?: number;\n \n /** Chain scopes - which Wormhole chain IDs can use this session (empty = all chains) */\n chainScopes?: number[];\n}\n\n/**\n * Signature produced by signing with a session key\n * \n * This is a lightweight software signature (secp256k1) that can be\n * validated on-chain via CCQ to Hub's isSessionActive() state.\n */\nexport interface SessionSignature {\n /** ECDSA signature (r, s, v) from session private key */\n signature: Uint8Array;\n \n /** Session key hash (links signature to registered session) */\n sessionKeyHash: string;\n \n /** User's Passkey key hash (for Hub state query) */\n userKeyHash: string;\n \n /** Timestamp when signature was created (for replay prevention) */\n timestamp: number;\n \n /** Optional nonce for additional replay protection */\n nonce?: number;\n}\n\n/**\n * Configuration for SessionManager initialization\n */\nexport interface SessionManagerConfig {\n /** Default session configuration */\n defaultSessionConfig: SessionConfig;\n \n /** Storage backend ('indexeddb' or 'localstorage', default: 'indexeddb') */\n storageBackend?: 'indexeddb' | 'localstorage';\n \n /** Enable debug logging */\n debug?: boolean;\n \n /** Custom encryption key derivation (for testing only) */\n encryptionKey?: CryptoKey;\n}\n\n// ============================================================================\n// Session Lifecycle Events\n// ============================================================================\n\n/**\n * Events emitted during session lifecycle\n */\nexport type SessionEvent = \n | { type: 'session-created'; session: SessionKey }\n | { type: 'session-loaded'; session: SessionKey }\n | { type: 'session-expired'; keyHash: string }\n | { type: 'session-refreshed'; session: SessionKey }\n | { type: 'session-revoked'; keyHash: string }\n | { type: 'all-sessions-revoked'; count: number }\n | { type: 'session-error'; error: Error };\n\nexport type SessionEventCallback = (event: SessionEvent) => void;\n\n// ============================================================================\n// Storage Interface\n// ============================================================================\n\n/**\n * Interface for session storage implementations\n * \n * Implementations MUST:\n * - Encrypt private keys before storage\n * - Use secure key derivation (e.g., PBKDF2 or similar)\n * - Provide atomic read/write/delete operations\n */\nexport interface SessionStorage {\n /**\n * Save a session (private key will be encrypted)\n */\n save(session: SessionKey): Promise<void>;\n \n /**\n * Load the active session (private key will be decrypted)\n */\n load(): Promise<SessionKey | null>;\n \n /**\n * Clear all stored sessions\n */\n clear(): Promise<void>;\n \n /**\n * Check if a session exists\n */\n exists(): Promise<boolean>;\n}\n\n// ============================================================================\n// Action Signing Types\n// ============================================================================\n\n/**\n * Parameters for an action to be signed with a session key\n */\nexport interface ActionParams {\n /** Action type (transfer, execute, bridge, etc.) */\n action: string;\n \n /** Target chain (Wormhole chain ID) */\n targetChain: number;\n \n /** Transaction value in base units */\n value: bigint;\n \n /** Action-specific payload */\n payload: Uint8Array;\n \n /** Nonce for replay prevention */\n nonce: number;\n \n /** Optional deadline timestamp */\n deadline?: number;\n}\n\n/**\n * Result of session-signed action\n */\nexport interface SessionSignedAction {\n /** Original action parameters */\n action: ActionParams;\n \n /** Session signature */\n signature: SessionSignature;\n \n /** Ready to submit to relayer or on-chain */\n readyToSubmit: boolean;\n}\n\n// ============================================================================\n// Error Types\n// ============================================================================\n\nexport class SessionError extends Error {\n constructor(\n message: string,\n public code: SessionErrorCode,\n public details?: unknown\n ) {\n super(message);\n this.name = 'SessionError';\n }\n}\n\nexport enum SessionErrorCode {\n NO_ACTIVE_SESSION = 'NO_ACTIVE_SESSION',\n SESSION_EXPIRED = 'SESSION_EXPIRED',\n VALUE_EXCEEDS_LIMIT = 'VALUE_EXCEEDS_LIMIT',\n CHAIN_NOT_ALLOWED = 'CHAIN_NOT_ALLOWED',\n STORAGE_ERROR = 'STORAGE_ERROR',\n ENCRYPTION_ERROR = 'ENCRYPTION_ERROR',\n INVALID_CONFIG = 'INVALID_CONFIG',\n REGISTRATION_FAILED = 'REGISTRATION_FAILED',\n REVOCATION_FAILED = 'REVOCATION_FAILED',\n BATCH_REVOCATION_FAILED = 'BATCH_REVOCATION_FAILED',\n}\n","/**\n * Veridex Protocol SDK - Session Cryptography Utilities\n * \n * Provides cryptographic operations for session key management:\n * - secp256k1 key generation (NOT secp256r1 - sessions are software-backed)\n * - ECDSA signing with session keys\n * - Key hash derivation (keccak256)\n * - Secure random generation\n */\n\nimport { ethers } from 'ethers';\nimport { SessionError, SessionErrorCode } from './types.js';\n\n// ============================================================================\n// Constants\n// ============================================================================\n\n/** Maximum session duration enforced on-chain (24 hours) */\nexport const MAX_SESSION_DURATION = 86400; // 24 hours in seconds\n\n/** Minimum session duration (60 seconds) */\nexport const MIN_SESSION_DURATION = 60;\n\n/** Default session duration (1 hour) */\nexport const DEFAULT_SESSION_DURATION = 3600;\n\n/** Default refresh buffer (5 minutes before expiry) */\nexport const DEFAULT_REFRESH_BUFFER = 300;\n\n// ============================================================================\n// Key Generation\n// ============================================================================\n\n/**\n * Key pair for secp256k1 session keys\n */\nexport interface KeyPair {\n publicKey: Uint8Array;\n privateKey: Uint8Array;\n address: string; // Ethereum-style address for verification\n}\n\n/**\n * Generate a new secp256k1 key pair for session key\n * \n * Security:\n * - Uses cryptographically secure random (ethers.Wallet.createRandom)\n * - Returns uncompressed public key (65 bytes)\n * - Private key is 32 bytes\n * \n * @returns KeyPair with public/private keys and derived address\n */\nexport function generateSecp256k1KeyPair(): KeyPair {\n try {\n // Use ethers.js for secure key generation\n const wallet = ethers.Wallet.createRandom();\n \n // Extract raw private key (32 bytes)\n const privateKey = ethers.getBytes(wallet.privateKey);\n \n // ethers v6 returns COMPRESSED public key (33 bytes).\n // We need UNCOMPRESSED (65 bytes: 0x04 || x || y).\n // Use SigningKey to derive the uncompressed form.\n const signingKey = new ethers.SigningKey(wallet.privateKey);\n const publicKey = ethers.getBytes(signingKey.publicKey);\n \n return {\n publicKey,\n privateKey,\n address: wallet.address,\n };\n } catch (error) {\n throw new SessionError(\n 'Failed to generate secp256k1 key pair',\n SessionErrorCode.ENCRYPTION_ERROR,\n error\n );\n }\n}\n\n/**\n * Compute keccak256 hash of public key (session key identifier)\n * \n * This hash is used as the on-chain identifier for the session.\n * It matches the Solidity keccak256(publicKey) computation.\n * \n * @param publicKey Uncompressed public key (65 bytes)\n * @returns Hex string of keccak256 hash (0x...)\n */\nexport function computeSessionKeyHash(publicKey: Uint8Array): string {\n if (publicKey.length !== 65 || publicKey[0] !== 0x04) {\n throw new SessionError(\n 'Invalid public key format (expected 65-byte uncompressed key)',\n SessionErrorCode.INVALID_CONFIG\n );\n }\n \n // Hash the full uncompressed public key (including 0x04 prefix)\n return ethers.keccak256(publicKey);\n}\n\n// ============================================================================\n// Signing\n// ============================================================================\n\n/**\n * Sign a message hash with a session key (secp256k1 ECDSA)\n * \n * @param privateKey Session private key (32 bytes)\n * @param messageHash Message hash to sign (32 bytes)\n * @returns Signature with r, s, v components\n */\nexport function signWithSessionKey(\n privateKey: Uint8Array,\n messageHash: Uint8Array | string\n): { r: string; s: string; v: number; signature: Uint8Array } {\n try {\n if (privateKey.length !== 32) {\n throw new SessionError(\n 'Invalid private key length (expected 32 bytes)',\n SessionErrorCode.ENCRYPTION_ERROR\n );\n }\n \n // Create signing key from private key\n const signingKey = new ethers.SigningKey(privateKey);\n \n // Ensure message hash is bytes\n const hashBytes = typeof messageHash === 'string' \n ? ethers.getBytes(messageHash)\n : messageHash;\n \n if (hashBytes.length !== 32) {\n throw new SessionError(\n 'Invalid message hash length (expected 32 bytes)',\n SessionErrorCode.INVALID_CONFIG\n );\n }\n \n // Sign the hash\n const sig = signingKey.sign(hashBytes);\n \n // Extract r, s, v\n const r = sig.r;\n const s = sig.s;\n const v = sig.v;\n \n // Combine into 65-byte signature (r + s + v)\n const signature = ethers.getBytes(sig.serialized);\n \n return { r, s, v, signature };\n } catch (error) {\n throw new SessionError(\n 'Failed to sign with session key',\n SessionErrorCode.ENCRYPTION_ERROR,\n error\n );\n }\n}\n\n/**\n * Hash an action for signing\n * \n * Creates a deterministic hash of action parameters that can be\n * signed with a session key and verified on-chain.\n * \n * Hash format: keccak256(abi.encodePacked(\n * action, targetChain, value, keccak256(payload), nonce, deadline\n * ))\n * \n * @param params Action parameters\n * @returns Message hash (32 bytes)\n */\nexport function hashAction(params: {\n action: string;\n targetChain: number;\n value: bigint;\n payload: Uint8Array;\n nonce: number;\n deadline?: number;\n}): Uint8Array {\n try {\n // Hash the payload first\n const payloadHash = ethers.keccak256(params.payload);\n \n // Encode packed (matches Solidity abi.encodePacked)\n const encoded = ethers.solidityPacked(\n ['string', 'uint256', 'uint256', 'bytes32', 'uint256', 'uint256'],\n [\n params.action,\n params.targetChain,\n params.value,\n payloadHash,\n params.nonce,\n params.deadline ?? 0,\n ]\n );\n \n // Return keccak256 hash\n return ethers.getBytes(ethers.keccak256(encoded));\n } catch (error) {\n throw new SessionError(\n 'Failed to hash action',\n SessionErrorCode.INVALID_CONFIG,\n error\n );\n }\n}\n\n/**\n * Verify a session key signature\n * \n * Used for testing and client-side validation before submission.\n * On-chain verification is handled by Spoke contracts via CCQ.\n * \n * @param messageHash Message that was signed\n * @param signature Signature to verify\n * @param expectedPublicKey Expected public key of signer\n * @returns True if signature is valid\n */\nexport function verifySessionSignature(\n messageHash: Uint8Array | string,\n signature: Uint8Array,\n expectedPublicKey: Uint8Array\n): boolean {\n try {\n if (signature.length !== 65) {\n return false;\n }\n \n // Ensure hash is bytes\n const hashBytes = typeof messageHash === 'string'\n ? ethers.getBytes(messageHash)\n : messageHash;\n \n // Recover public key from signature\n const recovered = ethers.SigningKey.recoverPublicKey(\n hashBytes,\n ethers.hexlify(signature)\n );\n \n // Compare with expected public key\n const recoveredBytes = ethers.getBytes(recovered);\n \n if (recoveredBytes.length !== expectedPublicKey.length) {\n return false;\n }\n \n // Constant-time comparison\n return recoveredBytes.every((byte, i) => byte === expectedPublicKey[i]);\n } catch {\n return false;\n }\n}\n\n// ============================================================================\n// Encryption Key Derivation\n// ============================================================================\n\n/**\n * Derive an AES-GCM encryption key for session storage\n * \n * Uses PBKDF2 to derive a key from a user-specific seed.\n * The seed should be derived from the user's Passkey credential ID.\n * \n * Security considerations:\n * - Uses 100,000 iterations (OWASP minimum)\n * - Salt is derived from credential ID (unique per user)\n * - Key is bound to specific browser/device via extractable: false\n * \n * @param credentialId User's Passkey credential ID (unique identifier)\n * @returns AES-GCM encryption key\n */\nexport async function deriveEncryptionKey(credentialId: string): Promise<CryptoKey> {\n try {\n // Use credential ID as password material\n const passwordBytes = ethers.toUtf8Bytes(credentialId);\n \n // Import as key material\n const keyMaterial = await crypto.subtle.importKey(\n 'raw',\n passwordBytes as BufferSource,\n 'PBKDF2',\n false,\n ['deriveKey']\n );\n \n // Derive salt from credential ID (deterministic but unique per user)\n const saltBytes = ethers.getBytes(ethers.keccak256(passwordBytes));\n \n // Derive AES-GCM key\n const key = await crypto.subtle.deriveKey(\n {\n name: 'PBKDF2',\n salt: saltBytes as BufferSource,\n iterations: 100000, // OWASP minimum\n hash: 'SHA-256',\n },\n keyMaterial,\n {\n name: 'AES-GCM',\n length: 256,\n },\n false, // Not extractable (stays in browser)\n ['encrypt', 'decrypt']\n );\n \n return key;\n } catch (error) {\n throw new SessionError(\n 'Failed to derive encryption key',\n SessionErrorCode.ENCRYPTION_ERROR,\n error\n );\n }\n}\n\n/**\n * Generate a random initialization vector (IV) for AES-GCM\n * \n * @returns 12-byte IV (standard for AES-GCM)\n */\nexport function generateIv(): Uint8Array {\n return crypto.getRandomValues(new Uint8Array(12));\n}\n\n/**\n * Encrypt data with AES-GCM\n * \n * @param data Data to encrypt\n * @param key AES-GCM encryption key\n * @returns Encrypted data with IV prepended\n */\nexport async function encrypt(data: Uint8Array, key: CryptoKey): Promise<Uint8Array> {\n try {\n const iv = generateIv();\n \n const encrypted = await crypto.subtle.encrypt(\n {\n name: 'AES-GCM',\n iv: iv as BufferSource,\n },\n key,\n data as BufferSource\n );\n \n // Prepend IV to encrypted data (IV is not secret)\n const result = new Uint8Array(iv.length + encrypted.byteLength);\n result.set(iv, 0);\n result.set(new Uint8Array(encrypted), iv.length);\n \n return result;\n } catch (error) {\n throw new SessionError(\n 'Encryption failed',\n SessionErrorCode.ENCRYPTION_ERROR,\n error\n );\n }\n}\n\n/**\n * Decrypt data with AES-GCM\n * \n * @param encryptedData Data with IV prepended\n * @param key AES-GCM encryption key\n * @returns Decrypted data\n */\nexport async function decrypt(encryptedData: Uint8Array, key: CryptoKey): Promise<Uint8Array> {\n try {\n if (encryptedData.length < 12) {\n throw new Error('Invalid encrypted data (too short)');\n }\n \n // Extract IV (first 12 bytes)\n const iv = encryptedData.slice(0, 12);\n \n // Extract encrypted data (remaining bytes)\n const ciphertext = encryptedData.slice(12);\n \n const decrypted = await crypto.subtle.decrypt(\n {\n name: 'AES-GCM',\n iv,\n },\n key,\n ciphertext\n );\n \n return new Uint8Array(decrypted);\n } catch (error) {\n throw new SessionError(\n 'Decryption failed',\n SessionErrorCode.ENCRYPTION_ERROR,\n error\n );\n }\n}\n\n// ============================================================================\n// Validation\n// ============================================================================\n\n/**\n * Validate session configuration\n * \n * @param config Session configuration to validate\n * @throws SessionError if configuration is invalid\n */\nexport function validateSessionConfig(config: {\n duration: number;\n maxValue: bigint;\n}): void {\n if (config.duration < MIN_SESSION_DURATION) {\n throw new SessionError(\n `Session duration too short (minimum: ${MIN_SESSION_DURATION}s)`,\n SessionErrorCode.INVALID_CONFIG\n );\n }\n \n if (config.duration > MAX_SESSION_DURATION) {\n throw new SessionError(\n `Session duration too long (maximum: ${MAX_SESSION_DURATION}s = 24 hours)`,\n SessionErrorCode.INVALID_CONFIG\n );\n }\n \n if (config.maxValue < 0n) {\n throw new SessionError(\n 'Session maxValue cannot be negative',\n SessionErrorCode.INVALID_CONFIG\n );\n }\n}\n","/**\n * Veridex Protocol SDK - Secure Session Storage\n * \n * Provides encrypted storage for session keys using IndexedDB or LocalStorage.\n * Private keys are ALWAYS encrypted at rest using AES-GCM.\n * \n * Security guarantees:\n * - Private keys never stored in plaintext\n * - Encryption keys derived from Passkey credential ID (user-bound)\n * - Keys are non-extractable (remain in browser's crypto subsystem)\n * - Automatic cleanup on revocation or expiry\n */\n\nimport { ethers } from 'ethers';\nimport type { SessionKey, SessionStorage } from './types.js';\nimport { SessionError, SessionErrorCode } from './types.js';\nimport { encrypt, decrypt, deriveEncryptionKey } from './crypto.js';\n\n// ============================================================================\n// IndexedDB Session Storage (Preferred)\n// ============================================================================\n\n/** IndexedDB database name */\nconst DB_NAME = 'veridex-sessions';\n\n/** IndexedDB version */\nconst DB_VERSION = 1;\n\n/** Object store name */\nconst STORE_NAME = 'sessions';\n\n/**\n * IndexedDB-based session storage with encryption\n * \n * Preferred storage backend because:\n * - Larger storage quota (~50MB vs ~10MB)\n * - Structured storage (no serialization overhead)\n * - Better performance for binary data\n * - Non-blocking async API\n */\nexport class IndexedDBSessionStorage implements SessionStorage {\n private db: IDBDatabase | null = null;\n private encryptionKey: CryptoKey | null = null;\n private credentialId: string;\n \n /**\n * @param credentialId User's Passkey credential ID (for key derivation)\n */\n constructor(credentialId: string) {\n if (!credentialId) {\n throw new SessionError(\n 'Credential ID required for session storage',\n SessionErrorCode.INVALID_CONFIG\n );\n }\n this.credentialId = credentialId;\n }\n \n /**\n * Initialize database connection\n */\n private async initialize(): Promise<void> {\n if (this.db) return;\n \n return new Promise((resolve, reject) => {\n const request = indexedDB.open(DB_NAME, DB_VERSION);\n \n request.onerror = () => {\n reject(new SessionError(\n 'Failed to open IndexedDB',\n SessionErrorCode.STORAGE_ERROR,\n request.error\n ));\n };\n \n request.onsuccess = () => {\n this.db = request.result;\n resolve();\n };\n \n request.onupgradeneeded = (event) => {\n const db = (event.target as IDBOpenDBRequest).result;\n \n // Create object store if it doesn't exist\n if (!db.objectStoreNames.contains(STORE_NAME)) {\n const store = db.createObjectStore(STORE_NAME, { keyPath: 'keyHash' });\n \n // Create indexes for efficient queries\n store.createIndex('userKeyHash', 'userKeyHash', { unique: false });\n store.createIndex('expiry', 'expiry', { unique: false });\n }\n };\n });\n }\n \n /**\n * Get or derive encryption key\n */\n private async getEncryptionKey(): Promise<CryptoKey> {\n if (this.encryptionKey) {\n return this.encryptionKey;\n }\n \n this.encryptionKey = await deriveEncryptionKey(this.credentialId);\n return this.encryptionKey;\n }\n \n /**\n * Save a session (encrypts private key)\n */\n async save(session: SessionKey): Promise<void> {\n try {\n await this.initialize();\n \n if (!this.db) {\n throw new Error('Database not initialized');\n }\n \n // Get encryption key\n const key = await this.getEncryptionKey();\n \n // Encrypt private key\n const encryptedPrivateKey = await encrypt(session.privateKey, key);\n \n // Prepare storage object (private key encrypted)\n const storageObject = {\n keyHash: session.keyHash,\n publicKey: Array.from(session.publicKey), // Store as array for IndexedDB\n encryptedPrivateKey: Array.from(encryptedPrivateKey),\n expiry: session.expiry,\n maxValue: session.maxValue.toString(), // BigInt as string\n chainScopes: session.chainScopes,\n userKeyHash: session.userKeyHash,\n savedAt: Date.now(),\n };\n \n // Store in IndexedDB\n return new Promise((resolve, reject) => {\n const transaction = this.db!.transaction([STORE_NAME], 'readwrite');\n const store = transaction.objectStore(STORE_NAME);\n const request = store.put(storageObject);\n \n request.onsuccess = () => resolve();\n request.onerror = () => {\n reject(new SessionError(\n 'Failed to save session',\n SessionErrorCode.STORAGE_ERROR,\n request.error\n ));\n };\n });\n } catch (error) {\n if (error instanceof SessionError) {\n throw error;\n }\n throw new SessionError(\n 'Failed to save session',\n SessionErrorCode.STORAGE_ERROR,\n error\n );\n }\n }\n \n /**\n * Load the active session (decrypts private key)\n */\n async load(): Promise<SessionKey | null> {\n try {\n await this.initialize();\n \n if (!this.db) {\n throw new Error('Database not initialized');\n }\n \n // Get all sessions\n const allSessions = await this.getAllSessions();\n \n if (allSessions.length === 0) {\n return null;\n }\n \n // Find the most recent non-expired session\n const now = Date.now();\n const validSessions = allSessions\n .filter(s => s.expiry > now)\n .sort((a, b) => b.savedAt - a.savedAt);\n \n if (validSessions.length === 0) {\n // All sessions expired, clean up\n await this.clear();\n return null;\n }\n \n const stored = validSessions[0];\n \n // Get encryption key\n const key = await this.getEncryptionKey();\n \n // Decrypt private key\n const encryptedPrivateKey = new Uint8Array(stored.encryptedPrivateKey);\n const privateKey = await decrypt(encryptedPrivateKey, key);\n \n // Reconstruct session\n const session: SessionKey = {\n keyHash: stored.keyHash,\n publicKey: new Uint8Array(stored.publicKey),\n privateKey,\n expiry: stored.expiry,\n maxValue: BigInt(stored.maxValue),\n chainScopes: stored.chainScopes,\n userKeyHash: stored.userKeyHash,\n };\n \n return session;\n } catch (error) {\n if (error instanceof SessionError) {\n throw error;\n }\n throw new SessionError(\n 'Failed to load session',\n SessionErrorCode.STORAGE_ERROR,\n error\n );\n }\n }\n \n /**\n * Get all stored sessions (internal helper)\n */\n private async getAllSessions(): Promise<Array<any>> {\n if (!this.db) {\n return [];\n }\n \n return new Promise((resolve, reject) => {\n const transaction = this.db!.transaction([STORE_NAME], 'readonly');\n const store = transaction.objectStore(STORE_NAME);\n const request = store.getAll();\n \n request.onsuccess = () => resolve(request.result || []);\n request.onerror = () => {\n reject(new SessionError(\n 'Failed to get sessions',\n SessionErrorCode.STORAGE_ERROR,\n request.error\n ));\n };\n });\n }\n \n /**\n * Clear all sessions\n */\n async clear(): Promise<void> {\n try {\n await this.initialize();\n \n if (!this.db) {\n return;\n }\n \n return new Promise((resolve, reject) => {\n const transaction = this.db!.transaction([STORE_NAME], 'readwrite');\n const store = transaction.objectStore(STORE_NAME);\n const request = store.clear();\n \n request.onsuccess = () => resolve();\n request.onerror = () => {\n reject(new SessionError(\n 'Failed to clear sessions',\n SessionErrorCode.STORAGE_ERROR,\n request.error\n ));\n };\n });\n } catch (error) {\n if (error instanceof SessionError) {\n throw error;\n }\n throw new SessionError(\n 'Failed to clear sessions',\n SessionErrorCode.STORAGE_ERROR,\n error\n );\n }\n }\n \n /**\n * Check if any session exists\n */\n async exists(): Promise<boolean> {\n try {\n await this.initialize();\n \n if (!this.db) {\n return false;\n }\n \n const sessions = await this.getAllSessions();\n return sessions.length > 0;\n } catch {\n return false;\n }\n }\n \n /**\n * Close database connection\n */\n close(): void {\n if (this.db) {\n this.db.close();\n this.db = null;\n }\n }\n}\n\n// ============================================================================\n// LocalStorage Session Storage (Fallback)\n// ============================================================================\n\n/** LocalStorage key prefix */\nconst STORAGE_KEY_PREFIX = 'veridex-session-';\n\n/**\n * LocalStorage-based session storage with encryption\n * \n * Fallback storage backend when IndexedDB is unavailable.\n * \n * Limitations:\n * - Smaller storage quota (~10MB)\n * - Synchronous API (blocks main thread)\n * - String-based storage (requires serialization)\n */\nexport class LocalStorageSessionStorage implements SessionStorage {\n private encryptionKey: CryptoKey | null = null;\n private credentialId: string;\n private storageKey: string;\n \n /**\n * @param credentialId User's Passkey credential ID (for key derivation)\n */\n constructor(credentialId: string) {\n if (!credentialId) {\n throw new SessionError(\n 'Credential ID required for session storage',\n SessionErrorCode.INVALID_CONFIG\n );\n }\n this.credentialId = credentialId;\n this.storageKey = STORAGE_KEY_PREFIX + ethers.keccak256(ethers.toUtf8Bytes(credentialId));\n }\n \n /**\n * Get or derive encryption key\n */\n private async getEncryptionKey(): Promise<CryptoKey> {\n if (this.encryptionKey) {\n return this.encryptionKey;\n }\n \n this.encryptionKey = await deriveEncryptionKey(this.credentialId);\n return this.encryptionKey;\n }\n \n /**\n * Save a session (encrypts private key)\n */\n async save(session: SessionKey): Promise<void> {\n try {\n // Get encryption key\n const key = await this.getEncryptionKey();\n \n // Encrypt private key\n const encryptedPrivateKey = await encrypt(session.privateKey, key);\n \n // Prepare storage object\n const storageObject = {\n keyHash: session.keyHash,\n publicKey: ethers.hexlify(session.publicKey),\n encryptedPrivateKey: ethers.hexlify(encryptedPrivateKey),\n expiry: session.expiry,\n maxValue: session.maxValue.toString(),\n chainScopes: session.chainScopes,\n userKeyHash: session.userKeyHash,\n savedAt: Date.now(),\n };\n \n // Store as JSON\n localStorage.setItem(this.storageKey, JSON.stringify(storageObject));\n } catch (error) {\n if (error instanceof SessionError) {\n throw error;\n }\n throw new SessionError(\n 'Failed to save session',\n SessionErrorCode.STORAGE_ERROR,\n error\n );\n }\n }\n \n /**\n * Load the active session (decrypts private key)\n */\n async load(): Promise<SessionKey | null> {\n try {\n const data = localStorage.getItem(this.storageKey);\n \n if (!data) {\n return null;\n }\n \n const stored = JSON.parse(data);\n \n // Check if expired\n if (stored.expiry <= Date.now()) {\n await this.clear();\n return null;\n }\n \n // Get encryption key\n const key = await this.getEncryptionKey();\n \n // Decrypt private key\n const encryptedPrivateKey = ethers.getBytes(stored.encryptedPrivateKey);\n const privateKey = await decrypt(encryptedPrivateKey, key);\n \n // Reconstruct session\n const session: SessionKey = {\n keyHash: stored.keyHash,\n publicKey: ethers.getBytes(stored.publicKey),\n privateKey,\n expiry: stored.expiry,\n maxValue: BigInt(stored.maxValue),\n chainScopes: stored.chainScopes,\n userKeyHash: stored.userKeyHash,\n };\n \n return session;\n } catch (error) {\n // Clear corrupted data\n await this.clear();\n \n if (error instanceof SessionError) {\n throw error;\n }\n throw new SessionError(\n 'Failed to load session',\n SessionErrorCode.STORAGE_ERROR,\n error\n );\n }\n }\n \n /**\n * Clear all sessions\n */\n async clear(): Promise<void> {\n try {\n localStorage.removeItem(this.storageKey);\n } catch (error) {\n throw new SessionError(\n 'Failed to clear sessions',\n SessionErrorCode.STORAGE_ERROR,\n error\n );\n }\n }\n \n /**\n * Check if any session exists\n */\n async exists(): Promise<boolean> {\n try {\n return localStorage.getItem(this.storageKey) !== null;\n } catch {\n return false;\n }\n }\n}\n\n// ============================================================================\n// Storage Factory\n// ============================================================================\n\n/**\n * Create appropriate session storage based on environment\n * \n * @param credentialId User's Passkey credential ID\n * @param preferredBackend Preferred storage backend ('indexeddb' or 'localstorage')\n * @returns Session storage implementation\n */\nexport function createSessionStorage(\n credentialId: string,\n preferredBackend?: 'indexeddb' | 'localstorage'\n): SessionStorage {\n // Check if running in browser\n if (typeof window === 'undefined') {\n throw new SessionError(\n 'Session storage requires browser environment',\n SessionErrorCode.STORAGE_ERROR\n );\n }\n \n // Try IndexedDB first (if not explicitly requesting localStorage)\n if (preferredBackend !== 'localstorage' && typeof indexedDB !== 'undefined') {\n try {\n return new IndexedDBSessionStorage(credentialId);\n } catch (error) {\n console.warn('IndexedDB unavailable, falling back to LocalStorage:', error);\n }\n }\n \n // Fallback to LocalStorage\n if (typeof localStorage !== 'undefined') {\n console.warn(\n '[Veridex SDK] Security advisory: IndexedDB is unavailable; falling back to LocalStorage for session storage. ' +\n 'Both backends encrypt session keys with AES-GCM, but IndexedDB is recommended for production use.',\n );\n return new LocalStorageSessionStorage(credentialId);\n }\n \n throw new SessionError(\n 'No storage backend available (requires IndexedDB or LocalStorage)',\n SessionErrorCode.STORAGE_ERROR\n );\n}\n","/**\n * Veridex Solana Program Error Codes\n *\n * Error code constants for parsing and handling Veridex program errors.\n * These codes map directly to the Anchor error enum variants in the\n * Solana program.\n *\n * @packageDocumentation\n */\n\n// ============================================================================\n// Error Code Ranges\n// ============================================================================\n\n/**\n * Error code range boundaries.\n * Use these to categorize errors programmatically.\n */\nexport const ERROR_RANGES = {\n /** Core protocol errors (paused, unauthorized, limits, etc.) */\n CORE: { min: 6000, max: 6099 },\n /** Query execution errors */\n QUERY_EXECUTION: { min: 6100, max: 6149 },\n /** ABI decoding errors */\n ABI: { min: 6150, max: 6199 },\n /** Query parsing/validation errors */\n QUERY_PARSING: { min: 6200, max: 6299 },\n} as const;\n\n// ============================================================================\n// Core Protocol Error Codes (6000-6099)\n// ============================================================================\n\nexport const VERIDEX_ERRORS = {\n // Core Protocol Errors\n /** Protocol is globally paused */\n PROTOCOL_PAUSED: 6000,\n /** Vault is paused */\n VAULT_PAUSED: 6001,\n /** VAA already processed (replay protection) */\n VAA_ALREADY_PROCESSED: 6002,\n /** Invalid emitter chain */\n INVALID_EMITTER_CHAIN: 6003,\n /** Invalid emitter address */\n INVALID_EMITTER: 6004,\n /** Invalid owner */\n INVALID_OWNER: 6005,\n /** Invalid target chain */\n INVALID_TARGET_CHAIN: 6006,\n /** Invalid payload version */\n INVALID_PAYLOAD_VERSION: 6007,\n /** Invalid action payload */\n INVALID_ACTION_PAYLOAD: 6008,\n /** Invalid action type */\n INVALID_ACTION_TYPE: 6009,\n /** Daily limit exceeded */\n DAILY_LIMIT_EXCEEDED: 6010,\n /** Insufficient funds */\n INSUFFICIENT_FUNDS: 6011,\n /** Unauthorized */\n UNAUTHORIZED: 6012,\n /** Invalid VAA */\n INVALID_VAA: 6013,\n /** Token bridge not configured */\n TOKEN_BRIDGE_NOT_CONFIGURED: 6014,\n /** Invalid bridge parameters */\n INVALID_BRIDGE_PARAMS: 6015,\n\n // Query Execution Errors (6100-6149)\n /** Invalid query response format */\n INVALID_QUERY_RESPONSE: 6100,\n /** Query response expired (> 60 seconds old) */\n QUERY_EXPIRED: 6101,\n /** Query signature verification failed */\n QUERY_INVALID: 6102,\n /** Query result doesn't match expected state */\n QUERY_MISMATCH: 6103,\n /** Query block time is in the future */\n QUERY_FUTURE_BLOCK: 6104,\n /** Invalid nonce in query response */\n INVALID_QUERY_NONCE: 6105,\n /** Secp256k1 verification instruction missing */\n SECP256K1_INSTRUCTION_MISSING: 6106,\n /** Invalid secp256k1 instruction format */\n INVALID_SECP256K1_INSTRUCTION: 6107,\n /** Insufficient Guardian signatures on query */\n INSUFFICIENT_SIGNATURES: 6108,\n /** Chain ID mismatch in query response */\n CHAIN_ID_MISMATCH: 6109,\n /** Query result not found */\n QUERY_RESULT_NOT_FOUND: 6110,\n\n // ABI Decoding Errors (6150-6199)\n /** ABI decoding: insufficient data */\n ABI_INSUFFICIENT_DATA: 6150,\n /** ABI decoding: value overflow */\n ABI_OVERFLOW: 6151,\n /** ABI decoding: invalid encoding */\n ABI_INVALID_ENCODING: 6152,\n /** ABI decoding: general failure */\n ABI_DECODING_FAILED: 6153,\n\n // Query Parsing Errors (6200-6299)\n /** Invalid query response format (parsing) */\n QUERY_PARSE_INVALID_RESPONSE: 6200,\n /** Invalid query version */\n QUERY_PARSE_INVALID_VERSION: 6201,\n /** Unsupported query type */\n QUERY_PARSE_UNSUPPORTED_TYPE: 6202,\n /** Query response is stale (parsing) */\n QUERY_PARSE_STALE: 6203,\n /** Query block time is in the future (parsing) */\n QUERY_PARSE_FUTURE_BLOCK: 6204,\n /** Invalid Hub state data */\n QUERY_PARSE_INVALID_HUB_STATE: 6205,\n /** Invalid nonce (parsing) */\n QUERY_PARSE_INVALID_NONCE: 6206,\n /** Query result doesn't match expected (parsing) */\n QUERY_PARSE_MISMATCH: 6207,\n /** Secp256k1 instruction not found (parsing) */\n QUERY_PARSE_SECP256K1_MISSING: 6208,\n /** Invalid Secp256k1 instruction (parsing) */\n QUERY_PARSE_INVALID_SECP256K1: 6209,\n /** Insufficient Guardian signatures (parsing) */\n QUERY_PARSE_INSUFFICIENT_SIGS: 6210,\n /** Invalid Guardian signature (parsing) */\n QUERY_PARSE_INVALID_GUARDIAN_SIG: 6211,\n /** Chain ID mismatch (parsing) */\n QUERY_PARSE_CHAIN_ID_MISMATCH: 6212,\n /** Guardian index out of range */\n QUERY_PARSE_GUARDIAN_INDEX_OOB: 6213,\n /** Non-increasing Guardian index */\n QUERY_PARSE_NON_INCREASING_INDEX: 6214,\n /** Query signature verification failed (parsing) */\n QUERY_PARSE_INVALID_SIGNATURE: 6215,\n /** ABI decoding failed (parsing) */\n QUERY_PARSE_ABI_FAILED: 6216,\n} as const;\n\nexport type VeridexErrorCode = (typeof VERIDEX_ERRORS)[keyof typeof VERIDEX_ERRORS];\n\n// ============================================================================\n// Error Messages\n// ============================================================================\n\n/**\n * Human-readable error messages for each error code.\n */\nexport const ERROR_MESSAGES: Record<VeridexErrorCode, string> = {\n // Core Protocol Errors\n [VERIDEX_ERRORS.PROTOCOL_PAUSED]: \"Protocol is paused\",\n [VERIDEX_ERRORS.VAULT_PAUSED]: \"Vault is paused\",\n [VERIDEX_ERRORS.VAA_ALREADY_PROCESSED]:\n \"This transaction has already been processed\",\n [VERIDEX_ERRORS.INVALID_EMITTER_CHAIN]: \"Invalid emitter chain\",\n [VERIDEX_ERRORS.INVALID_EMITTER]: \"Invalid emitter address\",\n [VERIDEX_ERRORS.INVALID_OWNER]: \"Invalid owner\",\n [VERIDEX_ERRORS.INVALID_TARGET_CHAIN]: \"Invalid target chain\",\n [VERIDEX_ERRORS.INVALID_PAYLOAD_VERSION]: \"Unsupported payload version\",\n [VERIDEX_ERRORS.INVALID_ACTION_PAYLOAD]: \"Invalid action payload\",\n [VERIDEX_ERRORS.INVALID_ACTION_TYPE]: \"Unknown action type\",\n [VERIDEX_ERRORS.DAILY_LIMIT_EXCEEDED]: \"Daily spending limit exceeded\",\n [VERIDEX_ERRORS.INSUFFICIENT_FUNDS]: \"Insufficient funds in vault\",\n [VERIDEX_ERRORS.UNAUTHORIZED]: \"Unauthorized\",\n [VERIDEX_ERRORS.INVALID_VAA]: \"Invalid VAA\",\n [VERIDEX_ERRORS.TOKEN_BRIDGE_NOT_CONFIGURED]: \"Token bridge not configured\",\n [VERIDEX_ERRORS.INVALID_BRIDGE_PARAMS]: \"Invalid bridge parameters\",\n\n // Query Execution Errors\n [VERIDEX_ERRORS.INVALID_QUERY_RESPONSE]: \"Invalid query response format\",\n [VERIDEX_ERRORS.QUERY_EXPIRED]:\n \"Query has expired. Please refresh and try again.\",\n [VERIDEX_ERRORS.QUERY_INVALID]: \"Query signature verification failed\",\n [VERIDEX_ERRORS.QUERY_MISMATCH]: \"Query result does not match expected state\",\n [VERIDEX_ERRORS.QUERY_FUTURE_BLOCK]:\n \"Query block time is in the future. Possible clock skew.\",\n [VERIDEX_ERRORS.INVALID_QUERY_NONCE]: \"Invalid nonce in query response\",\n [VERIDEX_ERRORS.SECP256K1_INSTRUCTION_MISSING]:\n \"Secp256k1 verification instruction missing\",\n [VERIDEX_ERRORS.INVALID_SECP256K1_INSTRUCTION]:\n \"Invalid secp256k1 instruction format\",\n [VERIDEX_ERRORS.INSUFFICIENT_SIGNATURES]:\n \"Insufficient Guardian signatures on query\",\n [VERIDEX_ERRORS.CHAIN_ID_MISMATCH]: \"Chain ID mismatch in query response\",\n [VERIDEX_ERRORS.QUERY_RESULT_NOT_FOUND]: \"Query result not found\",\n\n // ABI Decoding Errors\n [VERIDEX_ERRORS.ABI_INSUFFICIENT_DATA]: \"ABI decoding failed: insufficient data\",\n [VERIDEX_ERRORS.ABI_OVERFLOW]: \"ABI decoding failed: value overflow\",\n [VERIDEX_ERRORS.ABI_INVALID_ENCODING]: \"ABI decoding failed: invalid encoding\",\n [VERIDEX_ERRORS.ABI_DECODING_FAILED]: \"Failed to decode data from Hub\",\n\n // Query Parsing Errors\n [VERIDEX_ERRORS.QUERY_PARSE_INVALID_RESPONSE]: \"Invalid query response format\",\n [VERIDEX_ERRORS.QUERY_PARSE_INVALID_VERSION]: \"Invalid query version\",\n [VERIDEX_ERRORS.QUERY_PARSE_UNSUPPORTED_TYPE]: \"Unsupported query type\",\n [VERIDEX_ERRORS.QUERY_PARSE_STALE]: \"Query response is stale\",\n [VERIDEX_ERRORS.QUERY_PARSE_FUTURE_BLOCK]: \"Query block time is in the future\",\n [VERIDEX_ERRORS.QUERY_PARSE_INVALID_HUB_STATE]: \"Invalid Hub state data\",\n [VERIDEX_ERRORS.QUERY_PARSE_INVALID_NONCE]: \"Invalid nonce in query\",\n [VERIDEX_ERRORS.QUERY_PARSE_MISMATCH]: \"Query result mismatch\",\n [VERIDEX_ERRORS.QUERY_PARSE_SECP256K1_MISSING]: \"Secp256k1 instruction not found\",\n [VERIDEX_ERRORS.QUERY_PARSE_INVALID_SECP256K1]: \"Invalid Secp256k1 instruction\",\n [VERIDEX_ERRORS.QUERY_PARSE_INSUFFICIENT_SIGS]:\n \"Insufficient Guardian signatures\",\n [VERIDEX_ERRORS.QUERY_PARSE_INVALID_GUARDIAN_SIG]: \"Invalid Guardian signature\",\n [VERIDEX_ERRORS.QUERY_PARSE_CHAIN_ID_MISMATCH]: \"Chain ID mismatch\",\n [VERIDEX_ERRORS.QUERY_PARSE_GUARDIAN_INDEX_OOB]: \"Guardian index out of range\",\n [VERIDEX_ERRORS.QUERY_PARSE_NON_INCREASING_INDEX]:\n \"Non-increasing Guardian index\",\n [VERIDEX_ERRORS.QUERY_PARSE_INVALID_SIGNATURE]:\n \"Query signature verification failed\",\n [VERIDEX_ERRORS.QUERY_PARSE_ABI_FAILED]: \"ABI decoding failed\",\n};\n\n// ============================================================================\n// Helper Functions\n// ============================================================================\n\n/**\n * Check if an error code is in the core protocol range.\n */\nexport function isCoreError(code: number): boolean {\n return code >= ERROR_RANGES.CORE.min && code <= ERROR_RANGES.CORE.max;\n}\n\n/**\n * Check if an error code is a query execution error.\n */\nexport function isQueryExecutionError(code: number): boolean {\n return (\n code >= ERROR_RANGES.QUERY_EXECUTION.min &&\n code <= ERROR_RANGES.QUERY_EXECUTION.max\n );\n}\n\n/**\n * Check if an error code is an ABI decoding error.\n */\nexport function isAbiError(code: number): boolean {\n return code >= ERROR_RANGES.ABI.min && code <= ERROR_RANGES.ABI.max;\n}\n\n/**\n * Check if an error code is a query parsing error.\n */\nexport function isQueryParsingError(code: number): boolean {\n return (\n code >= ERROR_RANGES.QUERY_PARSING.min &&\n code <= ERROR_RANGES.QUERY_PARSING.max\n );\n}\n\n/**\n * Check if an error is related to query operations (execution or parsing).\n */\nexport function isQueryError(code: number): boolean {\n return isQueryExecutionError(code) || isQueryParsingError(code);\n}\n\n/**\n * Get the error category as a human-readable string.\n */\nexport function getErrorCategory(code: number): string {\n if (isCoreError(code)) return \"Core Protocol\";\n if (isQueryExecutionError(code)) return \"Query Execution\";\n if (isAbiError(code)) return \"ABI Decoding\";\n if (isQueryParsingError(code)) return \"Query Parsing\";\n return \"Unknown\";\n}\n\n/**\n * Get the human-readable message for an error code.\n */\nexport function getErrorMessage(code: number): string {\n return ERROR_MESSAGES[code as VeridexErrorCode] ?? `Unknown error: ${code}`;\n}\n\n/**\n * Parse an Anchor program error to extract the Veridex error code.\n *\n * @param error - The error object from a failed transaction\n * @returns The error code if found, undefined otherwise\n */\nexport function parseVeridexError(error: unknown): VeridexErrorCode | undefined {\n if (!error || typeof error !== \"object\") return undefined;\n\n // Handle Anchor ProgramError\n const anchorError = error as {\n code?: number;\n error?: { errorCode?: { code?: string; number?: number } };\n };\n\n // Try direct code property\n if (typeof anchorError.code === \"number\") {\n if (anchorError.code in ERROR_MESSAGES) {\n return anchorError.code as VeridexErrorCode;\n }\n }\n\n // Try Anchor v0.30+ error format\n if (anchorError.error?.errorCode?.number !== undefined) {\n const code = anchorError.error.errorCode.number;\n if (code in ERROR_MESSAGES) {\n return code as VeridexErrorCode;\n }\n }\n\n return undefined;\n}\n\n/**\n * Check if the error is a retryable error (e.g., expired query can be refreshed).\n */\nexport function isRetryableError(code: number): boolean {\n const retryableCodes: number[] = [\n VERIDEX_ERRORS.QUERY_EXPIRED,\n VERIDEX_ERRORS.QUERY_PARSE_STALE,\n VERIDEX_ERRORS.QUERY_FUTURE_BLOCK,\n VERIDEX_ERRORS.QUERY_PARSE_FUTURE_BLOCK,\n VERIDEX_ERRORS.QUERY_MISMATCH,\n VERIDEX_ERRORS.QUERY_PARSE_MISMATCH,\n ];\n return retryableCodes.includes(code);\n}\n\n/**\n * Suggested user action for common errors.\n */\nexport function getSuggestedAction(code: number): string {\n switch (code) {\n case VERIDEX_ERRORS.QUERY_EXPIRED:\n case VERIDEX_ERRORS.QUERY_PARSE_STALE:\n return \"The query data has expired. Please refresh and try again.\";\n case VERIDEX_ERRORS.QUERY_FUTURE_BLOCK:\n case VERIDEX_ERRORS.QUERY_PARSE_FUTURE_BLOCK:\n return \"Clock synchronization issue detected. Please wait a moment and retry.\";\n case VERIDEX_ERRORS.INSUFFICIENT_FUNDS:\n return \"Add more funds to your vault before attempting this operation.\";\n case VERIDEX_ERRORS.DAILY_LIMIT_EXCEEDED:\n return \"Daily spending limit exceeded. Wait until tomorrow or increase your limit.\";\n case VERIDEX_ERRORS.PROTOCOL_PAUSED:\n return \"The protocol is temporarily paused. Please try again later.\";\n case VERIDEX_ERRORS.VAULT_PAUSED:\n return \"Your vault is paused. Contact support if this is unexpected.\";\n case VERIDEX_ERRORS.INSUFFICIENT_SIGNATURES:\n case VERIDEX_ERRORS.QUERY_PARSE_INSUFFICIENT_SIGS:\n return \"Waiting for Guardian consensus. Please try again in a few seconds.\";\n default:\n return \"An error occurred. Please try again or contact support.\";\n }\n}\n","/**\n * Veridex Protocol SDK — Enterprise Manager\n *\n * Bundles the operations that enterprise / integrator back-ends need:\n * - Batch vault creation across chains\n * - Admin spending limit management for multiple vaults\n * - Server-side signing helpers (non-WebAuthn path)\n * - Pre-built webhook-style event subscription\n *\n * All features delegate to existing SDK primitives — this is an\n * orchestration layer, not a divergent code path.\n */\n\nimport type { VeridexSDK } from './VeridexSDK.js';\nimport type { MultiChainVaultResult, ChainDeploymentConfig } from './GasSponsor.js';\nimport type { SpendingLimits } from './SpendingLimits.types.js';\nimport type { PortfolioBalance } from './BalanceManager.js';\nimport type { TransferParams, TransferResult } from './types.js';\nimport type { BalanceChangeCallback, BalanceErrorCallback, BalanceWatcherOptions, Unsubscribe } from './BalanceWatcher.js';\nimport { BalanceWatcher } from './BalanceWatcher.js';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface EnterpriseManagerConfig {\n /**\n * The VeridexSDK instance (typically created via `createSDK` or\n * `createEnterpriseSDK` with a sponsor key).\n */\n sdk: VeridexSDK;\n /**\n * Maximum concurrent operations for batch methods (default: 3).\n */\n maxConcurrency?: number;\n}\n\nexport interface BatchVaultRequest {\n /** Key hashes to create vaults for */\n keyHashes: string[];\n /** Optional: specific chain IDs to create vaults on (defaults to all sponsored chains) */\n chainIds?: number[];\n /** Maximum concurrent vault creations (overrides config default) */\n maxConcurrency?: number;\n}\n\nexport interface BatchVaultResult {\n total: number;\n succeeded: number;\n failed: number;\n results: Array<{\n keyHash: string;\n result: MultiChainVaultResult | null;\n error?: string;\n }>;\n}\n\nexport interface BatchTransferRequest {\n /** Transfers to execute */\n transfers: TransferParams[];\n /** Signer to pay for gas */\n signer: any;\n /** Maximum concurrent transfers (overrides config default) */\n maxConcurrency?: number;\n}\n\nexport interface BatchTransferResult {\n total: number;\n succeeded: number;\n failed: number;\n results: Array<{\n params: TransferParams;\n result: TransferResult | null;\n error?: string;\n }>;\n}\n\nexport interface BatchSpendingLimitRequest {\n /** Vault addresses and their new daily limit */\n updates: Array<{\n /** New daily limit in wei/base units (0 = unlimited) */\n newLimit: bigint;\n }>;\n /** Signer to pay for gas */\n signer: any;\n}\n\nexport interface BatchSpendingLimitResult {\n total: number;\n succeeded: number;\n failed: number;\n results: Array<{\n newLimit: bigint;\n result: TransferResult | null;\n error?: string;\n }>;\n}\n\n/** Lifecycle event types for batch operations */\nexport type BatchLifecycleEvent =\n | { type: 'started'; total: number }\n | { type: 'item_started'; index: number; total: number }\n | { type: 'item_completed'; index: number; total: number; success: boolean; error?: string }\n | { type: 'completed'; succeeded: number; failed: number; total: number };\n\n/** Callback for batch operation lifecycle events */\nexport type BatchLifecycleCallback = (event: BatchLifecycleEvent) => void;\n\nexport interface VaultOverview {\n keyHash: string;\n vaultAddress: string;\n wormholeChainId: number;\n exists: boolean;\n balance?: PortfolioBalance;\n limits?: SpendingLimits;\n}\n\n// ============================================================================\n// EnterpriseManager class\n// ============================================================================\n\n/**\n * High-level orchestration for enterprise / integrator use cases.\n *\n * @example\n * ```typescript\n * import { createEnterpriseSDK, EnterpriseManager } from '@veridex/sdk';\n *\n * const sdk = createEnterpriseSDK({\n * sponsorPrivateKey: process.env.SPONSOR_KEY!,\n * relayerUrl: 'https://relayer.veridex.network',\n * relayerApiKey: 'key',\n * });\n *\n * const enterprise = new EnterpriseManager({ sdk });\n *\n * // Batch create vaults for 50 users\n * const result = await enterprise.batchCreateVaults({\n * keyHashes: userKeyHashes,\n * });\n *\n * // Watch all vaults for balance changes\n * const unsub = enterprise.watchVaultBalance(\n * 10004, vaultAddress,\n * (event) => callWebhook(event),\n * );\n * ```\n */\nexport class EnterpriseManager {\n private readonly sdk: VeridexSDK;\n private readonly balanceWatcher: BalanceWatcher;\n private readonly maxConcurrency: number;\n\n constructor(config: EnterpriseManagerConfig) {\n this.sdk = config.sdk;\n this.maxConcurrency = config.maxConcurrency ?? 3;\n\n // Build a balance fetcher that delegates to the SDK's balance manager\n this.balanceWatcher = new BalanceWatcher(\n async (chainId, address) => {\n return this.sdk.balance.getPortfolioBalance(chainId, address, false);\n },\n );\n }\n\n // ========================================================================\n // Concurrency Helper\n // ========================================================================\n\n /**\n * Run tasks with bounded concurrency.\n */\n private async runWithConcurrency<T>(\n tasks: Array<() => Promise<T>>,\n maxConcurrency: number,\n ): Promise<T[]> {\n const results: T[] = new Array(tasks.length);\n let nextIndex = 0;\n\n async function worker() {\n while (nextIndex < tasks.length) {\n const idx = nextIndex++;\n results[idx] = await tasks[idx]();\n }\n }\n\n const workers = Array.from(\n { length: Math.min(maxConcurrency, tasks.length) },\n () => worker(),\n );\n await Promise.all(workers);\n return results;\n }\n\n // ========================================================================\n // Batch Vault Operations\n // ========================================================================\n\n /**\n * Create sponsored vaults for multiple users with concurrency control.\n *\n * Uses the SDK's GasSponsor under the hood. Errors for individual\n * key hashes are captured, not thrown — the batch continues.\n */\n async batchCreateVaults(\n request: BatchVaultRequest,\n onLifecycle?: BatchLifecycleCallback,\n ): Promise<BatchVaultResult> {\n const concurrency = request.maxConcurrency ?? this.maxConcurrency;\n const results: BatchVaultResult['results'] = new Array(request.keyHashes.length);\n\n onLifecycle?.({ type: 'started', total: request.keyHashes.length });\n\n const tasks = request.keyHashes.map((keyHash, index) => async () => {\n onLifecycle?.({ type: 'item_started', index, total: request.keyHashes.length });\n try {\n const result = await this.sdk.sponsor.createVaultsOnAllChains(keyHash);\n results[index] = { keyHash, result };\n onLifecycle?.({ type: 'item_completed', index, total: request.keyHashes.length, success: true });\n } catch (err) {\n const error = err instanceof Error ? err.message : String(err);\n results[index] = { keyHash, result: null, error };\n onLifecycle?.({ type: 'item_completed', index, total: request.keyHashes.length, success: false, error });\n }\n });\n\n await this.runWithConcurrency(tasks, concurrency);\n\n const succeeded = results.filter(r => r.result?.allSuccessful).length;\n const failed = request.keyHashes.length - succeeded;\n onLifecycle?.({ type: 'completed', succeeded, failed, total: request.keyHashes.length });\n\n return {\n total: request.keyHashes.length,\n succeeded,\n failed,\n results,\n };\n }\n\n /**\n * Check vault existence across all sponsored chains for a key hash.\n */\n async checkVaults(keyHash: string): Promise<Record<number, { exists: boolean; address: string }>> {\n return this.sdk.sponsor.checkVaultsOnAllChains(keyHash);\n }\n\n /**\n * List all chains where sponsorship is available.\n */\n getSponsoredChains(): ChainDeploymentConfig[] {\n return this.sdk.sponsor.getSupportedChains();\n }\n\n // ========================================================================\n // Batch Transfers\n // ========================================================================\n\n /**\n * Execute multiple transfers with concurrency control.\n *\n * Each transfer is prepared and executed independently. Errors are\n * captured per-transfer so the batch continues on individual failures.\n *\n * @example\n * ```typescript\n * const result = await enterprise.batchTransfer({\n * transfers: [\n * { targetChain: 10004, token: '0x...', recipient: '0xAlice', amount: 1000000n },\n * { targetChain: 10004, token: '0x...', recipient: '0xBob', amount: 2000000n },\n * ],\n * signer,\n * maxConcurrency: 2,\n * }, (event) => console.log(event.type, event));\n * ```\n */\n async batchTransfer(\n request: BatchTransferRequest,\n onLifecycle?: BatchLifecycleCallback,\n ): Promise<BatchTransferResult> {\n const concurrency = request.maxConcurrency ?? this.maxConcurrency;\n const results: BatchTransferResult['results'] = new Array(request.transfers.length);\n\n onLifecycle?.({ type: 'started', total: request.transfers.length });\n\n const tasks = request.transfers.map((params, index) => async () => {\n onLifecycle?.({ type: 'item_started', index, total: request.transfers.length });\n try {\n const prepared = await this.sdk.prepareTransfer(params);\n const result = await this.sdk.executeTransfer(prepared, request.signer);\n results[index] = { params, result };\n onLifecycle?.({ type: 'item_completed', index, total: request.transfers.length, success: true });\n } catch (err) {\n const error = err instanceof Error ? err.message : String(err);\n results[index] = { params, result: null, error };\n onLifecycle?.({ type: 'item_completed', index, total: request.transfers.length, success: false, error });\n }\n });\n\n await this.runWithConcurrency(tasks, concurrency);\n\n const succeeded = results.filter(r => r.result !== null).length;\n const failed = request.transfers.length - succeeded;\n onLifecycle?.({ type: 'completed', succeeded, failed, total: request.transfers.length });\n\n return {\n total: request.transfers.length,\n succeeded,\n failed,\n results,\n };\n }\n\n // ========================================================================\n // Batch Spending Limits\n // ========================================================================\n\n /**\n * Update daily spending limits for the current vault in sequence.\n *\n * Each limit update requires a passkey signature, so these are executed\n * one-at-a-time (signing cannot be parallelized).\n *\n * @example\n * ```typescript\n * const result = await enterprise.batchSetSpendingLimits({\n * updates: [\n * { newLimit: ethers.parseEther('5.0') },\n * { newLimit: ethers.parseEther('10.0') },\n * ],\n * signer,\n * });\n * ```\n */\n async batchSetSpendingLimits(\n request: BatchSpendingLimitRequest,\n onLifecycle?: BatchLifecycleCallback,\n ): Promise<BatchSpendingLimitResult> {\n const results: BatchSpendingLimitResult['results'] = [];\n\n onLifecycle?.({ type: 'started', total: request.updates.length });\n\n for (let i = 0; i < request.updates.length; i++) {\n const update = request.updates[i];\n onLifecycle?.({ type: 'item_started', index: i, total: request.updates.length });\n try {\n const prepared = await this.sdk.prepareSetDailyLimit(update.newLimit);\n const result = await this.sdk.executeTransfer(prepared, request.signer);\n results.push({ newLimit: update.newLimit, result });\n onLifecycle?.({ type: 'item_completed', index: i, total: request.updates.length, success: true });\n } catch (err) {\n const error = err instanceof Error ? err.message : String(err);\n results.push({ newLimit: update.newLimit, result: null, error });\n onLifecycle?.({ type: 'item_completed', index: i, total: request.updates.length, success: false, error });\n }\n }\n\n const succeeded = results.filter(r => r.result !== null).length;\n const failed = request.updates.length - succeeded;\n onLifecycle?.({ type: 'completed', succeeded, failed, total: request.updates.length });\n\n return {\n total: request.updates.length,\n succeeded,\n failed,\n results,\n };\n }\n\n // ========================================================================\n // Admin Spending Limits\n // ========================================================================\n\n /**\n * Read spending limits for any vault address on the current chain.\n * Useful for admin dashboards that need to inspect user vaults.\n */\n async getSpendingLimitsForVault(\n vaultAddress: string,\n wormholeChainId?: number,\n ): Promise<SpendingLimits> {\n const chainId = wormholeChainId ?? this.sdk.getChainConfig().wormholeChainId;\n const rpcUrl = this.sdk.getChainConfig().rpcUrl;\n return this.sdk.spendingLimits.getSpendingLimits(vaultAddress, chainId, rpcUrl);\n }\n\n /**\n * Read spending limits for multiple vaults in parallel.\n */\n async getSpendingLimitsForVaults(\n vaultAddresses: string[],\n wormholeChainId?: number,\n ): Promise<Map<string, SpendingLimits | Error>> {\n const chainId = wormholeChainId ?? this.sdk.getChainConfig().wormholeChainId;\n const rpcUrl = this.sdk.getChainConfig().rpcUrl;\n\n const entries = await Promise.allSettled(\n vaultAddresses.map(async addr => {\n const limits = await this.sdk.spendingLimits.getSpendingLimits(addr, chainId, rpcUrl);\n return [addr, limits] as const;\n }),\n );\n\n const map = new Map<string, SpendingLimits | Error>();\n for (let i = 0; i < entries.length; i++) {\n const entry = entries[i];\n const addr = vaultAddresses[i];\n if (entry.status === 'fulfilled') {\n map.set(addr, entry.value[1]);\n } else {\n map.set(addr, entry.reason instanceof Error ? entry.reason : new Error(String(entry.reason)));\n }\n }\n return map;\n }\n\n // ========================================================================\n // Balance Watching (Subscription / Webhook-style)\n // ========================================================================\n\n /**\n * Watch a vault's balance for changes.\n *\n * The callback fires whenever the polling interval detects a difference.\n * Returns an unsubscribe function.\n *\n * @example\n * ```typescript\n * const unsub = enterprise.watchVaultBalance(\n * 10004,\n * '0xVaultAddr',\n * (event) => {\n * // Push to webhook, update dashboard, etc.\n * fetch(webhookUrl, { method: 'POST', body: JSON.stringify(event) });\n * },\n * { intervalMs: 10_000 },\n * );\n * ```\n */\n watchVaultBalance(\n wormholeChainId: number,\n address: string,\n onChange: BalanceChangeCallback,\n options?: BalanceWatcherOptions,\n onError?: BalanceErrorCallback,\n ): Unsubscribe {\n return this.balanceWatcher.watch(wormholeChainId, address, onChange, options, onError);\n }\n\n /**\n * Stop all active balance watchers.\n */\n stopAllWatchers(): void {\n this.balanceWatcher.stopAll();\n }\n\n /**\n * Get number of active balance watchers.\n */\n get activeWatcherCount(): number {\n return this.balanceWatcher.activeCount;\n }\n\n // ========================================================================\n // Vault Overview (Dashboard)\n // ========================================================================\n\n /**\n * Get a combined overview for a vault: existence, balances, limits.\n *\n * Useful for rendering an admin dashboard row.\n */\n async getVaultOverview(\n keyHash: string,\n wormholeChainId?: number,\n ): Promise<VaultOverview> {\n const chainId = wormholeChainId ?? this.sdk.getChainConfig().wormholeChainId;\n const chainClient = this.sdk.getChainClient();\n const vaultAddress = chainClient.computeVaultAddress(keyHash);\n const exists = await chainClient.vaultExists(keyHash);\n\n let balance: PortfolioBalance | undefined;\n let limits: SpendingLimits | undefined;\n\n if (exists) {\n try {\n balance = await this.sdk.balance.getPortfolioBalance(chainId, vaultAddress, false);\n } catch { /* swallow — non-critical */ }\n\n try {\n limits = await this.getSpendingLimitsForVault(vaultAddress, chainId);\n } catch { /* swallow — non-critical */ }\n }\n\n return {\n keyHash,\n vaultAddress,\n wormholeChainId: chainId,\n exists,\n balance,\n limits,\n };\n }\n}\n","/**\n * @packageDocumentation\n * @module erc8004/contracts\n * @description\n * Low-level ERC-8004 contract utilities shared across SDK layers.\n * \n * Provides:\n * - Contract instance creation for Identity, Reputation, and Validation registries\n * - Address resolution by chain and network\n * - ABI references\n * \n * This module lives in the core SDK (`@veridex/sdk`) so that both the agent-sdk\n * and relayer can share the same contract interaction utilities.\n * \n * References:\n * - ADR-0029 §SDK Module Structure\n * - ERC8004_IMPLEMENTATION_PLAN.md Phase 1\n */\n\n// ============================================================================\n// Canonical Singleton Addresses (CREATE2 deterministic — same on every chain)\n// ============================================================================\n\n/** Identity Registry — same address on ALL EVM mainnets */\nexport const ERC8004_MAINNET_IDENTITY = '0x8004A169FB4a3325136EB29fA0ceB6D2e539a432';\n\n/** Reputation Registry — same address on ALL EVM mainnets */\nexport const ERC8004_MAINNET_REPUTATION = '0x8004BAa17C55a88189AE136b182e5fdA19dE9b63';\n\n/** Identity Registry — same address on ALL EVM testnets */\nexport const ERC8004_TESTNET_IDENTITY = '0x8004A818BFB912233c491871b3d84c89A494BD9e';\n\n/** Reputation Registry — same address on ALL EVM testnets */\nexport const ERC8004_TESTNET_REPUTATION = '0x8004B663056A597Dffe9eCcC1965A193B7388713';\n\n// Validation Registry addresses not yet published (spec still under active update)\n\n/**\n * Resolve canonical ERC-8004 registry addresses for a given network.\n */\nexport function getERC8004Addresses(testnet: boolean): {\n identityRegistry: string;\n reputationRegistry: string;\n} {\n return {\n identityRegistry: testnet ? ERC8004_TESTNET_IDENTITY : ERC8004_MAINNET_IDENTITY,\n reputationRegistry: testnet ? ERC8004_TESTNET_REPUTATION : ERC8004_MAINNET_REPUTATION,\n };\n}\n\n/**\n * Check if a chain has ERC-8004 singletons deployed.\n */\nexport function isERC8004Chain(chainName: string): boolean {\n return (ERC8004_CHAINS.mainnet as readonly string[]).includes(chainName) ||\n (ERC8004_CHAINS.testnet as readonly string[]).includes(chainName);\n}\n\n/** Chains where ERC-8004 singletons are deployed */\nexport const ERC8004_CHAINS = {\n mainnet: [\n 'ethereum', 'base', 'polygon', 'arbitrum', 'optimism', 'linea', 'megaeth', 'monad',\n ],\n testnet: [\n 'ethereum-sepolia', 'base-sepolia', 'polygon-amoy', 'arbitrum-sepolia',\n 'optimism-sepolia', 'monad-testnet',\n ],\n} as const;\n\n// ============================================================================\n// ABIs — Minimal read-only interfaces for cross-package use\n// ============================================================================\n\n/** Minimal Identity Registry ABI for read operations */\nexport const IDENTITY_REGISTRY_READ_ABI = [\n 'function ownerOf(uint256 tokenId) view returns (address)',\n 'function balanceOf(address owner) view returns (uint256)',\n 'function totalSupply() view returns (uint256)',\n 'function agentURI(uint256 agentId) view returns (string)',\n 'function agentWallet(uint256 agentId) view returns (address)',\n 'function getMetadata(uint256 agentId, string key) view returns (string)',\n] as const;\n\n/** Minimal Reputation Registry ABI for read operations */\nexport const REPUTATION_REGISTRY_READ_ABI = [\n 'function getSummary(uint256 agentId, address[] clientAddresses, string tag1, string tag2) view returns (uint256 count, int128 summaryValue, uint8 summaryValueDecimals)',\n 'function readFeedback(uint256 agentId, address clientAddress, uint256 feedbackIndex) view returns (int128 value, uint8 valueDecimals, string tag1, string tag2, bool isRevoked)',\n 'function getClients(uint256 agentId) view returns (address[])',\n 'function getLastIndex(uint256 agentId, address clientAddress) view returns (uint256)',\n] as const;\n\n/** Full Identity Registry ABI (read + write) */\nexport const IDENTITY_REGISTRY_ABI = [\n // Registration\n 'function register(string agentURI) returns (uint256)',\n 'function register(string agentURI, tuple(string key, string value)[] metadata) returns (uint256)',\n\n // Read — ERC-721 standard\n 'function ownerOf(uint256 tokenId) view returns (address)',\n 'function balanceOf(address owner) view returns (uint256)',\n 'function totalSupply() view returns (uint256)',\n\n // Read — ERC-8004 specific\n 'function agentURI(uint256 agentId) view returns (string)',\n 'function agentWallet(uint256 agentId) view returns (address)',\n 'function getMetadata(uint256 agentId, string key) view returns (string)',\n\n // Write — URI and wallet management\n 'function setAgentURI(uint256 agentId, string newURI)',\n 'function setAgentWallet(uint256 agentId, address wallet, uint256 deadline, bytes signature)',\n 'function unsetAgentWallet(uint256 agentId)',\n 'function setMetadata(uint256 agentId, string key, string value)',\n\n // Events\n 'event Transfer(address indexed from, address indexed to, uint256 indexed tokenId)',\n 'event AgentURIUpdated(uint256 indexed agentId, string newURI)',\n 'event AgentWalletSet(uint256 indexed agentId, address wallet)',\n 'event AgentWalletUnset(uint256 indexed agentId)',\n 'event MetadataUpdated(uint256 indexed agentId, string key, string value)',\n] as const;\n\n/** Full Reputation Registry ABI (read + write) */\nexport const REPUTATION_REGISTRY_ABI = [\n // Write\n 'function giveFeedback(uint256 agentId, int128 value, uint8 valueDecimals, string tag1, string tag2)',\n 'function giveFeedback(uint256 agentId, int128 value, uint8 valueDecimals, string tag1, string tag2, string endpointURI, string feedbackURI, bytes32 feedbackHash)',\n 'function revokeFeedback(uint256 agentId, uint256 feedbackIndex)',\n 'function appendResponse(uint256 agentId, address clientAddress, uint256 feedbackIndex, string responseURI, bytes32 responseHash)',\n\n // Read\n 'function getSummary(uint256 agentId, address[] clientAddresses, string tag1, string tag2) view returns (uint256 count, int128 summaryValue, uint8 summaryValueDecimals)',\n 'function readFeedback(uint256 agentId, address clientAddress, uint256 feedbackIndex) view returns (int128 value, uint8 valueDecimals, string tag1, string tag2, bool isRevoked)',\n 'function getClients(uint256 agentId) view returns (address[])',\n 'function getLastIndex(uint256 agentId, address clientAddress) view returns (uint256)',\n\n // Events\n 'event FeedbackGiven(uint256 indexed agentId, address indexed client, int128 value, uint8 valueDecimals)',\n 'event FeedbackRevoked(uint256 indexed agentId, address indexed client, uint256 feedbackIndex)',\n 'event ResponseAppended(uint256 indexed agentId, address indexed client, uint256 feedbackIndex)',\n] as const;\n\n/** Validation Registry ABI (Phase 3 — spec still under active update) */\nexport const VALIDATION_REGISTRY_ABI = [\n 'function validationRequest(address validatorAddress, uint256 agentId, string requestURI, bytes32 requestHash) returns (bytes32)',\n 'function getValidationStatus(bytes32 requestHash) view returns (address validatorAddress, uint256 agentId, uint8 response, bytes32 responseHash, string tag, uint256 lastUpdate)',\n 'function getSummary(uint256 agentId, address[] validatorAddresses, string tag) view returns (uint256 count, uint256 averageResponse)',\n 'function getAgentValidations(uint256 agentId) view returns (bytes32[])',\n] as const;\n"],"mappings":"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","names":["ethers","DEFAULT_RPC_URLS","ethers","ethers","DEFAULT_CONFIG","ethers","formatAmount","isNativeToken","ethers","ethers","VAULT_ABI","ethers","VeridexErrorCode","ethers","ethers","VAULT_FACTORY_ABI","TESTNET_CHAINS","MAINNET_CHAINS","ethers","result","data","ethers","ethers","ethers","ethers","ethers","ethers","ethers"]}
|