{"version":3,"sources":["../src/bridge.ts"],"sourcesContent":["/**\n * Core bridge utilities — shared between x402 and MPP clients.\n *\n * Auto-discovers bridge info from the RelAI API and provides helpers\n * for executing cross-chain payments transparently.\n *\n * Usage (MPP):\n * ```ts\n * import { evmChargeWithBridge } from '@relai-fi/x402/mpp/with-bridge'\n * ```\n *\n * Usage (x402):\n * ```ts\n * import { createX402Client } from '@relai-fi/x402'\n * const client = createX402Client({ ..., bridge: { enabled: true } })\n * ```\n */\n\nconst RELAI_API_BASE = 'https://api.relai.fi'\n\nexport interface BridgeInfo {\n  settleEndpoint: string\n  supportedSourceChains: string[]\n  supportedSourceAssets: string[]\n  payTo: Record<string, string>\n  feePayerSvm: string | null\n  feeBps: number\n  paymentFacilitator: string\n}\n\nexport interface BridgeSettleRequest {\n  /** x402 mode: base64-encoded payment header */\n  sourcePayment?: string\n  /** MPP mode: source tx hash */\n  sourceTxHash?: string\n  /** MPP mode: wallet address that sent the source tx */\n  senderAddress?: string\n  /** MPP mode: signature of (sourceTxHash + JSON(targetAccept)) */\n  senderSignature?: string\n  /** CAIP-2 source chain identifier */\n  sourceChain: string\n  targetAccept: {\n    scheme: 'exact'\n    network: string\n    asset: string\n    payTo: string\n    amount: string\n  }\n  /** x402 payment requirements (full 402 body) — needed by settle for x402 flow */\n  requirements?: any\n  resource?: string\n  paymentFacilitator?: string | null\n}\n\nexport interface BridgeSettleResponse {\n  success?: boolean\n  targetTxId?: string\n  sourceTxId?: string\n  /** x402 payment header (returned by x402-flavored settle) */\n  xPayment?: string\n}\n\n// ── Cache (keyed by base URL) ──────────────────────────────────────────\n\nconst _cacheMap = new Map<string, { info: BridgeInfo; time: number }>()\nconst CACHE_TTL = 5 * 60 * 1000 // 5 minutes\n\n/**\n * Fetch bridge info from the RelAI API (cached per base URL for 5 minutes).\n */\nexport async function getBridgeInfo(baseUrl = RELAI_API_BASE): Promise<BridgeInfo> {\n  const key = baseUrl.replace(/\\/$/, '')\n  const now = Date.now()\n  const cached = _cacheMap.get(key)\n  if (cached && now - cached.time < CACHE_TTL) return cached.info\n\n  const url = `${key}/bridge/info`\n  const res = await fetch(url)\n  if (!res.ok) {\n    if (cached) return cached.info // stale cache better than failure\n    throw new Error(`[relai:bridge] Failed to fetch ${url}: ${res.status}`)\n  }\n\n  const data = (await res.json()) as any\n  const info: BridgeInfo = {\n    settleEndpoint: data.settleEndpoint,\n    supportedSourceChains: data.supportedSourceChains || [],\n    supportedSourceAssets: data.supportedSourceAssets || [],\n    payTo: data.payTo || {},\n    feePayerSvm: data.feePayerSvm ?? null,\n    feeBps: data.feeBps ?? 100,\n    paymentFacilitator: data.paymentFacilitator || 'https://facilitator.x402.fi',\n  }\n  _cacheMap.set(key, { info, time: now })\n  return info\n}\n\n/**\n * Call the bridge settle endpoint.\n */\nexport async function settleBridge(\n  settleEndpoint: string,\n  body: BridgeSettleRequest,\n): Promise<BridgeSettleResponse> {\n  const res = await fetch(settleEndpoint, {\n    method: 'POST',\n    headers: { 'Content-Type': 'application/json' },\n    body: JSON.stringify(body),\n  })\n\n  if (!res.ok) {\n    const err = (await res.json().catch(() => ({}))) as any\n    throw new Error(`[relai:bridge] settle failed: ${err.error || res.status}${err.details ? ' — ' + err.details : ''}`)\n  }\n\n  return res.json() as Promise<BridgeSettleResponse>\n}\n\n/**\n * Select a source chain from supported chains that matches the available wallet.\n */\nexport function selectSourceChain(\n  supportedChains: string[],\n  hasEvmWallet: boolean,\n  hasSolanaWallet: boolean,\n  preferredSourceChainId?: number,\n): { type: 'evm' | 'solana'; chain: string } | null {\n  // If a specific source chain is preferred, try it first\n  if (preferredSourceChainId && hasEvmWallet) {\n    const preferred = `eip155:${preferredSourceChainId}`\n    if (supportedChains.includes(preferred)) {\n      return { type: 'evm', chain: preferred }\n    }\n  }\n\n  // Solana first (lower fees)\n  if (hasSolanaWallet) {\n    const sol = supportedChains.find((c) => c.startsWith('solana:'))\n    if (sol) return { type: 'solana', chain: sol }\n  }\n\n  // Then any EVM chain\n  if (hasEvmWallet) {\n    for (const chain of supportedChains) {\n      if (chain.startsWith('eip155:')) {\n        return { type: 'evm', chain }\n      }\n    }\n  }\n\n  return null\n}\n\n/**\n * Compute source amount including bridge fee.\n */\nexport function computeSourceAmount(targetAmount: bigint, feeBps: number): bigint {\n  const fee = (targetAmount * BigInt(feeBps)) / 10000n\n  return targetAmount + fee\n}\n\n// Known EVM RPC URLs (fallback)\nexport const DEFAULT_EVM_RPC: Record<string, string> = {\n  'eip155:8453': 'https://mainnet.base.org',\n  'eip155:137': 'https://polygon-rpc.com',\n  'eip155:1': 'https://eth.llamarpc.com',\n  'eip155:42161': 'https://arb1.arbitrum.io/rpc',\n  'eip155:43114': 'https://api.avax.network/ext/bc/C/rpc',\n  'eip155:1187947933': 'https://skale-base.skalenodes.com/v1/base',\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAkBA,IAAM,iBAAiB;AA8CvB,IAAM,YAAY,oBAAI,IAAgD;AACtE,IAAM,YAAY,IAAI,KAAK;AAK3B,eAAsB,cAAc,UAAU,gBAAqC;AACjF,QAAM,MAAM,QAAQ,QAAQ,OAAO,EAAE;AACrC,QAAM,MAAM,KAAK,IAAI;AACrB,QAAM,SAAS,UAAU,IAAI,GAAG;AAChC,MAAI,UAAU,MAAM,OAAO,OAAO,UAAW,QAAO,OAAO;AAE3D,QAAM,MAAM,GAAG,GAAG;AAClB,QAAM,MAAM,MAAM,MAAM,GAAG;AAC3B,MAAI,CAAC,IAAI,IAAI;AACX,QAAI,OAAQ,QAAO,OAAO;AAC1B,UAAM,IAAI,MAAM,kCAAkC,GAAG,KAAK,IAAI,MAAM,EAAE;AAAA,EACxE;AAEA,QAAM,OAAQ,MAAM,IAAI,KAAK;AAC7B,QAAM,OAAmB;AAAA,IACvB,gBAAgB,KAAK;AAAA,IACrB,uBAAuB,KAAK,yBAAyB,CAAC;AAAA,IACtD,uBAAuB,KAAK,yBAAyB,CAAC;AAAA,IACtD,OAAO,KAAK,SAAS,CAAC;AAAA,IACtB,aAAa,KAAK,eAAe;AAAA,IACjC,QAAQ,KAAK,UAAU;AAAA,IACvB,oBAAoB,KAAK,sBAAsB;AAAA,EACjD;AACA,YAAU,IAAI,KAAK,EAAE,MAAM,MAAM,IAAI,CAAC;AACtC,SAAO;AACT;AAKA,eAAsB,aACpB,gBACA,MAC+B;AAC/B,QAAM,MAAM,MAAM,MAAM,gBAAgB;AAAA,IACtC,QAAQ;AAAA,IACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,IAC9C,MAAM,KAAK,UAAU,IAAI;AAAA,EAC3B,CAAC;AAED,MAAI,CAAC,IAAI,IAAI;AACX,UAAM,MAAO,MAAM,IAAI,KAAK,EAAE,MAAM,OAAO,CAAC,EAAE;AAC9C,UAAM,IAAI,MAAM,iCAAiC,IAAI,SAAS,IAAI,MAAM,GAAG,IAAI,UAAU,aAAQ,IAAI,UAAU,EAAE,EAAE;AAAA,EACrH;AAEA,SAAO,IAAI,KAAK;AAClB;AAKO,SAAS,kBACd,iBACA,cACA,iBACA,wBACkD;AAElD,MAAI,0BAA0B,cAAc;AAC1C,UAAM,YAAY,UAAU,sBAAsB;AAClD,QAAI,gBAAgB,SAAS,SAAS,GAAG;AACvC,aAAO,EAAE,MAAM,OAAO,OAAO,UAAU;AAAA,IACzC;AAAA,EACF;AAGA,MAAI,iBAAiB;AACnB,UAAM,MAAM,gBAAgB,KAAK,CAAC,MAAM,EAAE,WAAW,SAAS,CAAC;AAC/D,QAAI,IAAK,QAAO,EAAE,MAAM,UAAU,OAAO,IAAI;AAAA,EAC/C;AAGA,MAAI,cAAc;AAChB,eAAW,SAAS,iBAAiB;AACnC,UAAI,MAAM,WAAW,SAAS,GAAG;AAC/B,eAAO,EAAE,MAAM,OAAO,MAAM;AAAA,MAC9B;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAKO,SAAS,oBAAoB,cAAsB,QAAwB;AAChF,QAAM,MAAO,eAAe,OAAO,MAAM,IAAK;AAC9C,SAAO,eAAe;AACxB;AAGO,IAAM,kBAA0C;AAAA,EACrD,eAAe;AAAA,EACf,cAAc;AAAA,EACd,YAAY;AAAA,EACZ,gBAAgB;AAAA,EAChB,gBAAgB;AAAA,EAChB,qBAAqB;AACvB;","names":[]}