{"version":3,"sources":["../src/utils.ts"],"sourcesContent":["/**\n * Veridex Protocol SDK - Utility Functions\n */\n\nimport { ethers } from 'ethers';\nimport type { ChainConfig } from './types.js';\nimport { TESTNET_CHAINS, MAINNET_CHAINS } from './constants.js';\n\n// ============================================================================\n// Base64URL Encoding/Decoding (WebAuthn compatible)\n// ============================================================================\n\n/**\n * Base64URL encode a buffer\n */\nexport function base64URLEncode(buffer: Uint8Array): string {\n  // Convert Uint8Array to base64 using browser APIs\n  const bytes = Array.from(buffer);\n  const binary = String.fromCharCode(...bytes);\n  const base64 = btoa(binary);\n  return base64.replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=/g, '');\n}\n\n/**\n * Base64URL decode a string\n */\nexport function base64URLDecode(str: string): Uint8Array {\n  const base64 = str.replace(/-/g, '+').replace(/_/g, '/');\n  const padded = base64 + '='.repeat((4 - (base64.length % 4)) % 4);\n  // Use browser's atob for base64 decoding\n  const binary = atob(padded);\n  const bytes = new Uint8Array(binary.length);\n  for (let i = 0; i < binary.length; i++) {\n    bytes[i] = binary.charCodeAt(i);\n  }\n  return bytes;\n}\n\n// ============================================================================\n// Signature Utilities\n// ============================================================================\n\n/**\n * Parse DER-encoded ECDSA signature to r and s values\n */\nexport function parseDERSignature(signature: Uint8Array): { r: Uint8Array; s: Uint8Array } {\n  let offset = 0;\n\n  if (signature[offset++] !== 0x30) {\n    throw new Error('Invalid signature format');\n  }\n\n  // Skip total length\n  offset++;\n\n  if (signature[offset++] !== 0x02) {\n    throw new Error('Invalid signature format');\n  }\n\n  const rLength = signature[offset++];\n  if (rLength === undefined) {\n    throw new Error('Invalid signature format: missing r length');\n  }\n  let r = signature.slice(offset, offset + rLength);\n  offset += rLength;\n\n  // Remove leading zero if present (for positive number representation)\n  if (r[0] === 0x00 && r.length > 32) {\n    r = r.slice(1);\n  }\n  // Pad to 32 bytes if needed\n  if (r.length < 32) {\n    const padded = new Uint8Array(32);\n    padded.set(r, 32 - r.length);\n    r = padded;\n  }\n\n  if (signature[offset++] !== 0x02) {\n    throw new Error('Invalid signature format');\n  }\n\n  const sLength = signature[offset++];\n  if (sLength === undefined) {\n    throw new Error('Invalid signature format: missing s length');\n  }\n  let s = signature.slice(offset, offset + sLength);\n\n  // Remove leading zero if present\n  if (s[0] === 0x00 && s.length > 32) {\n    s = s.slice(1);\n  }\n  // Pad to 32 bytes if needed\n  if (s.length < 32) {\n    const padded = new Uint8Array(32);\n    padded.set(s, 32 - s.length);\n    s = padded;\n  }\n\n  return { r, s };\n}\n\n/**\n * Encode signature for Solidity verification\n */\nexport function encodeSignatureForSolidity(r: bigint, s: bigint): string {\n  return ethers.solidityPacked(['uint256', 'uint256'], [r, s]);\n}\n\n// ============================================================================\n// Key Hash Utilities\n// ============================================================================\n\n/**\n * Compute key hash from public key coordinates\n */\nexport function computeKeyHash(publicKeyX: bigint, publicKeyY: bigint): string {\n  return ethers.keccak256(\n    ethers.solidityPacked(['uint256', 'uint256'], [publicKeyX, publicKeyY])\n  );\n}\n\n// ============================================================================\n// Chain Utilities\n// ============================================================================\n\n/**\n * Get chain config by name\n */\nexport function getChainConfig(chainName: string, testnet = true): ChainConfig | undefined {\n  const chains = testnet ? TESTNET_CHAINS : MAINNET_CHAINS;\n  return chains[chainName];\n}\n\n/**\n * Get chain config by Wormhole chain ID\n */\nexport function getChainByWormholeId(wormholeChainId: number, testnet = true): ChainConfig | undefined {\n  const chains = testnet ? TESTNET_CHAINS : MAINNET_CHAINS;\n  return Object.values(chains).find(chain => chain.wormholeChainId === wormholeChainId);\n}\n\n/**\n * Get chain config by EVM chain ID\n */\nexport function getChainByEvmId(evmChainId: number, testnet = true): ChainConfig | undefined {\n  const chains = testnet ? TESTNET_CHAINS : MAINNET_CHAINS;\n  return Object.values(chains).find(chain => chain.chainId === evmChainId);\n}\n\n/**\n * Check if a chain is EVM-compatible\n */\nexport function isEvmChain(wormholeChainId: number): boolean {\n  // Non-EVM chains\n  const nonEvmChains = new Set([1, 8, 15, 21, 22]); // Solana, Algorand, NEAR, Sui, Aptos\n  return !nonEvmChains.has(wormholeChainId);\n}\n\n/**\n * Get all supported chains\n */\nexport function getSupportedChains(testnet = true): ChainConfig[] {\n  const chains = testnet ? TESTNET_CHAINS : MAINNET_CHAINS;\n  return Object.values(chains);\n}\n\n// ============================================================================\n// Explorer URL Utilities\n// ============================================================================\n\n/**\n * Get transaction explorer URL\n */\nexport function getTxExplorerUrl(chain: ChainConfig, txHash: string): string {\n  if (chain.isEvm) {\n    return `${chain.explorerUrl}/tx/${txHash}`;\n  }\n\n  // Non-EVM chains have different URL patterns\n  switch (chain.wormholeChainId) {\n    case 1: // Solana\n      return `${chain.explorerUrl}/tx/${txHash}?cluster=devnet`;\n    case 21: // Sui\n      return `${chain.explorerUrl}/tx/${txHash}`;\n    case 22: // Aptos\n      return `${chain.explorerUrl}/txn/${txHash}?network=testnet`;\n    default:\n      return `${chain.explorerUrl}/tx/${txHash}`;\n  }\n}\n\n/**\n * Get address explorer URL\n */\nexport function getAddressExplorerUrl(chain: ChainConfig, address: string): string {\n  if (chain.isEvm) {\n    return `${chain.explorerUrl}/address/${address}`;\n  }\n\n  switch (chain.wormholeChainId) {\n    case 1: // Solana\n      return `${chain.explorerUrl}/address/${address}?cluster=devnet`;\n    case 21: // Sui\n      return `${chain.explorerUrl}/account/${address}`;\n    case 22: // Aptos\n      return `${chain.explorerUrl}/account/${address}?network=testnet`;\n    default:\n      return `${chain.explorerUrl}/address/${address}`;\n  }\n}\n\n// ============================================================================\n// Validation Utilities\n// ============================================================================\n\n/**\n * Validate an EVM address\n */\nexport function isValidEvmAddress(address: string): boolean {\n  return ethers.isAddress(address);\n}\n\n/**\n * Validate a bytes32 hex string\n */\nexport function isValidBytes32(hex: string): boolean {\n  const clean = hex.replace('0x', '');\n  return /^[0-9a-fA-F]{64}$/.test(clean);\n}\n\n/**\n * Validate a Wormhole chain ID\n */\nexport function isValidWormholeChainId(chainId: number): boolean {\n  // Valid Wormhole chain IDs range from 1 to ~10007 (testnets)\n  return chainId >= 1 && chainId <= 50000;\n}\n\n// ============================================================================\n// Retry Utilities\n// ============================================================================\n\n/**\n * Retry a function with exponential backoff\n */\nexport async function retryWithBackoff<T>(\n  fn: () => Promise<T>,\n  options: {\n    maxRetries?: number;\n    initialDelayMs?: number;\n    maxDelayMs?: number;\n    backoffMultiplier?: number;\n    onRetry?: (attempt: number, error: Error) => void;\n  } = {}\n): Promise<T> {\n  const {\n    maxRetries = 5,\n    initialDelayMs = 1000,\n    maxDelayMs = 30000,\n    backoffMultiplier = 2,\n    onRetry,\n  } = options;\n\n  let lastError: Error | undefined;\n  let delay = initialDelayMs;\n\n  for (let attempt = 1; attempt <= maxRetries; attempt++) {\n    try {\n      return await fn();\n    } catch (error) {\n      lastError = error as Error;\n\n      if (attempt < maxRetries) {\n        onRetry?.(attempt, lastError);\n        await sleep(delay);\n        delay = Math.min(delay * backoffMultiplier, maxDelayMs);\n      }\n    }\n  }\n\n  throw lastError ?? new Error('Retry failed');\n}\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\nfunction sleep(ms: number): Promise<void> {\n  return new Promise(resolve => setTimeout(resolve, ms));\n}\n"],"mappings":"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","names":[]}