{"version":3,"file":"token-decimals.mjs","names":[],"sources":["../../../src/lib/token-decimals.ts"],"sourcesContent":["/**\n * Shared utility for resolving ERC-20 token decimals.\n *\n * Used by defi-swap (3 call sites), the plan executor balance resolver,\n * safety-service, and allowance-manager.\n *\n * Strategy:\n * 1. ETH/WETH → 18 (no RPC needed)\n * 2. Well-known stablecoins (USDC, USDT) → 6\n * 3. On-chain `decimals()` call via publicClient\n * 4. Fallback to 18 if all else fails\n */\n\n/** Well-known token addresses on Base (lowercase for comparison). */\nconst WELL_KNOWN_DECIMALS: Record<string, number> = {\n  // USDC on Base\n  '0x833589fcd6edb6e08f4c7c32d4f71b54bda02913': 6,\n  // USDT on Base\n  '0xfde4c96c8593536e31f229ea8f37b2ada2699bb2': 6,\n  // USDC on Ethereum\n  '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48': 6,\n  // USDT on Ethereum\n  '0xdac17f958d2ee523a2206206994597c13d831ec7': 6,\n  // USDC on Polygon\n  '0x3c499c542cef5e3811e1192ce70d8cc03d5c3359': 6,\n  // USDC.e on Polygon\n  '0x2791bca1f2de4661ed88a30c99a7a9449aa84174': 6,\n};\n\n/** Sentinel addresses that represent native ETH (not an ERC-20). */\nconst ETH_ADDRESSES = new Set([\n  '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee', // common sentinel\n  '0x4200000000000000000000000000000000000006', // WETH on Base / OP\n]);\n\n/**\n * Resolve the decimal count for a token address.\n *\n * @param tokenAddress - The ERC-20 contract address (0x...) or ETH sentinel.\n * @param publicClient - A viem PublicClient (or compatible) for on-chain reads.\n *                        Pass `null` to skip on-chain resolution.\n * @returns The token's decimal count (defaults to 18 if unknown).\n */\nexport async function resolveTokenDecimals(\n  tokenAddress: string,\n  publicClient: { readContract: (args: any) => Promise<unknown> } | null,\n): Promise<number> {\n  const lower = tokenAddress.toLowerCase();\n\n  // 1. Native ETH / WETH\n  if (ETH_ADDRESSES.has(lower)) {\n    return 18;\n  }\n\n  // 2. Well-known stablecoins\n  const known = WELL_KNOWN_DECIMALS[lower];\n  if (known !== undefined) {\n    return known;\n  }\n\n  // 3. On-chain read\n  if (publicClient) {\n    try {\n      const dec = await publicClient.readContract({\n        address: tokenAddress as `0x${string}`,\n        abi: [{\n          name: 'decimals',\n          type: 'function',\n          stateMutability: 'view',\n          inputs: [],\n          outputs: [{ name: '', type: 'uint8' }],\n        }] as const,\n        functionName: 'decimals',\n      });\n      return Number(dec);\n    } catch {\n      // Contract might not implement decimals() — fall through\n    }\n  }\n\n  // 4. Fallback\n  return 18;\n}\n\n/**\n * Check if a token address represents native ETH (including WETH).\n */\nexport function isNativeEth(tokenAddress: string): boolean {\n  return ETH_ADDRESSES.has(tokenAddress.toLowerCase());\n}\n"],"mappings":";;;;;;;;;;;;;;AAcA,MAAM,sBAA8C;CAElD,8CAA8C;CAE9C,8CAA8C;CAE9C,8CAA8C;CAE9C,8CAA8C;CAE9C,8CAA8C;CAE9C,8CAA8C;CAC/C;;AAGD,MAAM,gBAAgB,IAAI,IAAI,CAC5B,8CACA,6CACD,CAAC;;;;;;;;;AAUF,eAAsB,qBACpB,cACA,cACiB;CACjB,MAAM,QAAQ,aAAa,aAAa;AAGxC,KAAI,cAAc,IAAI,MAAM,CAC1B,QAAO;CAIT,MAAM,QAAQ,oBAAoB;AAClC,KAAI,UAAU,KAAA,EACZ,QAAO;AAIT,KAAI,aACF,KAAI;EACF,MAAM,MAAM,MAAM,aAAa,aAAa;GAC1C,SAAS;GACT,KAAK,CAAC;IACJ,MAAM;IACN,MAAM;IACN,iBAAiB;IACjB,QAAQ,EAAE;IACV,SAAS,CAAC;KAAE,MAAM;KAAI,MAAM;KAAS,CAAC;IACvC,CAAC;GACF,cAAc;GACf,CAAC;AACF,SAAO,OAAO,IAAI;SACZ;AAMV,QAAO;;;;;AAMT,SAAgB,YAAY,cAA+B;AACzD,QAAO,cAAc,IAAI,aAAa,aAAa,CAAC"}