{"version":3,"sources":["../../src/auth/prepareAuth.ts"],"sourcesContent":["import { ethers } from 'ethers';\n\nimport type { PasskeyCredential, TransferParams, ExecuteParams, BridgeParams } from '../core/types.js';\nimport { PasskeyManager } from '../core/PasskeyManager.js';\nimport { buildGaslessChallenge, encodeBridgeAction, encodeExecuteAction, encodeTransferAction } from '../payload.js';\nimport { queryHubState } from '../queries/hubState.js';\nimport { getDefaultHub } from '../presets.js';\n\nexport type AuthenticateAndPrepareParams = {\n  credential: PasskeyCredential;\n  action?: TransferParams | ExecuteParams | BridgeParams;\n  /** Pre-encoded Hub action payload (hex string). If provided, `action` is ignored. */\n  actionPayload?: string;\n  targetChain: number;\n};\n\nexport type AuthenticateAndPrepareResult = {\n  serializedTx: Uint8Array;\n  queryProof: Uint8Array<ArrayBufferLike>;\n  estimatedLatency: number;\n  fallbackAvailable: boolean;\n};\n\nfunction resolveNetwork(): 'testnet' | 'mainnet' {\n  const envCandidates = [\n    (globalThis as any)?.process?.env?.NEXT_PUBLIC_VERIDEX_NETWORK,\n    (globalThis as any)?.process?.env?.VERIDEX_NETWORK,\n    (globalThis as any)?.process?.env?.NEXT_PUBLIC_WORMHOLE_NETWORK,\n    (globalThis as any)?.process?.env?.WORMHOLE_NETWORK,\n  ].filter(Boolean);\n\n  const env = (envCandidates[0] as string | undefined)?.toLowerCase();\n  if (env === 'mainnet' || env === 'testnet') return env;\n  return 'testnet';\n}\n\nfunction getHubChainId(network: 'testnet' | 'mainnet'): number {\n  return getDefaultHub(network).wormholeChainId;\n}\n\nfunction getHubRpcUrl(network: 'testnet' | 'mainnet'): string {\n  return getDefaultHub(network).rpcUrl;\n}\n\nfunction getHubAddress(network: 'testnet' | 'mainnet'): string {\n  const hub = getDefaultHub(network).contracts.hub;\n  if (!hub) {\n    throw new Error('Hub address missing in SDK constants');\n  }\n  return hub;\n}\n\nfunction encodeActionPayload(action: TransferParams | ExecuteParams | BridgeParams, targetChain: number): string {\n  if ((action as TransferParams).token !== undefined && (action as TransferParams).recipient !== undefined) {\n    const a = action as TransferParams;\n    return encodeTransferAction(a.token, a.recipient, a.amount);\n  }\n\n  if ((action as ExecuteParams).target !== undefined && (action as ExecuteParams).data !== undefined) {\n    const a = action as ExecuteParams;\n    return encodeExecuteAction(a.target, a.value, a.data);\n  }\n\n  const a = action as BridgeParams;\n  return encodeBridgeAction(a.token, a.amount, targetChain, a.recipient);\n}\n\nasync function fetchNonceViaRpc(userKeyHash: string, network: 'testnet' | 'mainnet'): Promise<bigint> {\n  const rpcUrl = getHubRpcUrl(network);\n  const hubAddress = getHubAddress(network);\n\n  const provider = new ethers.JsonRpcProvider(rpcUrl);\n  const hubIface = new ethers.Interface([\n    'function getNonce(bytes32 userKeyHash) external view returns (uint256)',\n    'function userNonces(bytes32 userKeyHash) external view returns (uint256)',\n  ]);\n\n  const calls: Array<() => Promise<bigint>> = [\n    async () => {\n      const data = hubIface.encodeFunctionData('getNonce', [userKeyHash]);\n      const res = await provider.call({ to: hubAddress, data });\n      const decoded = hubIface.decodeFunctionResult('getNonce', res);\n      return decoded[0] as bigint;\n    },\n    async () => {\n      const data = hubIface.encodeFunctionData('userNonces', [userKeyHash]);\n      const res = await provider.call({ to: hubAddress, data });\n      const decoded = hubIface.decodeFunctionResult('userNonces', res);\n      return decoded[0] as bigint;\n    },\n  ];\n\n  let lastErr: unknown;\n  for (const fn of calls) {\n    try {\n      return await fn();\n    } catch (e) {\n      lastErr = e;\n    }\n  }\n\n  throw lastErr instanceof Error ? lastErr : new Error(String(lastErr));\n}\n\nfunction toHex32(value: bigint): string {\n  return '0x' + value.toString(16).padStart(64, '0');\n}\n\n/**\n * Client-first authentication preparation:\n * - user signs locally (FaceID/TouchID)\n * - client queries Wormhole Query Proxy for Guardian-attested nonce/state\n * - client returns a ready-to-submit relayer payload (JSON bytes)\n * - falls back to RPC nonce if Queries fails\n */\nexport async function authenticateAndPrepare(\n  userParams: AuthenticateAndPrepareParams,\n  apiKey: string\n): Promise<AuthenticateAndPrepareResult> {\n  const network = resolveNetwork();\n  const hubChainId = getHubChainId(network);\n\n  const actionPayload = userParams.actionPayload ?? (userParams.action\n    ? encodeActionPayload(userParams.action, userParams.targetChain)\n    : undefined);\n\n  if (!actionPayload) {\n    throw new Error('Missing action payload: provide either actionPayload or action');\n  }\n\n  let nonce: bigint;\n  let queryProof: Uint8Array<ArrayBufferLike> = new Uint8Array();\n  let fallbackAvailable = true;\n\n  const queryStart = Date.now();\n  try {\n    if (!apiKey) {\n      throw new Error('Missing Query Proxy apiKey');\n    }\n\n    const state = await queryHubState(userParams.credential.keyHash, apiKey, { network, maxAge: 60 });\n\n    if (!state.isRegistered) {\n      // This is a hard failure: signing won’t help if the key isn’t registered.\n      throw new Error('Passkey is not registered on Hub');\n    }\n\n    nonce = state.nonce;\n    queryProof = state.proof;\n  } catch {\n    // Fallback: fetch nonce directly from hub RPC.\n    nonce = await fetchNonceViaRpc(userParams.credential.keyHash, network);\n    queryProof = new Uint8Array();\n  }\n  const queryLatencyMs = Date.now() - queryStart;\n\n  const challenge = buildGaslessChallenge(userParams.targetChain, actionPayload, nonce, hubChainId);\n  const passkey = new PasskeyManager();\n  passkey.setCredential(userParams.credential);\n  const signature = await passkey.sign(challenge);\n\n  // Relayer request body (matches packages/relayer POST /api/v1/submit requirements)\n  // Uses full WebAuthn data for authenticateAndDispatch\n  const requestBody: any = {\n    authenticatorData: signature.authenticatorData,\n    clientDataJSON: signature.clientDataJSON,\n    challengeIndex: signature.challengeIndex,\n    typeIndex: signature.typeIndex,\n    r: toHex32(signature.r),\n    s: toHex32(signature.s),\n    publicKeyX: toHex32(userParams.credential.publicKeyX),\n    publicKeyY: toHex32(userParams.credential.publicKeyY),\n    targetChain: userParams.targetChain,\n    actionPayload,\n    nonce: Number(nonce),\n  };\n\n  // Include proof as an optional field for callers to forward/store (relayer ignores extra fields).\n  if (queryProof.length) {\n    requestBody.queryProof = ethers.hexlify(queryProof);\n  }\n\n  const serializedTx = new TextEncoder().encode(JSON.stringify(requestBody));\n\n  // Heuristic: Queries is sub-second; RPC nonce lookup is slower.\n  const estimatedLatency = queryProof.length ? Math.max(250, queryLatencyMs) : Math.max(800, queryLatencyMs);\n\n  return {\n    serializedTx,\n    queryProof,\n    estimatedLatency,\n    fallbackAvailable,\n  };\n}\n"],"mappings":"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","names":["a"]}