@anywalletkit/protocol-swap2-cctp 0.5.4 → 0.5.5
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/{chunk-LK64TDTT.js → chunk-3UR3G3XL.js} +2 -2
- package/dist/{chunk-H4W3JMYC.js → chunk-UPA4KJKX.js} +76 -42
- package/dist/chunk-UPA4KJKX.js.map +1 -0
- package/dist/index.cjs +75 -41
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +2 -2
- package/dist/protocol.cjs +75 -41
- package/dist/protocol.cjs.map +1 -1
- package/dist/protocol.js +2 -2
- package/dist/provider.cjs +75 -41
- package/dist/provider.cjs.map +1 -1
- package/dist/provider.d.cts +1 -0
- package/dist/provider.d.ts +1 -0
- package/dist/provider.js +1 -1
- package/package.json +3 -3
- package/dist/chunk-H4W3JMYC.js.map +0 -1
- /package/dist/{chunk-LK64TDTT.js.map → chunk-3UR3G3XL.js.map} +0 -0
package/dist/protocol.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/protocol.ts","../src/config.ts","../src/provider.ts","../src/activity.ts"],"sourcesContent":["import {SingleProviderSwap2} from \"@anywalletkit/protocol-swap2-core/swap2/single\";\nimport type {Swap2Account, Swap2EngineConfig} from \"@anywalletkit/protocol-swap2-core/swap2/base\";\nimport {cctp as cctpCfg} from \"./config.js\";\nimport {cctpProvider, type CctpProviderConfig} from \"./provider.js\";\n\nexport interface CctpSwap2Config extends Swap2EngineConfig, CctpProviderConfig {}\n\n/** Standalone CCTP swap2: USDC burn-and-mint between EVM chains, claim via `claimSwap2`. */\nexport class CctpSwap2Protocol extends SingleProviderSwap2 {\n protected readonly provider;\n constructor(account: Swap2Account | undefined, config: CctpSwap2Config) {\n super(account, config);\n this.provider = cctpProvider(config);\n }\n protected override chainSupported(caip2: string): boolean {\n return cctpCfg.supportsChain(caip2);\n }\n protected override pairSupported(fromChain: string, toChain: string): boolean {\n return cctpCfg.supports(fromChain, toChain);\n }\n}\n","// Circle CCTP V2 — mainnet domains, contracts and the native USDC each domain\n// mints. Sources (read 2026-10-10, Arc + Morph 2026-10-14): developers.circle.com/cctp/evm-smart-contracts\n// (domains + TokenMessengerV2 / MessageTransmitterV2, the same addresses on\n// every EVM chain except EDGE), developers.circle.com/stablecoins/usdc-contract-addresses\n// (native USDC). Only chains whose USDC is Circle-native are listed: CCTP\n// burns native USDC, a bridged USDC.e (BSC, Gnosis) cannot ride it.\nimport {evmRef, isEvm} from \"@anywalletkit/protocol-swap2-core/util\";\n\nexport interface CctpDomain {\n caip2: string;\n chainId: number;\n domain: number;\n name: string;\n usdc: string;\n tokenMessenger: string;\n messageTransmitter: string;\n}\n\nexport const TOKEN_MESSENGER_V2 = \"0x28b5a0e9C621a5BadaA536219b3a228C8168cf5d\";\nexport const MESSAGE_TRANSMITTER_V2 = \"0x81D40F21F12A8F0E3252Bccb954D722d4c464B64\";\n\nconst d = (chainId: number, domain: number, name: string, usdc: string): CctpDomain => ({\n caip2: `eip155:${chainId}`, chainId, domain, name, usdc, tokenMessenger: TOKEN_MESSENGER_V2, messageTransmitter: MESSAGE_TRANSMITTER_V2,\n});\n\n/** CAIP-2 → CCTP domain. */\nexport const CCTP_DOMAINS: Readonly<Record<string, CctpDomain>> = Object.freeze(Object.fromEntries([\n d(1, 0, \"Ethereum\", \"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48\"),\n d(43114, 1, \"Avalanche\", \"0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E\"),\n d(10, 2, \"OP Mainnet\", \"0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85\"),\n d(42161, 3, \"Arbitrum\", \"0xaf88d065e77c8cC2239327C5EDb3A432268e5831\"),\n d(8453, 6, \"Base\", \"0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913\"),\n d(137, 7, \"Polygon PoS\", \"0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359\"),\n d(130, 10, \"Unichain\", \"0x078D782b760474a361dDA0AF3839290b0EF57AD6\"),\n d(59144, 11, \"Linea\", \"0x176211869cA2b568f2A7D4EE941E073a821EE1ff\"),\n d(146, 13, \"Sonic\", \"0x29219dd400f2Bf60E5a23d13Be72B486D4038894\"),\n d(480, 14, \"World Chain\", \"0x79A02482A880bCe3F13E09da970dC34dB4cD24D1\"),\n d(143, 15, \"Monad\", \"0x754704Bc059F8C67012fEd69BC8A327a5aafb603\"),\n d(1329, 16, \"Sei\", \"0xe15fC38F6D8c56aF07bbCBe3BAf5708A2Bf42392\"),\n d(999, 19, \"HyperEVM\", \"0xb88339CB7199b77E23DB6E890353E22632Ba630f\"),\n d(57073, 21, \"Ink\", \"0x2D270e6886d130D724215A266106e6832161EAEd\"),\n d(98866, 22, \"Plume\", \"0x222365EF19F7947e5484218551B56bb3965Aa7aF\"),\n d(9745, 33, \"Plasma\", \"0x2d661C89D812261039AF9764eceaAee884f5F67F\"),\n d(196, 37, \"X Layer\", \"0xB6CEceAB302E2E4948951eE7843FC24E92933061\"),\n // 2026-10-14: Arc and Morph (developers.circle.com/cctp/evm-smart-contracts + usdc-contract-addresses; TokenMessengerV2 /\n // MessageTransmitterV2 have code on both chains, MessageTransmitterV2.localDomain() answers 26 / 30 and\n // TokenMessengerV2.localMessageTransmitter() points at 0x81D4…). Arc's USDC is the chain's gas token: 0x3600… is its\n // 6-decimal ERC-20 interface, which is what CCTP burns and mints.\n d(5042, 26, \"Arc\", \"0x3600000000000000000000000000000000000000\"),\n d(2818, 30, \"Morph\", \"0xCfb1186F4e93D60E60a8bDd997427D1F33bc372B\"),\n].map((x) => [x.caip2, x])));\n\n/** CCTP domain → entry. */\nexport const CCTP_BY_DOMAIN: Readonly<Record<number, CctpDomain>> = Object.freeze(\n Object.fromEntries(Object.values(CCTP_DOMAINS).map((x) => [x.domain, x])),\n);\n\n/** Solana is CCTP domain 5 (not executed by this package yet: the engine runs calldata on EVM only). */\nexport const CCTP_SOLANA_DOMAIN = 5;\n\nexport const CCTP_API = \"https://iris-api.circle.com\";\n\n/** Finality thresholds the header carries: Fast Transfer (confirmed) vs Standard (finalized). */\nexport const FINALITY_FAST = 1000;\nexport const FINALITY_STANDARD = 2000;\n\nexport const cctp = {\n supportsChain(chain: string): boolean {\n return isEvm(chain) && !!CCTP_DOMAINS[`eip155:${evmRef(chain)}`];\n },\n supports(from: string, to: string): boolean {\n return from !== to && this.supportsChain(from) && this.supportsChain(to);\n },\n};\n","import type {RemotePins} from \"@anywalletkit/protocol-swap2-core/types\";\nimport {createPublicClient, decodeFunctionData, encodeFunctionData, getAddress, http, isAddress, pad, parseAbi, zeroHash, type Hex} from \"viem\";\nimport {describeCctpActivity} from \"./activity.js\";\nimport {ccAsset} from \"@anywalletkit/swap2-assets\";\nimport {timeoutSignal} from \"@anywalletkit/protocol-swap2-core/util\";\nimport type {Asset, CrossChainProvider, IntentRef, IntentStatus, Quote, QuoteParams, UnsignedTx} from \"@anywalletkit/protocol-swap2-core/types\";\nimport {CCTP_API, CCTP_BY_DOMAIN, CCTP_DOMAINS, FINALITY_FAST, FINALITY_STANDARD, cctp as cctpCfg, type CctpDomain} from \"./config.js\";\nimport {bigintToNumber} from \"@anywalletkit/core\";\n\n/**\n * Circle CCTP V2 — native USDC between chains by burn-and-mint, no spread, no\n * aggregator fee. TWO-PHASE: `depositForBurn` on the source burns the USDC and\n * emits the message; Circle's attestation service (Iris) signs it once the\n * source reached the requested finality; `receiveMessage(message, attestation)`\n * on the destination mints. That second transaction is the user's: the engine\n * exposes it through `buildClaim` / `claimSwap2` (status \"action-required\").\n *\n * - Fast Transfer (finality 1000, confirmed, ~seconds–minutes) costs a fee in\n * bps that Circle publishes per pair; Standard (2000, finalized, ~15 min)\n * is free. `mode: \"auto\"` takes Fast when the pair offers it and the Fast\n * allowance covers the amount, else Standard.\n * - `maxFee` sent on-chain is the published fee (plus a small buffer) and is\n * the only thing that can be deducted: the guaranteed output is\n * amount − maxFee. `preflightDeposit` re-reads Circle's published fee right\n * before the burn (the deployed TokenMessengerV2 has no on-chain\n * `getMinFeeAmount`/`minFee` — both revert on Ethereum, Base, Arbitrum,\n * 2026-10-12) and, with an RPC for the source chain, the transmitter's\n * `localDomain()` on the very contract the calldata targets.\n * - Everything is bound to Circle's documented contract addresses and the\n * native USDC of each domain; a catalog USDC that is not the native one\n * refuses the route (USDC.e cannot be burnt).\n */\n\nconst TOKEN_MESSENGER_ABI = parseAbi([\n \"function depositForBurn(uint256 amount, uint32 destinationDomain, bytes32 mintRecipient, address burnToken, bytes32 destinationCaller, uint256 maxFee, uint32 minFinalityThreshold)\",\n \"function localMessageTransmitter() view returns (address)\",\n]);\nconst MESSAGE_TRANSMITTER_ABI = parseAbi([\n \"function receiveMessage(bytes message, bytes attestation) returns (bool)\",\n \"function localDomain() view returns (uint32)\",\n \"function usedNonces(bytes32 nonce) view returns (uint256)\",\n]);\n\nconst EVM_PLACEHOLDER = \"0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045\";\nconst DEFAULT_QUOTE_TTL_MS = 60_000;\n/** Fallback gas limit: a depositForBurn runs ~110–150k, receiveMessage ~150–200k. */\nconst GAS_DEPOSIT = \"200000\";\nconst GAS_CLAIM = \"260000\";\n\nexport type CctpMode = \"auto\" | \"fast\" | \"standard\";\n\nexport interface CctpProviderConfig {\n enabled?: boolean;\n /** Circle attestation API base (default https://iris-api.circle.com). */\n apiUrl?: string;\n /** Fast when offered and within the allowance (default), or force one path. */\n mode?: CctpMode;\n /** Extra headroom on the published Fast fee, in percent of the fee (default 10). The excess is never charged. */\n feeBufferPct?: number;\n /**\n * JSON-RPC URLs per CAIP-2 chain. Optional, but with them the provider\n * verifies the contracts before the burn and detects the mint on the\n * destination (`usedNonces`). Without the destination chain's URL the status\n * reaches \"completed\" only through the id `claimSwap2` returns for a claim the\n * account saw succeed; a bare claim hash stays \"pending\" (hash kept).\n */\n rpcUrls?: Readonly<Record<string, string>>;\n /** Local lifetime of a quote (fees are stable; default 60 s). */\n quoteTtlMs?: number;\n /** Injectable for tests. */\n fetchImpl?: typeof fetch;\n}\n\ninterface FeeRow { finalityThreshold: number; minimumFee: number }\ninterface ApiMessage {\n message?: string;\n eventNonce?: string;\n attestation?: string | null;\n status?: string;\n delayReason?: string | null;\n cctpVersion?: number;\n decodedMessage?: {\n sourceDomain?: string; destinationDomain?: string; nonce?: string; mintRecipient?: string;\n decodedMessageBody?: {amount?: string; maxFee?: string; feeExecuted?: string; expirationBlock?: string; mintRecipient?: string; burnToken?: string};\n };\n}\n\nconst isHexData = (v: unknown): v is Hex => typeof v === \"string\" && /^0x(?:[0-9a-fA-F]{2})+$/.test(v);\nconst same = (a: string | undefined, b: string) => !!a && a.toLowerCase() === b.toLowerCase();\n\n/** `amount × bps` rounded up; `bps` may be fractional (Circle publishes 1.3). */\nfunction feeFor(amount: bigint, bps: number, bufferPct: number): bigint {\n const hundredths = BigInt(Math.round(bps * 100)); // 1.3 bps → 130\n const fee = (amount * hundredths + 999_999n) / 1_000_000n;\n if (fee === 0n) return 0n;\n return fee + (fee * BigInt(Math.round(bufferPct * 100)) + 9_999n) / 10_000n;\n}\n\n/**\n * The contracts a CCTP claim may call on `chain`: its MessageTransmitter (`receiveMessage`). Pass it\n * as `claimTargets` to a remote provider stub so the app, not the server, decides (round 3, M24).\n */\nexport function cctpClaimTargets(chain: string): readonly string[] {\n const d = Object.prototype.hasOwnProperty.call(CCTP_DOMAINS, chain) ? CCTP_DOMAINS[chain] : undefined;\n return d ? [d.messageTransmitter] : [];\n}\n\nexport function cctpProvider(config: CctpProviderConfig = {}): CrossChainProvider {\n config = Object.freeze({...config});\n const api = (config.apiUrl ?? CCTP_API).replace(/\\/+$/, \"\");\n if (!/^https?:\\/\\//.test(api)) throw new Error(\"cctp: apiUrl must use http or https\");\n const mode: CctpMode = config.mode ?? \"auto\";\n if (![\"auto\", \"fast\", \"standard\"].includes(mode)) throw new Error(\"cctp: mode must be auto | fast | standard\");\n const bufferPct = config.feeBufferPct ?? 10;\n if (!Number.isFinite(bufferPct) || bufferPct < 0 || bufferPct > 100) throw new Error(\"cctp: feeBufferPct must be between 0 and 100\");\n const quoteTtlMs = config.quoteTtlMs ?? DEFAULT_QUOTE_TTL_MS;\n if (!Number.isInteger(quoteTtlMs) || quoteTtlMs <= 0 || quoteTtlMs > 300_000) throw new Error(\"cctp: quoteTtlMs must be an integer between 1 and 300000\");\n const doFetch = config.fetchImpl ?? fetch;\n const rpcUrls = Object.freeze({...(config.rpcUrls ?? {})});\n\n const client = (caip2: string) => {\n const url = rpcUrls[caip2];\n return url ? createPublicClient({transport: http(url, {fetchOptions: {}, ...(config.fetchImpl ? {fetchFn: config.fetchImpl} : {})} as never), ccipRead: false}) : null;\n };\n\n async function getJson<T>(path: string, signal?: AbortSignal): Promise<T | null> {\n const res = await doFetch(`${api}${path}`, {headers: {accept: \"application/json\"}, signal: signal ?? timeoutSignal(12_000)});\n if (res.status === 404) return null;\n if (!res.ok) throw new Error(`cctp: ${path} → ${res.status}`);\n return (await res.json()) as T;\n }\n\n /** Circle's published fee per finality threshold, in bps of the burnt amount. */\n const feeRows = (src: CctpDomain, dst: CctpDomain, signal?: AbortSignal) =>\n getJson<FeeRow[]>(`/v2/burn/USDC/fees/${src.domain}/${dst.domain}`, signal);\n\n /** The native USDC of a domain, cross-checked against the asset catalog when it knows the chain. */\n function usdcOf(dom: CctpDomain): string | null {\n const known = ccAsset(dom.caip2, \"USDC\");\n if (known && (!known.contract || !same(known.contract, dom.usdc))) return null; // catalog has a USDC that is not Circle's → refuse\n return dom.usdc;\n }\n\n function parseIntent(intentId: string): {src: CctpDomain; dst: CctpDomain; threshold: number} | null {\n const [tag, s, dd, t] = intentId.split(\":\");\n if (tag !== \"cctp\") return null;\n const src = CCTP_BY_DOMAIN[Number(s)];\n const dst = CCTP_BY_DOMAIN[Number(dd)];\n const threshold = Number(t);\n if (!src || !dst || !(threshold === FINALITY_FAST || threshold === FINALITY_STANDARD)) return null;\n return {src, dst, threshold};\n }\n\n async function fetchMessage(src: CctpDomain, sourceTxHash: string): Promise<ApiMessage | null> {\n const out = await getJson<{messages?: ApiMessage[]}>(`/v2/messages/${src.domain}?transactionHash=${encodeURIComponent(sourceTxHash)}`);\n const m = out?.messages?.find((x) => x.cctpVersion === undefined || x.cctpVersion === 2);\n return m ?? null;\n }\n\n /** The nonce's state on the destination: null without an RPC there, \"unknown\" when the configured RPC fails to answer. */\n async function minted(dst: CctpDomain, nonce: Hex): Promise<boolean | null | \"unknown\"> {\n const c = client(dst.caip2);\n if (!c) return null;\n try {\n const used = await c.readContract({address: getAddress(dst.messageTransmitter), abi: MESSAGE_TRANSMITTER_ABI, functionName: \"usedNonces\", args: [nonce]});\n return used !== 0n;\n } catch {\n return \"unknown\";\n }\n }\n\n return {\n name: \"cctp\",\n claimTargets: cctpClaimTargets,\n describeActivity: describeCctpActivity,\n enabled: () => config.enabled ?? true,\n supportsChain: (chain: string) => cctpCfg.supportsChain(chain),\n supportsChainPair: (from: string, to: string) => cctpCfg.supports(from, to),\n supportsRoute(from: Asset, to: Asset): boolean {\n const src = CCTP_DOMAINS[from.chain];\n const dst = CCTP_DOMAINS[to.chain];\n if (!src || !dst || from.chain === to.chain) return false;\n if (from.token.toUpperCase() !== \"USDC\") return false;\n // Destination is given as an address (zero = native): only the native USDC of the destination domain.\n return same(to.token, dst.usdc) || to.token.toUpperCase() === \"USDC\";\n },\n\n async getQuote(params: QuoteParams, signal?: AbortSignal): Promise<Quote | null> {\n if (params.flex) return null; // the amount is baked into the calldata\n const src = CCTP_DOMAINS[params.sourceChain];\n const dst = CCTP_DOMAINS[params.destChain];\n if (!src || !dst || src === dst) return null;\n if (params.sourceToken.toUpperCase() !== \"USDC\") return null;\n if (!(same(params.destToken, dst.usdc) || params.destToken.toUpperCase() === \"USDC\")) return null;\n const usdc = usdcOf(src);\n if (!usdc) { params.onRefusal?.(\"catalog USDC on the source chain is not Circle's native USDC\"); return null; }\n if (!/^\\d+$/.test(params.amountIn)) return null;\n const amount = BigInt(params.amountIn);\n if (amount <= 0n) return null;\n // The placeholder prices a dry quote; a live one without a recipient would mint to it (round 3, H8).\n const recipient = params.destAddress || (params.dry !== false ? EVM_PLACEHOLDER : \"\");\n if (!recipient) { params.onRefusal?.(\"a live quote needs a recipient\"); return null; }\n if (!isAddress(recipient)) { params.onRefusal?.(\"destination must be an EVM address\"); return null; }\n\n try {\n const fees = await feeRows(src, dst, signal);\n if (!fees || !Array.isArray(fees) || fees.length === 0) { params.onRefusal?.(\"Circle publishes no fee for this pair\"); return null; }\n const fast = fees.find((f) => f.finalityThreshold === FINALITY_FAST);\n const standard = fees.find((f) => f.finalityThreshold === FINALITY_STANDARD);\n let threshold: number;\n let bps: number;\n if (mode === \"standard\") {\n if (!standard) { params.onRefusal?.(\"Standard Transfer is not offered for this pair\"); return null; }\n threshold = FINALITY_STANDARD; bps = standard.minimumFee;\n } else {\n let fastOk = !!fast;\n if (fastOk) {\n const allowance = await getJson<{allowance?: number}>(\"/v2/fastBurn/USDC/allowance\", signal).catch(() => null);\n // The allowance is in whole USDC; refuse Fast when it cannot cover the burn.\n if (typeof allowance?.allowance === \"number\" && allowance.allowance * 1e6 < bigintToNumber(amount)) fastOk = false;\n }\n if (fastOk) { threshold = FINALITY_FAST; bps = fast!.minimumFee; }\n else if (mode === \"fast\") { params.onRefusal?.(fast ? \"Fast Transfer allowance is exhausted\" : \"Fast Transfer is not offered for this pair\"); return null; }\n else if (standard) { threshold = FINALITY_STANDARD; bps = standard.minimumFee; }\n else { params.onRefusal?.(\"neither Fast nor Standard is offered\"); return null; }\n }\n if (!Number.isFinite(bps) || bps < 0) return null;\n const maxFee = feeFor(amount, bps, bufferPct);\n if (maxFee >= amount) { params.onRefusal?.(\"amount is below the Fast Transfer fee\"); return null; }\n const out = amount - maxFee;\n if (params.minAmountOut !== undefined && out < BigInt(params.minAmountOut)) return null;\n\n const data = encodeFunctionData({\n abi: TOKEN_MESSENGER_ABI,\n functionName: \"depositForBurn\",\n args: [amount, dst.domain, pad(getAddress(recipient), {size: 32}), getAddress(usdc), zeroHash, maxFee, threshold],\n });\n const eta = threshold === FINALITY_FAST ? (src.domain === 0 ? 180 : 45) : (src.domain === 0 ? 1200 : 1000);\n return {\n provider: \"cctp\",\n intentId: `cctp:${src.domain}:${dst.domain}:${threshold}`,\n depositAddress: \"\",\n depositMemo: null,\n txRequest: {to: src.tokenMessenger, data, value: \"0\", chainId: src.chainId, gasLimit: GAS_DEPOSIT, approvalAddress: src.tokenMessenger},\n sourceAmount: amount.toString(),\n destAmount: out.toString(),\n minDestAmount: out.toString(),\n feeUsd: bigintToNumber(maxFee) / 1e6,\n fees: maxFee > 0n ? [{type: \"protocol\", amount: maxFee.toString(), token: usdc, included: true, description: `Circle Fast Transfer fee (${bps} bps + ${bufferPct}% buffer, unused part is not charged)`}] : [],\n etaSeconds: eta,\n reliability: 0.99,\n validUntilMs: Date.now() + quoteTtlMs,\n providerData: {\n sourceDomain: String(src.domain), destinationDomain: String(dst.domain), finalityThreshold: String(threshold),\n maxFee: maxFee.toString(), mintRecipient: getAddress(recipient), claimChain: dst.caip2, claimRequired: \"1\",\n },\n };\n } catch {\n return null;\n }\n },\n\n async buildDeposit(quote: Quote): Promise<UnsignedTx> {\n const tx = quote.txRequest;\n const parsed = parseIntent(quote.intentId);\n if (!tx || !parsed) throw new Error(\"swap2: CCTP quote has no transaction request\");\n return {\n chain: parsed.src.caip2,\n to: tx.to ?? \"\",\n value: tx.value ?? \"0\",\n ...(tx.data ? {data: tx.data} : {}),\n ...(tx.chainId !== undefined ? {chainId: tx.chainId} : {}),\n ...(tx.gasLimit ? {gasLimit: tx.gasLimit} : {}),\n ...(tx.approvalAddress ? {approvalAddress: tx.approvalAddress} : {}),\n };\n },\n\n /**\n * Fast: Circle's CURRENT fee (same source and rounding as the quote, without\n * the buffer) still fits `maxFee` — Iris would otherwise hold the burn\n * until it times out to Standard. With a source RPC: the target really is\n * CCTP for this domain.\n */\n async preflightDeposit(quote: Quote, tx: UnsignedTx): Promise<void> {\n const parsed = parseIntent(quote.intentId);\n if (!parsed) throw new Error(\"cctp: malformed intent id\");\n if (!same(tx.to, parsed.src.tokenMessenger)) throw new Error(\"cctp: deposit target is not the TokenMessengerV2 of the source domain\");\n if (parsed.threshold === FINALITY_FAST) {\n const fast = (await feeRows(parsed.src, parsed.dst))?.find((f) => f.finalityThreshold === FINALITY_FAST);\n if (!fast || !Number.isFinite(fast.minimumFee) || fast.minimumFee < 0) throw new Error(\"cctp: Circle no longer publishes a Fast Transfer fee for this pair — re-quote\");\n const minFee = feeFor(BigInt(quote.sourceAmount), fast.minimumFee, 0);\n const maxFee = BigInt(quote.providerData?.maxFee ?? \"0\");\n if (minFee > maxFee) throw new Error(`cctp: Circle's Fast Transfer fee ${minFee} (${fast.minimumFee} bps) exceeds the quoted maxFee ${maxFee} — re-quote`);\n }\n const c = client(parsed.src.caip2);\n if (!c) return;\n const transmitter = await c.readContract({address: getAddress(parsed.src.tokenMessenger), abi: TOKEN_MESSENGER_ABI, functionName: \"localMessageTransmitter\"});\n if (!same(transmitter, parsed.src.messageTransmitter)) throw new Error(\"cctp: TokenMessengerV2 does not point at the expected MessageTransmitterV2\");\n const domain = await c.readContract({address: getAddress(parsed.src.messageTransmitter), abi: MESSAGE_TRANSMITTER_ABI, functionName: \"localDomain\"});\n if (Number(domain) !== parsed.src.domain) throw new Error(`cctp: MessageTransmitterV2 reports domain ${domain}, expected ${parsed.src.domain}`);\n },\n\n async trackIntent(ref: IntentRef): Promise<IntentStatus> {\n const parsed = parseIntent(ref.intentId);\n if (!parsed) return {state: \"failed\"};\n const claim = {chain: parsed.dst.caip2, ready: false};\n if (!ref.sourceTxHash) return {state: \"pending\", claim};\n try {\n const m = await fetchMessage(parsed.src, ref.sourceTxHash);\n if (!m) return {state: \"pending\", depositReceived: false, claim};\n const nonce = m.decodedMessage?.nonce;\n if (m.status === \"complete\" && isHexData(m.attestation) && isHexData(m.message)) {\n // A message without a readable nonce cannot be checked on the destination even with an RPC there.\n const done = isHexData(nonce) && nonce.length === 66 ? await minted(parsed.dst, nonce) : client(parsed.dst.caip2) ? \"unknown\" : null;\n if (done === true) return {state: \"completed\", claim: {...claim, ready: false}, ...(ref.destTxHash ? {destTxHash: ref.destTxHash} : {})};\n if (ref.destTxHash) {\n // A claim the sending account saw included and succeed is the mint: receiveMessage reverts once the\n // nonce is used, so a successful one minted this message. Without a destination read that is completed;\n // a destination read that does not show it yet is a node behind the claim, not a claim to send again.\n if (ref.destTxConfirmed === true) {\n return done === false\n ? {state: \"pending\", depositReceived: true, destTxHash: ref.destTxHash, claim: {...claim, ready: false}}\n : {state: \"completed\", destTxHash: ref.destTxHash, claim: {...claim, ready: false}};\n }\n // A claim was sent, but nothing here can read whether it minted (no destination RPC, or one that did\n // not answer): the hash is kept and the swap stays pending — a hash alone is not a mint.\n if (done !== false) return {state: \"pending\", depositReceived: true, destTxHash: ref.destTxHash, claim: {...claim, ready: false}};\n }\n return {state: \"action-required\", depositReceived: true, claim: {...claim, ready: true}};\n }\n return {state: \"pending\", depositReceived: true, claim};\n } catch {\n return {state: \"pending\", claim};\n }\n },\n\n /** `receiveMessage(message, attestation)` on the destination once Circle attested; null while pending. */\n async buildClaim(ref: IntentRef): Promise<UnsignedTx | null> {\n const parsed = parseIntent(ref.intentId);\n if (!parsed || !ref.sourceTxHash) return null;\n const m = await fetchMessage(parsed.src, ref.sourceTxHash);\n if (!m || m.status !== \"complete\" || !isHexData(m.attestation) || !isHexData(m.message)) return null;\n // Bind the attested message to the route it claims to complete.\n if (m.decodedMessage?.destinationDomain !== undefined && Number(m.decodedMessage.destinationDomain) !== parsed.dst.domain) {\n throw new Error(\"cctp: attested message is for another destination domain\");\n }\n if (m.decodedMessage?.sourceDomain !== undefined && Number(m.decodedMessage.sourceDomain) !== parsed.src.domain) {\n throw new Error(\"cctp: attested message is for another source domain\");\n }\n // Fast messages expire at `expirationBlock` on the destination; an expired\n // one needs Circle's re-attestation before it can be received. The\n // transmitter compares it with `block.number`, which on Arbitrum-stack\n // chains is the L1 (Ethereum) height, not the L2 height eth_blockNumber\n // returns — the RPC block carries it as `l1BlockNumber` (live\n // 2026-10-16: a Base→Arbitrum claim was held as \"expired\" by L2 height).\n const exp = m.decodedMessage?.decodedMessageBody?.expirationBlock;\n const c = client(parsed.dst.caip2);\n if (c && exp && /^\\d+$/.test(exp) && BigInt(exp) > 0n) {\n const head = await c.request({method: \"eth_getBlockByNumber\", params: [\"latest\", false]})\n .then((b) => {\n const block = b as {number?: string; l1BlockNumber?: string} | null;\n const raw = block?.l1BlockNumber ?? block?.number;\n return raw ? BigInt(raw) : null;\n })\n .catch(() => null);\n if (head !== null && head >= BigInt(exp)) {\n const nonce = m.decodedMessage?.nonce ?? m.eventNonce;\n if (nonce) await doFetch(`${api}/v2/reattest/${nonce}`, {method: \"POST\", signal: timeoutSignal(12_000)}).catch(() => undefined);\n return null;\n }\n }\n return {\n chain: parsed.dst.caip2,\n to: parsed.dst.messageTransmitter,\n value: \"0\",\n data: encodeFunctionData({abi: MESSAGE_TRANSMITTER_ABI, functionName: \"receiveMessage\", args: [m.message, m.attestation]}),\n chainId: parsed.dst.chainId,\n gasLimit: GAS_CLAIM,\n };\n },\n };\n}\n\n/**\n * A remote CCTP quote's burn, decoded on the device against the app's own request (scan 2026-10-30, F3): exactly\n * `depositForBurn` on the source TokenMessengerV2 with no value, approving it; the input amount; the destination\n * chain's domain; the recipient as `mintRecipient`; the source domain's native USDC; no destination caller; a Fast\n * or Standard threshold; and a `maxFee` that leaves at least the quoted minimum and the caller's floor. The reason\n * it fails, or null. The engine then requires the build to repeat this quote's call.\n */\nexport function cctpVerifyQuote(params: QuoteParams, quote: Quote): string | null {\n const src = Object.prototype.hasOwnProperty.call(CCTP_DOMAINS, params.sourceChain) ? CCTP_DOMAINS[params.sourceChain] : undefined;\n const dst = Object.prototype.hasOwnProperty.call(CCTP_DOMAINS, params.destChain) ? CCTP_DOMAINS[params.destChain] : undefined;\n if (!src || !dst || src === dst) return \"not a CCTP route between two domains\";\n if (params.sourceToken.toUpperCase() !== \"USDC\" || !(same(params.destToken, dst.usdc) || params.destToken.toUpperCase() === \"USDC\")) return \"not USDC to USDC\";\n const tx = quote.txRequest;\n if (!tx?.data || !tx.to || tx.serializedTx !== undefined) return \"the quote carries no TokenMessenger call\";\n if (!same(tx.to, src.tokenMessenger)) return `the call targets ${tx.to}, not the TokenMessengerV2`;\n if (BigInt(tx.value ?? \"0\") !== 0n) return \"a burn attaches no value\";\n if (!tx.approvalAddress || !same(tx.approvalAddress, src.tokenMessenger)) return \"the burn approves another spender than the TokenMessengerV2\";\n if (tx.chainId !== undefined && tx.chainId !== src.chainId) return `the call is for chain ${tx.chainId}, not ${src.chainId}`;\n let args: readonly unknown[];\n try {\n const d = decodeFunctionData({abi: TOKEN_MESSENGER_ABI, data: tx.data as Hex});\n if (d.functionName !== \"depositForBurn\") return `${d.functionName} is not depositForBurn`;\n args = d.args;\n } catch {\n return \"the call is not depositForBurn\";\n }\n const [amount, domain, mintRecipient, burnToken, caller, maxFee, threshold] = args as [bigint, number, Hex, string, Hex, bigint, number];\n let amountIn: bigint, floor: bigint;\n try {\n amountIn = BigInt(params.amountIn);\n floor = BigInt(quote.minDestAmount);\n if (params.minAmountOut !== undefined && BigInt(params.minAmountOut) > floor) floor = BigInt(params.minAmountOut);\n } catch {\n return \"the request does not name amounts\";\n }\n if (amount !== amountIn || BigInt(quote.sourceAmount) !== amountIn) return `the burn moves ${amount}, not the ${amountIn} input`;\n if (domain !== dst.domain) return `the burn mints on domain ${domain}, not ${dst.name} (${dst.domain})`;\n // A dry quote without a recipient prices the placeholder the provider uses; it is never built (the engine re-quotes live).\n if (params.destAddress || params.dry === false) {\n if (!isAddress(params.destAddress)) return \"the recipient is not an EVM address\";\n if (mintRecipient.toLowerCase() !== pad(getAddress(params.destAddress), {size: 32}).toLowerCase()) return `the burn mints to ${mintRecipient}, not the recipient`;\n }\n if (!same(burnToken, src.usdc)) return `the burn spends ${burnToken}, not the source domain's USDC`;\n if (caller !== zeroHash) return \"the burn names a destination caller\";\n if (threshold !== FINALITY_FAST && threshold !== FINALITY_STANDARD) return `finality threshold ${threshold} is neither Fast nor Standard`;\n if (maxFee >= amount || amount - maxFee < floor) return `the burn's maxFee ${maxFee} leaves less than the ${floor} minimum`;\n // The server appends its intent token (`<id>~<tag>`); the id before it is what the server's provider tracks and claims.\n if ((/^([\\s\\S]+)~[0-9a-f]{32}$/.exec(quote.intentId)?.[1] ?? quote.intentId) !== `cctp:${src.domain}:${dst.domain}:${threshold}`) return \"the intent id does not name this burn\";\n if (quote.providerData?.maxFee !== undefined && quote.providerData.maxFee !== maxFee.toString()) return \"the quoted maxFee is not the burn's\";\n return null;\n}\n\n/**\n * The TokenMessenger a CCTP burn calls and approves, and the MessageTransmitter its claim calls, per\n * chain, and {@link cctpVerifyQuote} — the app's pins for `remoteProvider({name: \"cctp\", baseUrl, ...cctpPins})`\n * (scan 2026-10-27 modules, F8/F16; claims since round 3, M24; the burn's arguments since scan 2026-10-30, F3).\n */\nexport const cctpPins: RemotePins & {claimTargets(chain: string): readonly string[]} = Object.freeze({\n callTargets: (chain: string): readonly string[] => cctpMessengerFor(chain),\n spenders: (chain: string): readonly string[] => cctpMessengerFor(chain),\n claimTargets: cctpClaimTargets,\n verifyQuote: cctpVerifyQuote,\n});\nfunction cctpMessengerFor(chain: string): readonly string[] {\n const d = Object.prototype.hasOwnProperty.call(CCTP_DOMAINS, chain) ? CCTP_DOMAINS[chain] : undefined;\n return d ? [d.tokenMessenger] : [];\n}\n","/**\n * Activity recognition for Circle CCTP V2 on every domain in `config.ts`:\n * `depositForBurn` on TokenMessengerV2 is our source leg (\"Bridged USDC\"), and\n * `receiveMessage` on MessageTransmitterV2 is the claim that mints on the\n * destination (\"Received USDC via CCTP\") — whoever paid the gas, the USDC lands\n * on the `mintRecipient`. Both are `bridge`; the other leg's hash is only known\n * through the kit's journal / Circle's attestation API, so `related` stays empty.\n */\nimport type {ActivityItem, ChainTx, DescribeActivityContext} from \"@anywalletkit/core\";\nimport {chainLabel, describeSwapLike, matchesCall} from \"@anywalletkit/protocol-swap2-core/activity\";\nimport {CCTP_DOMAINS} from \"./config.js\";\n\nexport const CCTP_MODULE = \"@anywalletkit/protocol-swap2-cctp\";\n\n/** depositForBurn(uint256,uint32,bytes32,address,bytes32,uint256,uint32) — TokenMessengerV2 */\nexport const CCTP_DEPOSIT_FOR_BURN = \"0x8e0250ee\";\n/** receiveMessage(bytes,bytes) — MessageTransmitterV2 */\nexport const CCTP_RECEIVE_MESSAGE = \"0x57ecfd28\";\n\nexport function describeCctpActivity(tx: ChainTx, ctx: DescribeActivityContext): ActivityItem | null {\n const domain = CCTP_DOMAINS[tx.chain];\n if (!domain) return null;\n const subtitle = `CCTP · ${chainLabel(tx.chain)}`;\n if (matchesCall(tx, [domain.tokenMessenger], [CCTP_DEPOSIT_FOR_BURN])) {\n return describeSwapLike(tx, ctx, {protocol: CCTP_MODULE, subtitle, kind: \"bridge\", title: \"Bridged USDC\"});\n }\n if (matchesCall(tx, [domain.messageTransmitter], [CCTP_RECEIVE_MESSAGE])) {\n return describeSwapLike(tx, ctx, {protocol: CCTP_MODULE, subtitle, kind: \"bridge\", title: \"Received USDC via CCTP\"});\n }\n return null;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oBAAkC;;;ACMlC,kBAA4B;AAYrB,IAAM,qBAAqB;AAC3B,IAAM,yBAAyB;AAEtC,IAAM,IAAI,CAAC,SAAiB,QAAgB,MAAc,UAA8B;AAAA,EACtF,OAAO,UAAU,OAAO;AAAA,EAAI;AAAA,EAAS;AAAA,EAAQ;AAAA,EAAM;AAAA,EAAM,gBAAgB;AAAA,EAAoB,oBAAoB;AACnH;AAGO,IAAM,eAAqD,OAAO,OAAO,OAAO,YAAY;AAAA,EACjG,EAAE,GAAG,GAAG,YAAY,4CAA4C;AAAA,EAChE,EAAE,OAAO,GAAG,aAAa,4CAA4C;AAAA,EACrE,EAAE,IAAI,GAAG,cAAc,4CAA4C;AAAA,EACnE,EAAE,OAAO,GAAG,YAAY,4CAA4C;AAAA,EACpE,EAAE,MAAM,GAAG,QAAQ,4CAA4C;AAAA,EAC/D,EAAE,KAAK,GAAG,eAAe,4CAA4C;AAAA,EACrE,EAAE,KAAK,IAAI,YAAY,4CAA4C;AAAA,EACnE,EAAE,OAAO,IAAI,SAAS,4CAA4C;AAAA,EAClE,EAAE,KAAK,IAAI,SAAS,4CAA4C;AAAA,EAChE,EAAE,KAAK,IAAI,eAAe,4CAA4C;AAAA,EACtE,EAAE,KAAK,IAAI,SAAS,4CAA4C;AAAA,EAChE,EAAE,MAAM,IAAI,OAAO,4CAA4C;AAAA,EAC/D,EAAE,KAAK,IAAI,YAAY,4CAA4C;AAAA,EACnE,EAAE,OAAO,IAAI,OAAO,4CAA4C;AAAA,EAChE,EAAE,OAAO,IAAI,SAAS,4CAA4C;AAAA,EAClE,EAAE,MAAM,IAAI,UAAU,4CAA4C;AAAA,EAClE,EAAE,KAAK,IAAI,WAAW,4CAA4C;AAAA;AAAA;AAAA;AAAA;AAAA,EAKlE,EAAE,MAAM,IAAI,OAAO,4CAA4C;AAAA,EAC/D,EAAE,MAAM,IAAI,SAAS,4CAA4C;AACnE,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;AAGpB,IAAM,iBAAuD,OAAO;AAAA,EACzE,OAAO,YAAY,OAAO,OAAO,YAAY,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC;AAC1E;AAKO,IAAM,WAAW;AAGjB,IAAM,gBAAgB;AACtB,IAAM,oBAAoB;AAE1B,IAAM,OAAO;AAAA,EAClB,cAAc,OAAwB;AACpC,eAAO,mBAAM,KAAK,KAAK,CAAC,CAAC,aAAa,cAAU,oBAAO,KAAK,CAAC,EAAE;AAAA,EACjE;AAAA,EACA,SAAS,MAAc,IAAqB;AAC1C,WAAO,SAAS,MAAM,KAAK,cAAc,IAAI,KAAK,KAAK,cAAc,EAAE;AAAA,EACzE;AACF;;;ACxEA,kBAAyI;;;ACQzI,sBAAwD;AAGjD,IAAM,cAAc;AAGpB,IAAM,wBAAwB;AAE9B,IAAM,uBAAuB;AAE7B,SAAS,qBAAqB,IAAa,KAAmD;AACnG,QAAM,SAAS,aAAa,GAAG,KAAK;AACpC,MAAI,CAAC,OAAQ,QAAO;AACpB,QAAM,WAAW,iBAAU,4BAAW,GAAG,KAAK,CAAC;AAC/C,UAAI,6BAAY,IAAI,CAAC,OAAO,cAAc,GAAG,CAAC,qBAAqB,CAAC,GAAG;AACrE,eAAO,kCAAiB,IAAI,KAAK,EAAC,UAAU,aAAa,UAAU,MAAM,UAAU,OAAO,eAAc,CAAC;AAAA,EAC3G;AACA,UAAI,6BAAY,IAAI,CAAC,OAAO,kBAAkB,GAAG,CAAC,oBAAoB,CAAC,GAAG;AACxE,eAAO,kCAAiB,IAAI,KAAK,EAAC,UAAU,aAAa,UAAU,MAAM,UAAU,OAAO,yBAAwB,CAAC;AAAA,EACrH;AACA,SAAO;AACT;;;AD3BA,0BAAsB;AACtB,IAAAA,eAA4B;AAG5B,kBAA6B;AA0B7B,IAAM,0BAAsB,sBAAS;AAAA,EACnC;AAAA,EACA;AACF,CAAC;AACD,IAAM,8BAA0B,sBAAS;AAAA,EACvC;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAED,IAAM,kBAAkB;AACxB,IAAM,uBAAuB;AAE7B,IAAM,cAAc;AACpB,IAAM,YAAY;AAwClB,IAAM,YAAY,CAAC,MAAyB,OAAO,MAAM,YAAY,0BAA0B,KAAK,CAAC;AACrG,IAAM,OAAO,CAAC,GAAuB,MAAc,CAAC,CAAC,KAAK,EAAE,YAAY,MAAM,EAAE,YAAY;AAG5F,SAAS,OAAO,QAAgB,KAAa,WAA2B;AACtE,QAAM,aAAa,OAAO,KAAK,MAAM,MAAM,GAAG,CAAC;AAC/C,QAAM,OAAO,SAAS,aAAa,WAAY;AAC/C,MAAI,QAAQ,GAAI,QAAO;AACvB,SAAO,OAAO,MAAM,OAAO,KAAK,MAAM,YAAY,GAAG,CAAC,IAAI,SAAU;AACtE;AAMO,SAAS,iBAAiB,OAAkC;AACjE,QAAMC,KAAI,OAAO,UAAU,eAAe,KAAK,cAAc,KAAK,IAAI,aAAa,KAAK,IAAI;AAC5F,SAAOA,KAAI,CAACA,GAAE,kBAAkB,IAAI,CAAC;AACvC;AAEO,SAAS,aAAa,SAA6B,CAAC,GAAuB;AAChF,WAAS,OAAO,OAAO,EAAC,GAAG,OAAM,CAAC;AAClC,QAAM,OAAO,OAAO,UAAU,UAAU,QAAQ,QAAQ,EAAE;AAC1D,MAAI,CAAC,eAAe,KAAK,GAAG,EAAG,OAAM,IAAI,MAAM,qCAAqC;AACpF,QAAM,OAAiB,OAAO,QAAQ;AACtC,MAAI,CAAC,CAAC,QAAQ,QAAQ,UAAU,EAAE,SAAS,IAAI,EAAG,OAAM,IAAI,MAAM,2CAA2C;AAC7G,QAAM,YAAY,OAAO,gBAAgB;AACzC,MAAI,CAAC,OAAO,SAAS,SAAS,KAAK,YAAY,KAAK,YAAY,IAAK,OAAM,IAAI,MAAM,8CAA8C;AACnI,QAAM,aAAa,OAAO,cAAc;AACxC,MAAI,CAAC,OAAO,UAAU,UAAU,KAAK,cAAc,KAAK,aAAa,IAAS,OAAM,IAAI,MAAM,0DAA0D;AACxJ,QAAM,UAAU,OAAO,aAAa;AACpC,QAAM,UAAU,OAAO,OAAO,EAAC,GAAI,OAAO,WAAW,CAAC,EAAE,CAAC;AAEzD,QAAM,SAAS,CAAC,UAAkB;AAChC,UAAM,MAAM,QAAQ,KAAK;AACzB,WAAO,UAAM,gCAAmB,EAAC,eAAW,kBAAK,KAAK,EAAC,cAAc,CAAC,GAAG,GAAI,OAAO,YAAY,EAAC,SAAS,OAAO,UAAS,IAAI,CAAC,EAAE,CAAU,GAAG,UAAU,MAAK,CAAC,IAAI;AAAA,EACpK;AAEA,iBAAe,QAAW,MAAc,QAAyC;AAC/E,UAAM,MAAM,MAAM,QAAQ,GAAG,GAAG,GAAG,IAAI,IAAI,EAAC,SAAS,EAAC,QAAQ,mBAAkB,GAAG,QAAQ,cAAU,4BAAc,IAAM,EAAC,CAAC;AAC3H,QAAI,IAAI,WAAW,IAAK,QAAO;AAC/B,QAAI,CAAC,IAAI,GAAI,OAAM,IAAI,MAAM,SAAS,IAAI,WAAM,IAAI,MAAM,EAAE;AAC5D,WAAQ,MAAM,IAAI,KAAK;AAAA,EACzB;AAGA,QAAM,UAAU,CAAC,KAAiB,KAAiB,WACjD,QAAkB,sBAAsB,IAAI,MAAM,IAAI,IAAI,MAAM,IAAI,MAAM;AAG5E,WAAS,OAAO,KAAgC;AAC9C,UAAM,YAAQ,6BAAQ,IAAI,OAAO,MAAM;AACvC,QAAI,UAAU,CAAC,MAAM,YAAY,CAAC,KAAK,MAAM,UAAU,IAAI,IAAI,GAAI,QAAO;AAC1E,WAAO,IAAI;AAAA,EACb;AAEA,WAAS,YAAY,UAAgF;AACnG,UAAM,CAAC,KAAK,GAAG,IAAI,CAAC,IAAI,SAAS,MAAM,GAAG;AAC1C,QAAI,QAAQ,OAAQ,QAAO;AAC3B,UAAM,MAAM,eAAe,OAAO,CAAC,CAAC;AACpC,UAAM,MAAM,eAAe,OAAO,EAAE,CAAC;AACrC,UAAM,YAAY,OAAO,CAAC;AAC1B,QAAI,CAAC,OAAO,CAAC,OAAO,EAAE,cAAc,iBAAiB,cAAc,mBAAoB,QAAO;AAC9F,WAAO,EAAC,KAAK,KAAK,UAAS;AAAA,EAC7B;AAEA,iBAAe,aAAa,KAAiB,cAAkD;AAC7F,UAAM,MAAM,MAAM,QAAmC,gBAAgB,IAAI,MAAM,oBAAoB,mBAAmB,YAAY,CAAC,EAAE;AACrI,UAAM,IAAI,KAAK,UAAU,KAAK,CAAC,MAAM,EAAE,gBAAgB,UAAa,EAAE,gBAAgB,CAAC;AACvF,WAAO,KAAK;AAAA,EACd;AAGA,iBAAe,OAAO,KAAiB,OAAiD;AACtF,UAAM,IAAI,OAAO,IAAI,KAAK;AAC1B,QAAI,CAAC,EAAG,QAAO;AACf,QAAI;AACF,YAAM,OAAO,MAAM,EAAE,aAAa,EAAC,aAAS,wBAAW,IAAI,kBAAkB,GAAG,KAAK,yBAAyB,cAAc,cAAc,MAAM,CAAC,KAAK,EAAC,CAAC;AACxJ,aAAO,SAAS;AAAA,IAClB,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAEA,SAAO;AAAA,IACL,MAAM;AAAA,IACN,cAAc;AAAA,IACd,kBAAkB;AAAA,IAClB,SAAS,MAAM,OAAO,WAAW;AAAA,IACjC,eAAe,CAAC,UAAkB,KAAQ,cAAc,KAAK;AAAA,IAC7D,mBAAmB,CAAC,MAAc,OAAe,KAAQ,SAAS,MAAM,EAAE;AAAA,IAC1E,cAAc,MAAa,IAAoB;AAC7C,YAAM,MAAM,aAAa,KAAK,KAAK;AACnC,YAAM,MAAM,aAAa,GAAG,KAAK;AACjC,UAAI,CAAC,OAAO,CAAC,OAAO,KAAK,UAAU,GAAG,MAAO,QAAO;AACpD,UAAI,KAAK,MAAM,YAAY,MAAM,OAAQ,QAAO;AAEhD,aAAO,KAAK,GAAG,OAAO,IAAI,IAAI,KAAK,GAAG,MAAM,YAAY,MAAM;AAAA,IAChE;AAAA,IAEA,MAAM,SAAS,QAAqB,QAA6C;AAC/E,UAAI,OAAO,KAAM,QAAO;AACxB,YAAM,MAAM,aAAa,OAAO,WAAW;AAC3C,YAAM,MAAM,aAAa,OAAO,SAAS;AACzC,UAAI,CAAC,OAAO,CAAC,OAAO,QAAQ,IAAK,QAAO;AACxC,UAAI,OAAO,YAAY,YAAY,MAAM,OAAQ,QAAO;AACxD,UAAI,EAAE,KAAK,OAAO,WAAW,IAAI,IAAI,KAAK,OAAO,UAAU,YAAY,MAAM,QAAS,QAAO;AAC7F,YAAM,OAAO,OAAO,GAAG;AACvB,UAAI,CAAC,MAAM;AAAE,eAAO,YAAY,8DAA8D;AAAG,eAAO;AAAA,MAAM;AAC9G,UAAI,CAAC,QAAQ,KAAK,OAAO,QAAQ,EAAG,QAAO;AAC3C,YAAM,SAAS,OAAO,OAAO,QAAQ;AACrC,UAAI,UAAU,GAAI,QAAO;AAEzB,YAAM,YAAY,OAAO,gBAAgB,OAAO,QAAQ,QAAQ,kBAAkB;AAClF,UAAI,CAAC,WAAW;AAAE,eAAO,YAAY,gCAAgC;AAAG,eAAO;AAAA,MAAM;AACrF,UAAI,KAAC,uBAAU,SAAS,GAAG;AAAE,eAAO,YAAY,oCAAoC;AAAG,eAAO;AAAA,MAAM;AAEpG,UAAI;AACF,cAAM,OAAO,MAAM,QAAQ,KAAK,KAAK,MAAM;AAC3C,YAAI,CAAC,QAAQ,CAAC,MAAM,QAAQ,IAAI,KAAK,KAAK,WAAW,GAAG;AAAE,iBAAO,YAAY,uCAAuC;AAAG,iBAAO;AAAA,QAAM;AACpI,cAAM,OAAO,KAAK,KAAK,CAAC,MAAM,EAAE,sBAAsB,aAAa;AACnE,cAAM,WAAW,KAAK,KAAK,CAAC,MAAM,EAAE,sBAAsB,iBAAiB;AAC3E,YAAI;AACJ,YAAI;AACJ,YAAI,SAAS,YAAY;AACvB,cAAI,CAAC,UAAU;AAAE,mBAAO,YAAY,gDAAgD;AAAG,mBAAO;AAAA,UAAM;AACpG,sBAAY;AAAmB,gBAAM,SAAS;AAAA,QAChD,OAAO;AACL,cAAI,SAAS,CAAC,CAAC;AACf,cAAI,QAAQ;AACV,kBAAM,YAAY,MAAM,QAA8B,+BAA+B,MAAM,EAAE,MAAM,MAAM,IAAI;AAE7G,gBAAI,OAAO,WAAW,cAAc,YAAY,UAAU,YAAY,UAAM,4BAAe,MAAM,EAAG,UAAS;AAAA,UAC/G;AACA,cAAI,QAAQ;AAAE,wBAAY;AAAe,kBAAM,KAAM;AAAA,UAAY,WACxD,SAAS,QAAQ;AAAE,mBAAO,YAAY,OAAO,yCAAyC,4CAA4C;AAAG,mBAAO;AAAA,UAAM,WAClJ,UAAU;AAAE,wBAAY;AAAmB,kBAAM,SAAS;AAAA,UAAY,OAC1E;AAAE,mBAAO,YAAY,sCAAsC;AAAG,mBAAO;AAAA,UAAM;AAAA,QAClF;AACA,YAAI,CAAC,OAAO,SAAS,GAAG,KAAK,MAAM,EAAG,QAAO;AAC7C,cAAM,SAAS,OAAO,QAAQ,KAAK,SAAS;AAC5C,YAAI,UAAU,QAAQ;AAAE,iBAAO,YAAY,uCAAuC;AAAG,iBAAO;AAAA,QAAM;AAClG,cAAM,MAAM,SAAS;AACrB,YAAI,OAAO,iBAAiB,UAAa,MAAM,OAAO,OAAO,YAAY,EAAG,QAAO;AAEnF,cAAM,WAAO,gCAAmB;AAAA,UAC9B,KAAK;AAAA,UACL,cAAc;AAAA,UACd,MAAM,CAAC,QAAQ,IAAI,YAAQ,qBAAI,wBAAW,SAAS,GAAG,EAAC,MAAM,GAAE,CAAC,OAAG,wBAAW,IAAI,GAAG,sBAAU,QAAQ,SAAS;AAAA,QAClH,CAAC;AACD,cAAM,MAAM,cAAc,gBAAiB,IAAI,WAAW,IAAI,MAAM,KAAO,IAAI,WAAW,IAAI,OAAO;AACrG,eAAO;AAAA,UACL,UAAU;AAAA,UACV,UAAU,QAAQ,IAAI,MAAM,IAAI,IAAI,MAAM,IAAI,SAAS;AAAA,UACvD,gBAAgB;AAAA,UAChB,aAAa;AAAA,UACb,WAAW,EAAC,IAAI,IAAI,gBAAgB,MAAM,OAAO,KAAK,SAAS,IAAI,SAAS,UAAU,aAAa,iBAAiB,IAAI,eAAc;AAAA,UACtI,cAAc,OAAO,SAAS;AAAA,UAC9B,YAAY,IAAI,SAAS;AAAA,UACzB,eAAe,IAAI,SAAS;AAAA,UAC5B,YAAQ,4BAAe,MAAM,IAAI;AAAA,UACjC,MAAM,SAAS,KAAK,CAAC,EAAC,MAAM,YAAY,QAAQ,OAAO,SAAS,GAAG,OAAO,MAAM,UAAU,MAAM,aAAa,6BAA6B,GAAG,UAAU,SAAS,wCAAuC,CAAC,IAAI,CAAC;AAAA,UAC7M,YAAY;AAAA,UACZ,aAAa;AAAA,UACb,cAAc,KAAK,IAAI,IAAI;AAAA,UAC3B,cAAc;AAAA,YACZ,cAAc,OAAO,IAAI,MAAM;AAAA,YAAG,mBAAmB,OAAO,IAAI,MAAM;AAAA,YAAG,mBAAmB,OAAO,SAAS;AAAA,YAC5G,QAAQ,OAAO,SAAS;AAAA,YAAG,mBAAe,wBAAW,SAAS;AAAA,YAAG,YAAY,IAAI;AAAA,YAAO,eAAe;AAAA,UACzG;AAAA,QACF;AAAA,MACF,QAAQ;AACN,eAAO;AAAA,MACT;AAAA,IACF;AAAA,IAEA,MAAM,aAAa,OAAmC;AACpD,YAAM,KAAK,MAAM;AACjB,YAAM,SAAS,YAAY,MAAM,QAAQ;AACzC,UAAI,CAAC,MAAM,CAAC,OAAQ,OAAM,IAAI,MAAM,8CAA8C;AAClF,aAAO;AAAA,QACL,OAAO,OAAO,IAAI;AAAA,QAClB,IAAI,GAAG,MAAM;AAAA,QACb,OAAO,GAAG,SAAS;AAAA,QACnB,GAAI,GAAG,OAAO,EAAC,MAAM,GAAG,KAAI,IAAI,CAAC;AAAA,QACjC,GAAI,GAAG,YAAY,SAAY,EAAC,SAAS,GAAG,QAAO,IAAI,CAAC;AAAA,QACxD,GAAI,GAAG,WAAW,EAAC,UAAU,GAAG,SAAQ,IAAI,CAAC;AAAA,QAC7C,GAAI,GAAG,kBAAkB,EAAC,iBAAiB,GAAG,gBAAe,IAAI,CAAC;AAAA,MACpE;AAAA,IACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAQA,MAAM,iBAAiB,OAAc,IAA+B;AAClE,YAAM,SAAS,YAAY,MAAM,QAAQ;AACzC,UAAI,CAAC,OAAQ,OAAM,IAAI,MAAM,2BAA2B;AACxD,UAAI,CAAC,KAAK,GAAG,IAAI,OAAO,IAAI,cAAc,EAAG,OAAM,IAAI,MAAM,uEAAuE;AACpI,UAAI,OAAO,cAAc,eAAe;AACtC,cAAM,QAAQ,MAAM,QAAQ,OAAO,KAAK,OAAO,GAAG,IAAI,KAAK,CAAC,MAAM,EAAE,sBAAsB,aAAa;AACvG,YAAI,CAAC,QAAQ,CAAC,OAAO,SAAS,KAAK,UAAU,KAAK,KAAK,aAAa,EAAG,OAAM,IAAI,MAAM,oFAA+E;AACtK,cAAM,SAAS,OAAO,OAAO,MAAM,YAAY,GAAG,KAAK,YAAY,CAAC;AACpE,cAAM,SAAS,OAAO,MAAM,cAAc,UAAU,GAAG;AACvD,YAAI,SAAS,OAAQ,OAAM,IAAI,MAAM,oCAAoC,MAAM,KAAK,KAAK,UAAU,mCAAmC,MAAM,kBAAa;AAAA,MAC3J;AACA,YAAM,IAAI,OAAO,OAAO,IAAI,KAAK;AACjC,UAAI,CAAC,EAAG;AACR,YAAM,cAAc,MAAM,EAAE,aAAa,EAAC,aAAS,wBAAW,OAAO,IAAI,cAAc,GAAG,KAAK,qBAAqB,cAAc,0BAAyB,CAAC;AAC5J,UAAI,CAAC,KAAK,aAAa,OAAO,IAAI,kBAAkB,EAAG,OAAM,IAAI,MAAM,4EAA4E;AACnJ,YAAM,SAAS,MAAM,EAAE,aAAa,EAAC,aAAS,wBAAW,OAAO,IAAI,kBAAkB,GAAG,KAAK,yBAAyB,cAAc,cAAa,CAAC;AACnJ,UAAI,OAAO,MAAM,MAAM,OAAO,IAAI,OAAQ,OAAM,IAAI,MAAM,6CAA6C,MAAM,cAAc,OAAO,IAAI,MAAM,EAAE;AAAA,IAChJ;AAAA,IAEA,MAAM,YAAY,KAAuC;AACvD,YAAM,SAAS,YAAY,IAAI,QAAQ;AACvC,UAAI,CAAC,OAAQ,QAAO,EAAC,OAAO,SAAQ;AACpC,YAAM,QAAQ,EAAC,OAAO,OAAO,IAAI,OAAO,OAAO,MAAK;AACpD,UAAI,CAAC,IAAI,aAAc,QAAO,EAAC,OAAO,WAAW,MAAK;AACtD,UAAI;AACF,cAAM,IAAI,MAAM,aAAa,OAAO,KAAK,IAAI,YAAY;AACzD,YAAI,CAAC,EAAG,QAAO,EAAC,OAAO,WAAW,iBAAiB,OAAO,MAAK;AAC/D,cAAM,QAAQ,EAAE,gBAAgB;AAChC,YAAI,EAAE,WAAW,cAAc,UAAU,EAAE,WAAW,KAAK,UAAU,EAAE,OAAO,GAAG;AAE/E,gBAAM,OAAO,UAAU,KAAK,KAAK,MAAM,WAAW,KAAK,MAAM,OAAO,OAAO,KAAK,KAAK,IAAI,OAAO,OAAO,IAAI,KAAK,IAAI,YAAY;AAChI,cAAI,SAAS,KAAM,QAAO,EAAC,OAAO,aAAa,OAAO,EAAC,GAAG,OAAO,OAAO,MAAK,GAAG,GAAI,IAAI,aAAa,EAAC,YAAY,IAAI,WAAU,IAAI,CAAC,EAAE;AACvI,cAAI,IAAI,YAAY;AAIlB,gBAAI,IAAI,oBAAoB,MAAM;AAChC,qBAAO,SAAS,QACZ,EAAC,OAAO,WAAW,iBAAiB,MAAM,YAAY,IAAI,YAAY,OAAO,EAAC,GAAG,OAAO,OAAO,MAAK,EAAC,IACrG,EAAC,OAAO,aAAa,YAAY,IAAI,YAAY,OAAO,EAAC,GAAG,OAAO,OAAO,MAAK,EAAC;AAAA,YACtF;AAGA,gBAAI,SAAS,MAAO,QAAO,EAAC,OAAO,WAAW,iBAAiB,MAAM,YAAY,IAAI,YAAY,OAAO,EAAC,GAAG,OAAO,OAAO,MAAK,EAAC;AAAA,UAClI;AACA,iBAAO,EAAC,OAAO,mBAAmB,iBAAiB,MAAM,OAAO,EAAC,GAAG,OAAO,OAAO,KAAI,EAAC;AAAA,QACzF;AACA,eAAO,EAAC,OAAO,WAAW,iBAAiB,MAAM,MAAK;AAAA,MACxD,QAAQ;AACN,eAAO,EAAC,OAAO,WAAW,MAAK;AAAA,MACjC;AAAA,IACF;AAAA;AAAA,IAGA,MAAM,WAAW,KAA4C;AAC3D,YAAM,SAAS,YAAY,IAAI,QAAQ;AACvC,UAAI,CAAC,UAAU,CAAC,IAAI,aAAc,QAAO;AACzC,YAAM,IAAI,MAAM,aAAa,OAAO,KAAK,IAAI,YAAY;AACzD,UAAI,CAAC,KAAK,EAAE,WAAW,cAAc,CAAC,UAAU,EAAE,WAAW,KAAK,CAAC,UAAU,EAAE,OAAO,EAAG,QAAO;AAEhG,UAAI,EAAE,gBAAgB,sBAAsB,UAAa,OAAO,EAAE,eAAe,iBAAiB,MAAM,OAAO,IAAI,QAAQ;AACzH,cAAM,IAAI,MAAM,0DAA0D;AAAA,MAC5E;AACA,UAAI,EAAE,gBAAgB,iBAAiB,UAAa,OAAO,EAAE,eAAe,YAAY,MAAM,OAAO,IAAI,QAAQ;AAC/G,cAAM,IAAI,MAAM,qDAAqD;AAAA,MACvE;AAOA,YAAM,MAAM,EAAE,gBAAgB,oBAAoB;AAClD,YAAM,IAAI,OAAO,OAAO,IAAI,KAAK;AACjC,UAAI,KAAK,OAAO,QAAQ,KAAK,GAAG,KAAK,OAAO,GAAG,IAAI,IAAI;AACrD,cAAM,OAAO,MAAM,EAAE,QAAQ,EAAC,QAAQ,wBAAwB,QAAQ,CAAC,UAAU,KAAK,EAAC,CAAC,EACrF,KAAK,CAAC,MAAM;AACX,gBAAM,QAAQ;AACd,gBAAM,MAAM,OAAO,iBAAiB,OAAO;AAC3C,iBAAO,MAAM,OAAO,GAAG,IAAI;AAAA,QAC7B,CAAC,EACA,MAAM,MAAM,IAAI;AACnB,YAAI,SAAS,QAAQ,QAAQ,OAAO,GAAG,GAAG;AACxC,gBAAM,QAAQ,EAAE,gBAAgB,SAAS,EAAE;AAC3C,cAAI,MAAO,OAAM,QAAQ,GAAG,GAAG,gBAAgB,KAAK,IAAI,EAAC,QAAQ,QAAQ,YAAQ,4BAAc,IAAM,EAAC,CAAC,EAAE,MAAM,MAAM,MAAS;AAC9H,iBAAO;AAAA,QACT;AAAA,MACF;AACA,aAAO;AAAA,QACL,OAAO,OAAO,IAAI;AAAA,QAClB,IAAI,OAAO,IAAI;AAAA,QACf,OAAO;AAAA,QACP,UAAM,gCAAmB,EAAC,KAAK,yBAAyB,cAAc,kBAAkB,MAAM,CAAC,EAAE,SAAS,EAAE,WAAW,EAAC,CAAC;AAAA,QACzH,SAAS,OAAO,IAAI;AAAA,QACpB,UAAU;AAAA,MACZ;AAAA,IACF;AAAA,EACF;AACF;AASO,SAAS,gBAAgB,QAAqB,OAA6B;AAChF,QAAM,MAAM,OAAO,UAAU,eAAe,KAAK,cAAc,OAAO,WAAW,IAAI,aAAa,OAAO,WAAW,IAAI;AACxH,QAAM,MAAM,OAAO,UAAU,eAAe,KAAK,cAAc,OAAO,SAAS,IAAI,aAAa,OAAO,SAAS,IAAI;AACpH,MAAI,CAAC,OAAO,CAAC,OAAO,QAAQ,IAAK,QAAO;AACxC,MAAI,OAAO,YAAY,YAAY,MAAM,UAAU,EAAE,KAAK,OAAO,WAAW,IAAI,IAAI,KAAK,OAAO,UAAU,YAAY,MAAM,QAAS,QAAO;AAC5I,QAAM,KAAK,MAAM;AACjB,MAAI,CAAC,IAAI,QAAQ,CAAC,GAAG,MAAM,GAAG,iBAAiB,OAAW,QAAO;AACjE,MAAI,CAAC,KAAK,GAAG,IAAI,IAAI,cAAc,EAAG,QAAO,oBAAoB,GAAG,EAAE;AACtE,MAAI,OAAO,GAAG,SAAS,GAAG,MAAM,GAAI,QAAO;AAC3C,MAAI,CAAC,GAAG,mBAAmB,CAAC,KAAK,GAAG,iBAAiB,IAAI,cAAc,EAAG,QAAO;AACjF,MAAI,GAAG,YAAY,UAAa,GAAG,YAAY,IAAI,QAAS,QAAO,yBAAyB,GAAG,OAAO,SAAS,IAAI,OAAO;AAC1H,MAAI;AACJ,MAAI;AACF,UAAMA,SAAI,gCAAmB,EAAC,KAAK,qBAAqB,MAAM,GAAG,KAAW,CAAC;AAC7E,QAAIA,GAAE,iBAAiB,iBAAkB,QAAO,GAAGA,GAAE,YAAY;AACjE,WAAOA,GAAE;AAAA,EACX,QAAQ;AACN,WAAO;AAAA,EACT;AACA,QAAM,CAAC,QAAQ,QAAQ,eAAe,WAAW,QAAQ,QAAQ,SAAS,IAAI;AAC9E,MAAI,UAAkB;AACtB,MAAI;AACF,eAAW,OAAO,OAAO,QAAQ;AACjC,YAAQ,OAAO,MAAM,aAAa;AAClC,QAAI,OAAO,iBAAiB,UAAa,OAAO,OAAO,YAAY,IAAI,MAAO,SAAQ,OAAO,OAAO,YAAY;AAAA,EAClH,QAAQ;AACN,WAAO;AAAA,EACT;AACA,MAAI,WAAW,YAAY,OAAO,MAAM,YAAY,MAAM,SAAU,QAAO,kBAAkB,MAAM,aAAa,QAAQ;AACxH,MAAI,WAAW,IAAI,OAAQ,QAAO,4BAA4B,MAAM,SAAS,IAAI,IAAI,KAAK,IAAI,MAAM;AAEpG,MAAI,OAAO,eAAe,OAAO,QAAQ,OAAO;AAC9C,QAAI,KAAC,uBAAU,OAAO,WAAW,EAAG,QAAO;AAC3C,QAAI,cAAc,YAAY,UAAM,qBAAI,wBAAW,OAAO,WAAW,GAAG,EAAC,MAAM,GAAE,CAAC,EAAE,YAAY,EAAG,QAAO,qBAAqB,aAAa;AAAA,EAC9I;AACA,MAAI,CAAC,KAAK,WAAW,IAAI,IAAI,EAAG,QAAO,mBAAmB,SAAS;AACnE,MAAI,WAAW,qBAAU,QAAO;AAChC,MAAI,cAAc,iBAAiB,cAAc,kBAAmB,QAAO,sBAAsB,SAAS;AAC1G,MAAI,UAAU,UAAU,SAAS,SAAS,MAAO,QAAO,qBAAqB,MAAM,yBAAyB,KAAK;AAEjH,OAAK,2BAA2B,KAAK,MAAM,QAAQ,IAAI,CAAC,KAAK,MAAM,cAAc,QAAQ,IAAI,MAAM,IAAI,IAAI,MAAM,IAAI,SAAS,GAAI,QAAO;AACzI,MAAI,MAAM,cAAc,WAAW,UAAa,MAAM,aAAa,WAAW,OAAO,SAAS,EAAG,QAAO;AACxG,SAAO;AACT;AAOO,IAAM,WAA0E,OAAO,OAAO;AAAA,EACnG,aAAa,CAAC,UAAqC,iBAAiB,KAAK;AAAA,EACzE,UAAU,CAAC,UAAqC,iBAAiB,KAAK;AAAA,EACtE,cAAc;AAAA,EACd,aAAa;AACf,CAAC;AACD,SAAS,iBAAiB,OAAkC;AAC1D,QAAMA,KAAI,OAAO,UAAU,eAAe,KAAK,cAAc,KAAK,IAAI,aAAa,KAAK,IAAI;AAC5F,SAAOA,KAAI,CAACA,GAAE,cAAc,IAAI,CAAC;AACnC;;;AFzbO,IAAM,oBAAN,cAAgC,kCAAoB;AAAA,EACtC;AAAA,EACnB,YAAY,SAAmC,QAAyB;AACtE,UAAM,SAAS,MAAM;AACrB,SAAK,WAAW,aAAa,MAAM;AAAA,EACrC;AAAA,EACmB,eAAe,OAAwB;AACxD,WAAO,KAAQ,cAAc,KAAK;AAAA,EACpC;AAAA,EACmB,cAAc,WAAmB,SAA0B;AAC5E,WAAO,KAAQ,SAAS,WAAW,OAAO;AAAA,EAC5C;AACF;","names":["import_util","d"]}
|
|
1
|
+
{"version":3,"sources":["../src/protocol.ts","../src/config.ts","../src/provider.ts","../src/activity.ts"],"sourcesContent":["import {SingleProviderSwap2} from \"@anywalletkit/protocol-swap2-core/swap2/single\";\nimport type {Swap2Account, Swap2EngineConfig} from \"@anywalletkit/protocol-swap2-core/swap2/base\";\nimport {cctp as cctpCfg} from \"./config.js\";\nimport {cctpProvider, type CctpProviderConfig} from \"./provider.js\";\n\nexport interface CctpSwap2Config extends Swap2EngineConfig, CctpProviderConfig {}\n\n/** Standalone CCTP swap2: USDC burn-and-mint between EVM chains, claim via `claimSwap2`. */\nexport class CctpSwap2Protocol extends SingleProviderSwap2 {\n protected readonly provider;\n constructor(account: Swap2Account | undefined, config: CctpSwap2Config) {\n super(account, config);\n this.provider = cctpProvider(config);\n }\n protected override chainSupported(caip2: string): boolean {\n return cctpCfg.supportsChain(caip2);\n }\n protected override pairSupported(fromChain: string, toChain: string): boolean {\n return cctpCfg.supports(fromChain, toChain);\n }\n}\n","// Circle CCTP V2 — mainnet domains, contracts and the native USDC each domain\n// mints. Sources (read 2026-10-10, Arc + Morph 2026-10-14): developers.circle.com/cctp/evm-smart-contracts\n// (domains + TokenMessengerV2 / MessageTransmitterV2, the same addresses on\n// every EVM chain except EDGE), developers.circle.com/stablecoins/usdc-contract-addresses\n// (native USDC). Only chains whose USDC is Circle-native are listed: CCTP\n// burns native USDC, a bridged USDC.e (BSC, Gnosis) cannot ride it.\nimport {evmRef, isEvm} from \"@anywalletkit/protocol-swap2-core/util\";\n\nexport interface CctpDomain {\n caip2: string;\n chainId: number;\n domain: number;\n name: string;\n usdc: string;\n tokenMessenger: string;\n messageTransmitter: string;\n}\n\nexport const TOKEN_MESSENGER_V2 = \"0x28b5a0e9C621a5BadaA536219b3a228C8168cf5d\";\nexport const MESSAGE_TRANSMITTER_V2 = \"0x81D40F21F12A8F0E3252Bccb954D722d4c464B64\";\n\nconst d = (chainId: number, domain: number, name: string, usdc: string): CctpDomain => ({\n caip2: `eip155:${chainId}`, chainId, domain, name, usdc, tokenMessenger: TOKEN_MESSENGER_V2, messageTransmitter: MESSAGE_TRANSMITTER_V2,\n});\n\n/** CAIP-2 → CCTP domain. */\nexport const CCTP_DOMAINS: Readonly<Record<string, CctpDomain>> = Object.freeze(Object.fromEntries([\n d(1, 0, \"Ethereum\", \"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48\"),\n d(43114, 1, \"Avalanche\", \"0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E\"),\n d(10, 2, \"OP Mainnet\", \"0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85\"),\n d(42161, 3, \"Arbitrum\", \"0xaf88d065e77c8cC2239327C5EDb3A432268e5831\"),\n d(8453, 6, \"Base\", \"0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913\"),\n d(137, 7, \"Polygon PoS\", \"0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359\"),\n d(130, 10, \"Unichain\", \"0x078D782b760474a361dDA0AF3839290b0EF57AD6\"),\n d(59144, 11, \"Linea\", \"0x176211869cA2b568f2A7D4EE941E073a821EE1ff\"),\n d(146, 13, \"Sonic\", \"0x29219dd400f2Bf60E5a23d13Be72B486D4038894\"),\n d(480, 14, \"World Chain\", \"0x79A02482A880bCe3F13E09da970dC34dB4cD24D1\"),\n d(143, 15, \"Monad\", \"0x754704Bc059F8C67012fEd69BC8A327a5aafb603\"),\n d(1329, 16, \"Sei\", \"0xe15fC38F6D8c56aF07bbCBe3BAf5708A2Bf42392\"),\n d(999, 19, \"HyperEVM\", \"0xb88339CB7199b77E23DB6E890353E22632Ba630f\"),\n d(57073, 21, \"Ink\", \"0x2D270e6886d130D724215A266106e6832161EAEd\"),\n d(98866, 22, \"Plume\", \"0x222365EF19F7947e5484218551B56bb3965Aa7aF\"),\n d(9745, 33, \"Plasma\", \"0x2d661C89D812261039AF9764eceaAee884f5F67F\"),\n d(196, 37, \"X Layer\", \"0xB6CEceAB302E2E4948951eE7843FC24E92933061\"),\n // 2026-10-14: Arc and Morph (developers.circle.com/cctp/evm-smart-contracts + usdc-contract-addresses; TokenMessengerV2 /\n // MessageTransmitterV2 have code on both chains, MessageTransmitterV2.localDomain() answers 26 / 30 and\n // TokenMessengerV2.localMessageTransmitter() points at 0x81D4…). Arc's USDC is the chain's gas token: 0x3600… is its\n // 6-decimal ERC-20 interface, which is what CCTP burns and mints.\n d(5042, 26, \"Arc\", \"0x3600000000000000000000000000000000000000\"),\n d(2818, 30, \"Morph\", \"0xCfb1186F4e93D60E60a8bDd997427D1F33bc372B\"),\n].map((x) => [x.caip2, x])));\n\n/** CCTP domain → entry. */\nexport const CCTP_BY_DOMAIN: Readonly<Record<number, CctpDomain>> = Object.freeze(\n Object.fromEntries(Object.values(CCTP_DOMAINS).map((x) => [x.domain, x])),\n);\n\n/** Solana is CCTP domain 5 (not executed by this package yet: the engine runs calldata on EVM only). */\nexport const CCTP_SOLANA_DOMAIN = 5;\n\nexport const CCTP_API = \"https://iris-api.circle.com\";\n\n/** Finality thresholds the header carries: Fast Transfer (confirmed) vs Standard (finalized). */\nexport const FINALITY_FAST = 1000;\nexport const FINALITY_STANDARD = 2000;\n\nexport const cctp = {\n supportsChain(chain: string): boolean {\n return isEvm(chain) && !!CCTP_DOMAINS[`eip155:${evmRef(chain)}`];\n },\n supports(from: string, to: string): boolean {\n return from !== to && this.supportsChain(from) && this.supportsChain(to);\n },\n};\n","import type {RemotePins} from \"@anywalletkit/protocol-swap2-core/types\";\nimport {httpRefusal, refusal, refusalNotes, withReason, type Swap2RefusalReason} from \"@anywalletkit/protocol-swap2-core/errors\";\nimport {createPublicClient, decodeFunctionData, encodeFunctionData, getAddress, http, isAddress, pad, parseAbi, zeroHash, type Hex} from \"viem\";\nimport {describeCctpActivity} from \"./activity.js\";\nimport {ccAsset} from \"@anywalletkit/swap2-assets\";\nimport {timeoutSignal} from \"@anywalletkit/protocol-swap2-core/util\";\nimport type {Asset, CrossChainProvider, IntentRef, IntentStatus, Quote, QuoteParams, UnsignedTx} from \"@anywalletkit/protocol-swap2-core/types\";\nimport {CCTP_API, CCTP_BY_DOMAIN, CCTP_DOMAINS, FINALITY_FAST, FINALITY_STANDARD, cctp as cctpCfg, type CctpDomain} from \"./config.js\";\nimport {bigintToNumber} from \"@anywalletkit/core\";\n\n/**\n * Circle CCTP V2 — native USDC between chains by burn-and-mint, no spread, no\n * aggregator fee. TWO-PHASE: `depositForBurn` on the source burns the USDC and\n * emits the message; Circle's attestation service (Iris) signs it once the\n * source reached the requested finality; `receiveMessage(message, attestation)`\n * on the destination mints. That second transaction is the user's: the engine\n * exposes it through `buildClaim` / `claimSwap2` (status \"action-required\").\n *\n * - Fast Transfer (finality 1000, confirmed, ~seconds–minutes) costs a fee in\n * bps that Circle publishes per pair; Standard (2000, finalized, ~15 min)\n * is free. `mode: \"auto\"` takes Fast when the pair offers it and the Fast\n * allowance covers the amount, else Standard.\n * - `maxFee` sent on-chain is the published fee (plus a small buffer) and is\n * the only thing that can be deducted: the guaranteed output is\n * amount − maxFee. `preflightDeposit` re-reads Circle's published fee right\n * before the burn (the deployed TokenMessengerV2 has no on-chain\n * `getMinFeeAmount`/`minFee` — both revert on Ethereum, Base, Arbitrum,\n * 2026-10-12) and, with an RPC for the source chain, the transmitter's\n * `localDomain()` on the very contract the calldata targets.\n * - Everything is bound to Circle's documented contract addresses and the\n * native USDC of each domain; a catalog USDC that is not the native one\n * refuses the route (USDC.e cannot be burnt).\n */\n\nconst TOKEN_MESSENGER_ABI = parseAbi([\n \"function depositForBurn(uint256 amount, uint32 destinationDomain, bytes32 mintRecipient, address burnToken, bytes32 destinationCaller, uint256 maxFee, uint32 minFinalityThreshold)\",\n \"function localMessageTransmitter() view returns (address)\",\n]);\nconst MESSAGE_TRANSMITTER_ABI = parseAbi([\n \"function receiveMessage(bytes message, bytes attestation) returns (bool)\",\n \"function localDomain() view returns (uint32)\",\n \"function usedNonces(bytes32 nonce) view returns (uint256)\",\n]);\n\nconst EVM_PLACEHOLDER = \"0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045\";\nconst DEFAULT_QUOTE_TTL_MS = 60_000;\n/** Fallback gas limit: a depositForBurn runs ~110–150k, receiveMessage ~150–200k. */\nconst GAS_DEPOSIT = \"200000\";\nconst GAS_CLAIM = \"260000\";\n\nexport type CctpMode = \"auto\" | \"fast\" | \"standard\";\n\nexport interface CctpProviderConfig {\n enabled?: boolean;\n /** Circle attestation API base (default https://iris-api.circle.com). */\n apiUrl?: string;\n /** Fast when offered and within the allowance (default), or force one path. */\n mode?: CctpMode;\n /** Extra headroom on the published Fast fee, in percent of the fee (default 10). The excess is never charged. */\n feeBufferPct?: number;\n /**\n * JSON-RPC URLs per CAIP-2 chain. Optional, but with them the provider\n * verifies the contracts before the burn and detects the mint on the\n * destination (`usedNonces`). Without the destination chain's URL the status\n * reaches \"completed\" only through the id `claimSwap2` returns for a claim the\n * account saw succeed; a bare claim hash stays \"pending\" (hash kept).\n */\n rpcUrls?: Readonly<Record<string, string>>;\n /** Local lifetime of a quote (fees are stable; default 60 s). */\n quoteTtlMs?: number;\n /** Injectable for tests. */\n fetchImpl?: typeof fetch;\n}\n\ninterface FeeRow { finalityThreshold: number; minimumFee: number }\ninterface ApiMessage {\n message?: string;\n eventNonce?: string;\n attestation?: string | null;\n status?: string;\n delayReason?: string | null;\n cctpVersion?: number;\n decodedMessage?: {\n sourceDomain?: string; destinationDomain?: string; nonce?: string; mintRecipient?: string;\n decodedMessageBody?: {amount?: string; maxFee?: string; feeExecuted?: string; expirationBlock?: string; mintRecipient?: string; burnToken?: string};\n };\n}\n\nconst isHexData = (v: unknown): v is Hex => typeof v === \"string\" && /^0x(?:[0-9a-fA-F]{2})+$/.test(v);\n\n/**\n * Tags a failed read with what it means and hands back the same error: a network failure, our own timeout or an\n * answer that is not JSON is `upstream_unavailable`; the caller's own abort stays unclassified.\n */\nfunction unreachable<E>(error: E, signal?: AbortSignal): E {\n if (!signal?.aborted && error instanceof Error) withReason(error, \"upstream_unavailable\");\n return error;\n}\n\n/** A contract read on the caller's RPC that failed: an `eth_call` that reverted or found no code, else the node's failure. */\nfunction rpcFailure<E>(error: E): E {\n if (!(error instanceof Error)) return error;\n let reverted = false;\n for (let e: unknown = error, i = 0; e instanceof Error && i < 8; e = e.cause, i++) {\n if (e.name === \"ContractFunctionRevertedError\" || e.name === \"ContractFunctionZeroDataError\" || e.name === \"ExecutionRevertedError\") reverted = true;\n }\n return withReason(error, reverted ? \"simulation_failed\" : \"upstream_unavailable\");\n}\nconst same = (a: string | undefined, b: string) => !!a && a.toLowerCase() === b.toLowerCase();\n\n/** `amount × bps` rounded up; `bps` may be fractional (Circle publishes 1.3). */\nfunction feeFor(amount: bigint, bps: number, bufferPct: number): bigint {\n const hundredths = BigInt(Math.round(bps * 100)); // 1.3 bps → 130\n const fee = (amount * hundredths + 999_999n) / 1_000_000n;\n if (fee === 0n) return 0n;\n return fee + (fee * BigInt(Math.round(bufferPct * 100)) + 9_999n) / 10_000n;\n}\n\n/**\n * The contracts a CCTP claim may call on `chain`: its MessageTransmitter (`receiveMessage`). Pass it\n * as `claimTargets` to a remote provider stub so the app, not the server, decides (round 3, M24).\n */\nexport function cctpClaimTargets(chain: string): readonly string[] {\n const d = Object.prototype.hasOwnProperty.call(CCTP_DOMAINS, chain) ? CCTP_DOMAINS[chain] : undefined;\n return d ? [d.messageTransmitter] : [];\n}\n\nexport function cctpProvider(config: CctpProviderConfig = {}): CrossChainProvider {\n config = Object.freeze({...config});\n const api = (config.apiUrl ?? CCTP_API).replace(/\\/+$/, \"\");\n if (!/^https?:\\/\\//.test(api)) throw new Error(\"cctp: apiUrl must use http or https\");\n const mode: CctpMode = config.mode ?? \"auto\";\n if (![\"auto\", \"fast\", \"standard\"].includes(mode)) throw new Error(\"cctp: mode must be auto | fast | standard\");\n const bufferPct = config.feeBufferPct ?? 10;\n if (!Number.isFinite(bufferPct) || bufferPct < 0 || bufferPct > 100) throw new Error(\"cctp: feeBufferPct must be between 0 and 100\");\n const quoteTtlMs = config.quoteTtlMs ?? DEFAULT_QUOTE_TTL_MS;\n if (!Number.isInteger(quoteTtlMs) || quoteTtlMs <= 0 || quoteTtlMs > 300_000) throw new Error(\"cctp: quoteTtlMs must be an integer between 1 and 300000\");\n const doFetch = config.fetchImpl ?? fetch;\n const rpcUrls = Object.freeze({...(config.rpcUrls ?? {})});\n\n const client = (caip2: string) => {\n const url = rpcUrls[caip2];\n return url ? createPublicClient({transport: http(url, {fetchOptions: {}, ...(config.fetchImpl ? {fetchFn: config.fetchImpl} : {})} as never), ccipRead: false}) : null;\n };\n\n async function getJson<T>(path: string, signal?: AbortSignal): Promise<T | null> {\n let res: Response;\n try {\n res = await doFetch(`${api}${path}`, {headers: {accept: \"application/json\"}, signal: signal ?? timeoutSignal(12_000)});\n } catch (e) {\n throw unreachable(e, signal);\n }\n if (res.status === 404) return null;\n if (!res.ok) {\n // 429 (with Retry-After), 408 / 425 / 5xx; any other status stays unclassified. Circle's API takes no key, so a\n // 401 / 403 (a block in front of it) is upstream_unavailable with its status, never key_rejected.\n const byStatus = httpRefusal(res.status, res.headers?.get?.(\"retry-after\"));\n const info = byStatus?.reason === \"key_rejected\" ? {reason: \"upstream_unavailable\" as const, httpStatus: res.status} : byStatus;\n const error = new Error(`cctp: ${path} → ${res.status}`);\n throw info ? withReason(error, info) : error;\n }\n try {\n return (await res.json()) as T;\n } catch (e) {\n throw unreachable(e, signal);\n }\n }\n\n /** Circle's published fee per finality threshold, in bps of the burnt amount. */\n const feeRows = (src: CctpDomain, dst: CctpDomain, signal?: AbortSignal) =>\n getJson<FeeRow[]>(`/v2/burn/USDC/fees/${src.domain}/${dst.domain}`, signal);\n\n /** The native USDC of a domain, cross-checked against the asset catalog when it knows the chain. */\n function usdcOf(dom: CctpDomain): string | null {\n const known = ccAsset(dom.caip2, \"USDC\");\n if (known && (!known.contract || !same(known.contract, dom.usdc))) return null; // catalog has a USDC that is not Circle's → refuse\n return dom.usdc;\n }\n\n function parseIntent(intentId: string): {src: CctpDomain; dst: CctpDomain; threshold: number} | null {\n const [tag, s, dd, t] = intentId.split(\":\");\n if (tag !== \"cctp\") return null;\n const src = CCTP_BY_DOMAIN[Number(s)];\n const dst = CCTP_BY_DOMAIN[Number(dd)];\n const threshold = Number(t);\n if (!src || !dst || !(threshold === FINALITY_FAST || threshold === FINALITY_STANDARD)) return null;\n return {src, dst, threshold};\n }\n\n async function fetchMessage(src: CctpDomain, sourceTxHash: string): Promise<ApiMessage | null> {\n const out = await getJson<{messages?: ApiMessage[]}>(`/v2/messages/${src.domain}?transactionHash=${encodeURIComponent(sourceTxHash)}`);\n const m = out?.messages?.find((x) => x.cctpVersion === undefined || x.cctpVersion === 2);\n return m ?? null;\n }\n\n /** The nonce's state on the destination: null without an RPC there, \"unknown\" when the configured RPC fails to answer. */\n async function minted(dst: CctpDomain, nonce: Hex): Promise<boolean | null | \"unknown\"> {\n const c = client(dst.caip2);\n if (!c) return null;\n try {\n const used = await c.readContract({address: getAddress(dst.messageTransmitter), abi: MESSAGE_TRANSMITTER_ABI, functionName: \"usedNonces\", args: [nonce]});\n return used !== 0n;\n } catch {\n return \"unknown\";\n }\n }\n\n return {\n name: \"cctp\",\n claimTargets: cctpClaimTargets,\n describeActivity: describeCctpActivity,\n enabled: () => config.enabled ?? true,\n supportsChain: (chain: string) => cctpCfg.supportsChain(chain),\n supportsChainPair: (from: string, to: string) => cctpCfg.supports(from, to),\n supportsRoute(from: Asset, to: Asset): boolean {\n const src = CCTP_DOMAINS[from.chain];\n const dst = CCTP_DOMAINS[to.chain];\n if (!src || !dst || from.chain === to.chain) return false;\n if (from.token.toUpperCase() !== \"USDC\") return false;\n // Destination is given as an address (zero = native): only the native USDC of the destination domain.\n return same(to.token, dst.usdc) || to.token.toUpperCase() === \"USDC\";\n },\n\n async getQuote(params: QuoteParams, signal?: AbortSignal): Promise<Quote | null> {\n if (params.flex) return null; // the amount is baked into the calldata\n const src = CCTP_DOMAINS[params.sourceChain];\n const dst = CCTP_DOMAINS[params.destChain];\n if (!src || !dst || src === dst) return null;\n if (params.sourceToken.toUpperCase() !== \"USDC\") return null;\n if (!(same(params.destToken, dst.usdc) || params.destToken.toUpperCase() === \"USDC\")) return null;\n const usdc = usdcOf(src);\n if (!usdc) { params.onRefusal?.(\"catalog USDC on the source chain is not Circle's native USDC\", {reason: \"unsupported_pair\"}); return null; }\n if (!/^\\d+$/.test(params.amountIn)) return null;\n const amount = BigInt(params.amountIn);\n if (amount <= 0n) return null;\n // The placeholder prices a dry quote; a live one without a recipient would mint to it (round 3, H8).\n const recipient = params.destAddress || (params.dry !== false ? EVM_PLACEHOLDER : \"\");\n if (!recipient) { params.onRefusal?.(\"a live quote needs a recipient\", {reason: \"policy_refused\"}); return null; }\n if (!isAddress(recipient)) { params.onRefusal?.(\"destination must be an EVM address\"); return null; }\n\n try {\n const fees = await feeRows(src, dst, signal);\n if (!fees || !Array.isArray(fees) || fees.length === 0) {\n // No fee list (404) or an empty one: Circle does not serve the pair; a list of another shape is a broken answer.\n params.onRefusal?.(\"Circle publishes no fee for this pair\", {reason: !fees || Array.isArray(fees) ? \"unsupported_pair\" : \"upstream_unavailable\"});\n return null;\n }\n const fast = fees.find((f) => f.finalityThreshold === FINALITY_FAST);\n const standard = fees.find((f) => f.finalityThreshold === FINALITY_STANDARD);\n let threshold: number;\n let bps: number;\n if (mode === \"standard\") {\n if (!standard) { params.onRefusal?.(\"Standard Transfer is not offered for this pair\", {reason: \"unsupported_pair\"}); return null; }\n threshold = FINALITY_STANDARD; bps = standard.minimumFee;\n } else {\n let fastOk = !!fast;\n if (fastOk) {\n const allowance = await getJson<{allowance?: number}>(\"/v2/fastBurn/USDC/allowance\", signal).catch(() => null);\n // The allowance is in whole USDC; refuse Fast when it cannot cover the burn.\n if (typeof allowance?.allowance === \"number\" && allowance.allowance * 1e6 < bigintToNumber(amount)) fastOk = false;\n }\n if (fastOk) { threshold = FINALITY_FAST; bps = fast!.minimumFee; }\n else if (mode === \"fast\") {\n params.onRefusal?.(fast ? \"Fast Transfer allowance is exhausted\" : \"Fast Transfer is not offered for this pair\", {reason: fast ? \"insufficient_liquidity\" : \"unsupported_pair\"});\n return null;\n }\n else if (standard) { threshold = FINALITY_STANDARD; bps = standard.minimumFee; }\n else { params.onRefusal?.(\"neither Fast nor Standard is offered\", {reason: \"unsupported_pair\"}); return null; }\n }\n if (!Number.isFinite(bps) || bps < 0) return null;\n const maxFee = feeFor(amount, bps, bufferPct);\n if (maxFee >= amount) { params.onRefusal?.(\"amount is below the Fast Transfer fee\", {reason: \"amount_too_small\"}); return null; }\n const out = amount - maxFee;\n if (params.minAmountOut !== undefined && out < BigInt(params.minAmountOut)) return null;\n\n const data = encodeFunctionData({\n abi: TOKEN_MESSENGER_ABI,\n functionName: \"depositForBurn\",\n args: [amount, dst.domain, pad(getAddress(recipient), {size: 32}), getAddress(usdc), zeroHash, maxFee, threshold],\n });\n const eta = threshold === FINALITY_FAST ? (src.domain === 0 ? 180 : 45) : (src.domain === 0 ? 1200 : 1000);\n return {\n provider: \"cctp\",\n intentId: `cctp:${src.domain}:${dst.domain}:${threshold}`,\n depositAddress: \"\",\n depositMemo: null,\n txRequest: {to: src.tokenMessenger, data, value: \"0\", chainId: src.chainId, gasLimit: GAS_DEPOSIT, approvalAddress: src.tokenMessenger},\n sourceAmount: amount.toString(),\n destAmount: out.toString(),\n minDestAmount: out.toString(),\n feeUsd: bigintToNumber(maxFee) / 1e6,\n fees: maxFee > 0n ? [{type: \"protocol\", amount: maxFee.toString(), token: usdc, included: true, description: `Circle Fast Transfer fee (${bps} bps + ${bufferPct}% buffer, unused part is not charged)`}] : [],\n etaSeconds: eta,\n reliability: 0.99,\n validUntilMs: Date.now() + quoteTtlMs,\n providerData: {\n sourceDomain: String(src.domain), destinationDomain: String(dst.domain), finalityThreshold: String(threshold),\n maxFee: maxFee.toString(), mintRecipient: getAddress(recipient), claimChain: dst.caip2, claimRequired: \"1\",\n },\n };\n } catch {\n return null;\n }\n },\n\n async buildDeposit(quote: Quote): Promise<UnsignedTx> {\n const tx = quote.txRequest;\n const parsed = parseIntent(quote.intentId);\n if (!tx || !parsed) throw refusal(\"policy_refused\", \"swap2: CCTP quote has no transaction request\");\n return {\n chain: parsed.src.caip2,\n to: tx.to ?? \"\",\n value: tx.value ?? \"0\",\n ...(tx.data ? {data: tx.data} : {}),\n ...(tx.chainId !== undefined ? {chainId: tx.chainId} : {}),\n ...(tx.gasLimit ? {gasLimit: tx.gasLimit} : {}),\n ...(tx.approvalAddress ? {approvalAddress: tx.approvalAddress} : {}),\n };\n },\n\n /**\n * Fast: Circle's CURRENT fee (same source and rounding as the quote, without\n * the buffer) still fits `maxFee` — Iris would otherwise hold the burn\n * until it times out to Standard. With a source RPC: the target really is\n * CCTP for this domain.\n */\n async preflightDeposit(quote: Quote, tx: UnsignedTx): Promise<void> {\n const parsed = parseIntent(quote.intentId);\n if (!parsed) throw refusal(\"policy_refused\", \"cctp: malformed intent id\");\n if (!same(tx.to, parsed.src.tokenMessenger)) throw refusal(\"vault_mismatch\", \"cctp: deposit target is not the TokenMessengerV2 of the source domain\");\n if (parsed.threshold === FINALITY_FAST) {\n const fast = (await feeRows(parsed.src, parsed.dst))?.find((f) => f.finalityThreshold === FINALITY_FAST);\n if (!fast || !Number.isFinite(fast.minimumFee) || fast.minimumFee < 0) throw refusal(\"quote_expired\", \"cctp: Circle no longer publishes a Fast Transfer fee for this pair — re-quote\");\n const minFee = feeFor(BigInt(quote.sourceAmount), fast.minimumFee, 0);\n const maxFee = BigInt(quote.providerData?.maxFee ?? \"0\");\n if (minFee > maxFee) throw refusal(\"quote_expired\", `cctp: Circle's Fast Transfer fee ${minFee} (${fast.minimumFee} bps) exceeds the quoted maxFee ${maxFee} — re-quote`);\n }\n const c = client(parsed.src.caip2);\n if (!c) return;\n const transmitter = await c.readContract({address: getAddress(parsed.src.tokenMessenger), abi: TOKEN_MESSENGER_ABI, functionName: \"localMessageTransmitter\"})\n .catch((e: unknown) => { throw rpcFailure(e); });\n if (!same(transmitter, parsed.src.messageTransmitter)) throw refusal(\"vault_mismatch\", \"cctp: TokenMessengerV2 does not point at the expected MessageTransmitterV2\");\n const domain = await c.readContract({address: getAddress(parsed.src.messageTransmitter), abi: MESSAGE_TRANSMITTER_ABI, functionName: \"localDomain\"})\n .catch((e: unknown) => { throw rpcFailure(e); });\n if (Number(domain) !== parsed.src.domain) throw refusal(\"vault_mismatch\", `cctp: MessageTransmitterV2 reports domain ${domain}, expected ${parsed.src.domain}`);\n },\n\n async trackIntent(ref: IntentRef): Promise<IntentStatus> {\n const parsed = parseIntent(ref.intentId);\n if (!parsed) return {state: \"failed\"};\n const claim = {chain: parsed.dst.caip2, ready: false};\n if (!ref.sourceTxHash) return {state: \"pending\", claim};\n try {\n const m = await fetchMessage(parsed.src, ref.sourceTxHash);\n if (!m) return {state: \"pending\", depositReceived: false, claim};\n const nonce = m.decodedMessage?.nonce;\n if (m.status === \"complete\" && isHexData(m.attestation) && isHexData(m.message)) {\n // A message without a readable nonce cannot be checked on the destination even with an RPC there.\n const done = isHexData(nonce) && nonce.length === 66 ? await minted(parsed.dst, nonce) : client(parsed.dst.caip2) ? \"unknown\" : null;\n if (done === true) return {state: \"completed\", claim: {...claim, ready: false}, ...(ref.destTxHash ? {destTxHash: ref.destTxHash} : {})};\n if (ref.destTxHash) {\n // A claim the sending account saw included and succeed is the mint: receiveMessage reverts once the\n // nonce is used, so a successful one minted this message. Without a destination read that is completed;\n // a destination read that does not show it yet is a node behind the claim, not a claim to send again.\n if (ref.destTxConfirmed === true) {\n return done === false\n ? {state: \"pending\", depositReceived: true, destTxHash: ref.destTxHash, claim: {...claim, ready: false}}\n : {state: \"completed\", destTxHash: ref.destTxHash, claim: {...claim, ready: false}};\n }\n // A claim was sent, but nothing here can read whether it minted (no destination RPC, or one that did\n // not answer): the hash is kept and the swap stays pending — a hash alone is not a mint.\n if (done !== false) return {state: \"pending\", depositReceived: true, destTxHash: ref.destTxHash, claim: {...claim, ready: false}};\n }\n return {state: \"action-required\", depositReceived: true, claim: {...claim, ready: true}};\n }\n return {state: \"pending\", depositReceived: true, claim};\n } catch {\n return {state: \"pending\", claim};\n }\n },\n\n /** `receiveMessage(message, attestation)` on the destination once Circle attested; null while pending. */\n async buildClaim(ref: IntentRef): Promise<UnsignedTx | null> {\n const parsed = parseIntent(ref.intentId);\n if (!parsed || !ref.sourceTxHash) return null;\n const m = await fetchMessage(parsed.src, ref.sourceTxHash);\n if (!m || m.status !== \"complete\" || !isHexData(m.attestation) || !isHexData(m.message)) return null;\n // Bind the attested message to the route it claims to complete.\n if (m.decodedMessage?.destinationDomain !== undefined && Number(m.decodedMessage.destinationDomain) !== parsed.dst.domain) {\n throw refusal(\"recipient_mismatch\", \"cctp: attested message is for another destination domain\");\n }\n if (m.decodedMessage?.sourceDomain !== undefined && Number(m.decodedMessage.sourceDomain) !== parsed.src.domain) {\n throw refusal(\"policy_refused\", \"cctp: attested message is for another source domain\");\n }\n // Fast messages expire at `expirationBlock` on the destination; an expired\n // one needs Circle's re-attestation before it can be received. The\n // transmitter compares it with `block.number`, which on Arbitrum-stack\n // chains is the L1 (Ethereum) height, not the L2 height eth_blockNumber\n // returns — the RPC block carries it as `l1BlockNumber` (live\n // 2026-10-16: a Base→Arbitrum claim was held as \"expired\" by L2 height).\n const exp = m.decodedMessage?.decodedMessageBody?.expirationBlock;\n const c = client(parsed.dst.caip2);\n if (c && exp && /^\\d+$/.test(exp) && BigInt(exp) > 0n) {\n const head = await c.request({method: \"eth_getBlockByNumber\", params: [\"latest\", false]})\n .then((b) => {\n const block = b as {number?: string; l1BlockNumber?: string} | null;\n const raw = block?.l1BlockNumber ?? block?.number;\n return raw ? BigInt(raw) : null;\n })\n .catch(() => null);\n if (head !== null && head >= BigInt(exp)) {\n const nonce = m.decodedMessage?.nonce ?? m.eventNonce;\n if (nonce) await doFetch(`${api}/v2/reattest/${nonce}`, {method: \"POST\", signal: timeoutSignal(12_000)}).catch(() => undefined);\n return null;\n }\n }\n return {\n chain: parsed.dst.caip2,\n to: parsed.dst.messageTransmitter,\n value: \"0\",\n data: encodeFunctionData({abi: MESSAGE_TRANSMITTER_ABI, functionName: \"receiveMessage\", args: [m.message, m.attestation]}),\n chainId: parsed.dst.chainId,\n gasLimit: GAS_CLAIM,\n };\n },\n };\n}\n\n/** The reason behind each text {@link cctpVerifyQuote} returns (`cctpPins.reasonOf`). */\nconst notes = refusalNotes();\nconst why = (text: string, reason: Swap2RefusalReason): string => notes.note(text, reason);\n\n/**\n * A remote CCTP quote's burn, decoded on the device against the app's own request (scan 2026-10-30, F3): exactly\n * `depositForBurn` on the source TokenMessengerV2 with no value, approving it; the input amount; the destination\n * chain's domain; the recipient as `mintRecipient`; the source domain's native USDC; no destination caller; a Fast\n * or Standard threshold; and a `maxFee` that leaves at least the quoted minimum and the caller's floor. The reason\n * it fails, or null. The engine then requires the build to repeat this quote's call.\n */\nexport function cctpVerifyQuote(params: QuoteParams, quote: Quote): string | null {\n const src = Object.prototype.hasOwnProperty.call(CCTP_DOMAINS, params.sourceChain) ? CCTP_DOMAINS[params.sourceChain] : undefined;\n const dst = Object.prototype.hasOwnProperty.call(CCTP_DOMAINS, params.destChain) ? CCTP_DOMAINS[params.destChain] : undefined;\n if (!src || !dst || src === dst) return why(\"not a CCTP route between two domains\", \"unsupported_pair\");\n if (params.sourceToken.toUpperCase() !== \"USDC\" || !(same(params.destToken, dst.usdc) || params.destToken.toUpperCase() === \"USDC\")) return why(\"not USDC to USDC\", \"unsupported_pair\");\n const tx = quote.txRequest;\n if (!tx?.data || !tx.to || tx.serializedTx !== undefined) return why(\"the quote carries no TokenMessenger call\", \"policy_refused\");\n if (!same(tx.to, src.tokenMessenger)) return why(`the call targets ${tx.to}, not the TokenMessengerV2`, \"vault_mismatch\");\n if (BigInt(tx.value ?? \"0\") !== 0n) return why(\"a burn attaches no value\", \"policy_refused\");\n if (!tx.approvalAddress || !same(tx.approvalAddress, src.tokenMessenger)) return why(\"the burn approves another spender than the TokenMessengerV2\", \"vault_mismatch\");\n if (tx.chainId !== undefined && tx.chainId !== src.chainId) return why(`the call is for chain ${tx.chainId}, not ${src.chainId}`, \"policy_refused\");\n let args: readonly unknown[];\n try {\n const d = decodeFunctionData({abi: TOKEN_MESSENGER_ABI, data: tx.data as Hex});\n if (d.functionName !== \"depositForBurn\") return why(`${d.functionName} is not depositForBurn`, \"policy_refused\");\n args = d.args;\n } catch {\n return why(\"the call is not depositForBurn\", \"policy_refused\");\n }\n const [amount, domain, mintRecipient, burnToken, caller, maxFee, threshold] = args as [bigint, number, Hex, string, Hex, bigint, number];\n let amountIn: bigint, floor: bigint;\n try {\n amountIn = BigInt(params.amountIn);\n floor = BigInt(quote.minDestAmount);\n if (params.minAmountOut !== undefined && BigInt(params.minAmountOut) > floor) floor = BigInt(params.minAmountOut);\n } catch {\n return why(\"the request does not name amounts\", \"upstream_unavailable\");\n }\n if (amount !== amountIn || BigInt(quote.sourceAmount) !== amountIn) return why(`the burn moves ${amount}, not the ${amountIn} input`, \"policy_refused\");\n if (domain !== dst.domain) return why(`the burn mints on domain ${domain}, not ${dst.name} (${dst.domain})`, \"recipient_mismatch\");\n // A dry quote without a recipient prices the placeholder the provider uses; it is never built (the engine re-quotes live).\n if (params.destAddress || params.dry === false) {\n if (!isAddress(params.destAddress)) return \"the recipient is not an EVM address\";\n if (mintRecipient.toLowerCase() !== pad(getAddress(params.destAddress), {size: 32}).toLowerCase()) return why(`the burn mints to ${mintRecipient}, not the recipient`, \"recipient_mismatch\");\n }\n if (!same(burnToken, src.usdc)) return why(`the burn spends ${burnToken}, not the source domain's USDC`, \"policy_refused\");\n if (caller !== zeroHash) return why(\"the burn names a destination caller\", \"policy_refused\");\n if (threshold !== FINALITY_FAST && threshold !== FINALITY_STANDARD) return why(`finality threshold ${threshold} is neither Fast nor Standard`, \"policy_refused\");\n if (maxFee >= amount || amount - maxFee < floor) return why(`the burn's maxFee ${maxFee} leaves less than the ${floor} minimum`, \"price_check_failed\");\n // The server appends its intent token (`<id>~<tag>`); the id before it is what the server's provider tracks and claims.\n if ((/^([\\s\\S]+)~[0-9a-f]{32}$/.exec(quote.intentId)?.[1] ?? quote.intentId) !== `cctp:${src.domain}:${dst.domain}:${threshold}`) return why(\"the intent id does not name this burn\", \"policy_refused\");\n if (quote.providerData?.maxFee !== undefined && quote.providerData.maxFee !== maxFee.toString()) return why(\"the quoted maxFee is not the burn's\", \"policy_refused\");\n return null;\n}\n\n/**\n * The TokenMessenger a CCTP burn calls and approves, and the MessageTransmitter its claim calls, per\n * chain, and {@link cctpVerifyQuote} — the app's pins for `remoteProvider({name: \"cctp\", baseUrl, ...cctpPins})`\n * (scan 2026-10-27 modules, F8/F16; claims since round 3, M24; the burn's arguments since scan 2026-10-30, F3).\n * `reasonOf` classifies each text the verifier returns (`Swap2RefusalReason`), so a remote stub's refusal carries it.\n */\nexport const cctpPins: RemotePins & {claimTargets(chain: string): readonly string[]} = Object.freeze({\n callTargets: (chain: string): readonly string[] => cctpMessengerFor(chain),\n spenders: (chain: string): readonly string[] => cctpMessengerFor(chain),\n claimTargets: cctpClaimTargets,\n verifyQuote: cctpVerifyQuote,\n reasonOf: notes.reasonOf,\n});\nfunction cctpMessengerFor(chain: string): readonly string[] {\n const d = Object.prototype.hasOwnProperty.call(CCTP_DOMAINS, chain) ? CCTP_DOMAINS[chain] : undefined;\n return d ? [d.tokenMessenger] : [];\n}\n","/**\n * Activity recognition for Circle CCTP V2 on every domain in `config.ts`:\n * `depositForBurn` on TokenMessengerV2 is our source leg (\"Bridged USDC\"), and\n * `receiveMessage` on MessageTransmitterV2 is the claim that mints on the\n * destination (\"Received USDC via CCTP\") — whoever paid the gas, the USDC lands\n * on the `mintRecipient`. Both are `bridge`; the other leg's hash is only known\n * through the kit's journal / Circle's attestation API, so `related` stays empty.\n */\nimport type {ActivityItem, ChainTx, DescribeActivityContext} from \"@anywalletkit/core\";\nimport {chainLabel, describeSwapLike, matchesCall} from \"@anywalletkit/protocol-swap2-core/activity\";\nimport {CCTP_DOMAINS} from \"./config.js\";\n\nexport const CCTP_MODULE = \"@anywalletkit/protocol-swap2-cctp\";\n\n/** depositForBurn(uint256,uint32,bytes32,address,bytes32,uint256,uint32) — TokenMessengerV2 */\nexport const CCTP_DEPOSIT_FOR_BURN = \"0x8e0250ee\";\n/** receiveMessage(bytes,bytes) — MessageTransmitterV2 */\nexport const CCTP_RECEIVE_MESSAGE = \"0x57ecfd28\";\n\nexport function describeCctpActivity(tx: ChainTx, ctx: DescribeActivityContext): ActivityItem | null {\n const domain = CCTP_DOMAINS[tx.chain];\n if (!domain) return null;\n const subtitle = `CCTP · ${chainLabel(tx.chain)}`;\n if (matchesCall(tx, [domain.tokenMessenger], [CCTP_DEPOSIT_FOR_BURN])) {\n return describeSwapLike(tx, ctx, {protocol: CCTP_MODULE, subtitle, kind: \"bridge\", title: \"Bridged USDC\"});\n }\n if (matchesCall(tx, [domain.messageTransmitter], [CCTP_RECEIVE_MESSAGE])) {\n return describeSwapLike(tx, ctx, {protocol: CCTP_MODULE, subtitle, kind: \"bridge\", title: \"Received USDC via CCTP\"});\n }\n return null;\n}\n"],"mappings":"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","names":["import_util","d"]}
|
package/dist/protocol.js
CHANGED
package/dist/provider.cjs
CHANGED
|
@@ -26,6 +26,7 @@ __export(provider_exports, {
|
|
|
26
26
|
cctpVerifyQuote: () => cctpVerifyQuote
|
|
27
27
|
});
|
|
28
28
|
module.exports = __toCommonJS(provider_exports);
|
|
29
|
+
var import_errors = require("@anywalletkit/protocol-swap2-core/errors");
|
|
29
30
|
var import_viem = require("viem");
|
|
30
31
|
|
|
31
32
|
// src/activity.ts
|
|
@@ -119,6 +120,18 @@ var DEFAULT_QUOTE_TTL_MS = 6e4;
|
|
|
119
120
|
var GAS_DEPOSIT = "200000";
|
|
120
121
|
var GAS_CLAIM = "260000";
|
|
121
122
|
var isHexData = (v) => typeof v === "string" && /^0x(?:[0-9a-fA-F]{2})+$/.test(v);
|
|
123
|
+
function unreachable(error, signal) {
|
|
124
|
+
if (!signal?.aborted && error instanceof Error) (0, import_errors.withReason)(error, "upstream_unavailable");
|
|
125
|
+
return error;
|
|
126
|
+
}
|
|
127
|
+
function rpcFailure(error) {
|
|
128
|
+
if (!(error instanceof Error)) return error;
|
|
129
|
+
let reverted = false;
|
|
130
|
+
for (let e = error, i = 0; e instanceof Error && i < 8; e = e.cause, i++) {
|
|
131
|
+
if (e.name === "ContractFunctionRevertedError" || e.name === "ContractFunctionZeroDataError" || e.name === "ExecutionRevertedError") reverted = true;
|
|
132
|
+
}
|
|
133
|
+
return (0, import_errors.withReason)(error, reverted ? "simulation_failed" : "upstream_unavailable");
|
|
134
|
+
}
|
|
122
135
|
var same = (a, b) => !!a && a.toLowerCase() === b.toLowerCase();
|
|
123
136
|
function feeFor(amount, bps, bufferPct) {
|
|
124
137
|
const hundredths = BigInt(Math.round(bps * 100));
|
|
@@ -147,10 +160,24 @@ function cctpProvider(config = {}) {
|
|
|
147
160
|
return url ? (0, import_viem.createPublicClient)({ transport: (0, import_viem.http)(url, { fetchOptions: {}, ...config.fetchImpl ? { fetchFn: config.fetchImpl } : {} }), ccipRead: false }) : null;
|
|
148
161
|
};
|
|
149
162
|
async function getJson(path, signal) {
|
|
150
|
-
|
|
163
|
+
let res;
|
|
164
|
+
try {
|
|
165
|
+
res = await doFetch(`${api}${path}`, { headers: { accept: "application/json" }, signal: signal ?? (0, import_util2.timeoutSignal)(12e3) });
|
|
166
|
+
} catch (e) {
|
|
167
|
+
throw unreachable(e, signal);
|
|
168
|
+
}
|
|
151
169
|
if (res.status === 404) return null;
|
|
152
|
-
if (!res.ok)
|
|
153
|
-
|
|
170
|
+
if (!res.ok) {
|
|
171
|
+
const byStatus = (0, import_errors.httpRefusal)(res.status, res.headers?.get?.("retry-after"));
|
|
172
|
+
const info = byStatus?.reason === "key_rejected" ? { reason: "upstream_unavailable", httpStatus: res.status } : byStatus;
|
|
173
|
+
const error = new Error(`cctp: ${path} \u2192 ${res.status}`);
|
|
174
|
+
throw info ? (0, import_errors.withReason)(error, info) : error;
|
|
175
|
+
}
|
|
176
|
+
try {
|
|
177
|
+
return await res.json();
|
|
178
|
+
} catch (e) {
|
|
179
|
+
throw unreachable(e, signal);
|
|
180
|
+
}
|
|
154
181
|
}
|
|
155
182
|
const feeRows = (src, dst, signal) => getJson(`/v2/burn/USDC/fees/${src.domain}/${dst.domain}`, signal);
|
|
156
183
|
function usdcOf(dom) {
|
|
@@ -205,7 +232,7 @@ function cctpProvider(config = {}) {
|
|
|
205
232
|
if (!(same(params.destToken, dst.usdc) || params.destToken.toUpperCase() === "USDC")) return null;
|
|
206
233
|
const usdc = usdcOf(src);
|
|
207
234
|
if (!usdc) {
|
|
208
|
-
params.onRefusal?.("catalog USDC on the source chain is not Circle's native USDC");
|
|
235
|
+
params.onRefusal?.("catalog USDC on the source chain is not Circle's native USDC", { reason: "unsupported_pair" });
|
|
209
236
|
return null;
|
|
210
237
|
}
|
|
211
238
|
if (!/^\d+$/.test(params.amountIn)) return null;
|
|
@@ -213,7 +240,7 @@ function cctpProvider(config = {}) {
|
|
|
213
240
|
if (amount <= 0n) return null;
|
|
214
241
|
const recipient = params.destAddress || (params.dry !== false ? EVM_PLACEHOLDER : "");
|
|
215
242
|
if (!recipient) {
|
|
216
|
-
params.onRefusal?.("a live quote needs a recipient");
|
|
243
|
+
params.onRefusal?.("a live quote needs a recipient", { reason: "policy_refused" });
|
|
217
244
|
return null;
|
|
218
245
|
}
|
|
219
246
|
if (!(0, import_viem.isAddress)(recipient)) {
|
|
@@ -223,7 +250,7 @@ function cctpProvider(config = {}) {
|
|
|
223
250
|
try {
|
|
224
251
|
const fees = await feeRows(src, dst, signal);
|
|
225
252
|
if (!fees || !Array.isArray(fees) || fees.length === 0) {
|
|
226
|
-
params.onRefusal?.("Circle publishes no fee for this pair");
|
|
253
|
+
params.onRefusal?.("Circle publishes no fee for this pair", { reason: !fees || Array.isArray(fees) ? "unsupported_pair" : "upstream_unavailable" });
|
|
227
254
|
return null;
|
|
228
255
|
}
|
|
229
256
|
const fast = fees.find((f) => f.finalityThreshold === FINALITY_FAST);
|
|
@@ -232,7 +259,7 @@ function cctpProvider(config = {}) {
|
|
|
232
259
|
let bps;
|
|
233
260
|
if (mode === "standard") {
|
|
234
261
|
if (!standard) {
|
|
235
|
-
params.onRefusal?.("Standard Transfer is not offered for this pair");
|
|
262
|
+
params.onRefusal?.("Standard Transfer is not offered for this pair", { reason: "unsupported_pair" });
|
|
236
263
|
return null;
|
|
237
264
|
}
|
|
238
265
|
threshold = FINALITY_STANDARD;
|
|
@@ -247,20 +274,20 @@ function cctpProvider(config = {}) {
|
|
|
247
274
|
threshold = FINALITY_FAST;
|
|
248
275
|
bps = fast.minimumFee;
|
|
249
276
|
} else if (mode === "fast") {
|
|
250
|
-
params.onRefusal?.(fast ? "Fast Transfer allowance is exhausted" : "Fast Transfer is not offered for this pair");
|
|
277
|
+
params.onRefusal?.(fast ? "Fast Transfer allowance is exhausted" : "Fast Transfer is not offered for this pair", { reason: fast ? "insufficient_liquidity" : "unsupported_pair" });
|
|
251
278
|
return null;
|
|
252
279
|
} else if (standard) {
|
|
253
280
|
threshold = FINALITY_STANDARD;
|
|
254
281
|
bps = standard.minimumFee;
|
|
255
282
|
} else {
|
|
256
|
-
params.onRefusal?.("neither Fast nor Standard is offered");
|
|
283
|
+
params.onRefusal?.("neither Fast nor Standard is offered", { reason: "unsupported_pair" });
|
|
257
284
|
return null;
|
|
258
285
|
}
|
|
259
286
|
}
|
|
260
287
|
if (!Number.isFinite(bps) || bps < 0) return null;
|
|
261
288
|
const maxFee = feeFor(amount, bps, bufferPct);
|
|
262
289
|
if (maxFee >= amount) {
|
|
263
|
-
params.onRefusal?.("amount is below the Fast Transfer fee");
|
|
290
|
+
params.onRefusal?.("amount is below the Fast Transfer fee", { reason: "amount_too_small" });
|
|
264
291
|
return null;
|
|
265
292
|
}
|
|
266
293
|
const out = amount - maxFee;
|
|
@@ -302,7 +329,7 @@ function cctpProvider(config = {}) {
|
|
|
302
329
|
async buildDeposit(quote) {
|
|
303
330
|
const tx = quote.txRequest;
|
|
304
331
|
const parsed = parseIntent(quote.intentId);
|
|
305
|
-
if (!tx || !parsed) throw
|
|
332
|
+
if (!tx || !parsed) throw (0, import_errors.refusal)("policy_refused", "swap2: CCTP quote has no transaction request");
|
|
306
333
|
return {
|
|
307
334
|
chain: parsed.src.caip2,
|
|
308
335
|
to: tx.to ?? "",
|
|
@@ -321,21 +348,25 @@ function cctpProvider(config = {}) {
|
|
|
321
348
|
*/
|
|
322
349
|
async preflightDeposit(quote, tx) {
|
|
323
350
|
const parsed = parseIntent(quote.intentId);
|
|
324
|
-
if (!parsed) throw
|
|
325
|
-
if (!same(tx.to, parsed.src.tokenMessenger)) throw
|
|
351
|
+
if (!parsed) throw (0, import_errors.refusal)("policy_refused", "cctp: malformed intent id");
|
|
352
|
+
if (!same(tx.to, parsed.src.tokenMessenger)) throw (0, import_errors.refusal)("vault_mismatch", "cctp: deposit target is not the TokenMessengerV2 of the source domain");
|
|
326
353
|
if (parsed.threshold === FINALITY_FAST) {
|
|
327
354
|
const fast = (await feeRows(parsed.src, parsed.dst))?.find((f) => f.finalityThreshold === FINALITY_FAST);
|
|
328
|
-
if (!fast || !Number.isFinite(fast.minimumFee) || fast.minimumFee < 0) throw
|
|
355
|
+
if (!fast || !Number.isFinite(fast.minimumFee) || fast.minimumFee < 0) throw (0, import_errors.refusal)("quote_expired", "cctp: Circle no longer publishes a Fast Transfer fee for this pair \u2014 re-quote");
|
|
329
356
|
const minFee = feeFor(BigInt(quote.sourceAmount), fast.minimumFee, 0);
|
|
330
357
|
const maxFee = BigInt(quote.providerData?.maxFee ?? "0");
|
|
331
|
-
if (minFee > maxFee) throw
|
|
358
|
+
if (minFee > maxFee) throw (0, import_errors.refusal)("quote_expired", `cctp: Circle's Fast Transfer fee ${minFee} (${fast.minimumFee} bps) exceeds the quoted maxFee ${maxFee} \u2014 re-quote`);
|
|
332
359
|
}
|
|
333
360
|
const c = client(parsed.src.caip2);
|
|
334
361
|
if (!c) return;
|
|
335
|
-
const transmitter = await c.readContract({ address: (0, import_viem.getAddress)(parsed.src.tokenMessenger), abi: TOKEN_MESSENGER_ABI, functionName: "localMessageTransmitter" })
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
if (
|
|
362
|
+
const transmitter = await c.readContract({ address: (0, import_viem.getAddress)(parsed.src.tokenMessenger), abi: TOKEN_MESSENGER_ABI, functionName: "localMessageTransmitter" }).catch((e) => {
|
|
363
|
+
throw rpcFailure(e);
|
|
364
|
+
});
|
|
365
|
+
if (!same(transmitter, parsed.src.messageTransmitter)) throw (0, import_errors.refusal)("vault_mismatch", "cctp: TokenMessengerV2 does not point at the expected MessageTransmitterV2");
|
|
366
|
+
const domain = await c.readContract({ address: (0, import_viem.getAddress)(parsed.src.messageTransmitter), abi: MESSAGE_TRANSMITTER_ABI, functionName: "localDomain" }).catch((e) => {
|
|
367
|
+
throw rpcFailure(e);
|
|
368
|
+
});
|
|
369
|
+
if (Number(domain) !== parsed.src.domain) throw (0, import_errors.refusal)("vault_mismatch", `cctp: MessageTransmitterV2 reports domain ${domain}, expected ${parsed.src.domain}`);
|
|
339
370
|
},
|
|
340
371
|
async trackIntent(ref) {
|
|
341
372
|
const parsed = parseIntent(ref.intentId);
|
|
@@ -369,10 +400,10 @@ function cctpProvider(config = {}) {
|
|
|
369
400
|
const m = await fetchMessage(parsed.src, ref.sourceTxHash);
|
|
370
401
|
if (!m || m.status !== "complete" || !isHexData(m.attestation) || !isHexData(m.message)) return null;
|
|
371
402
|
if (m.decodedMessage?.destinationDomain !== void 0 && Number(m.decodedMessage.destinationDomain) !== parsed.dst.domain) {
|
|
372
|
-
throw
|
|
403
|
+
throw (0, import_errors.refusal)("recipient_mismatch", "cctp: attested message is for another destination domain");
|
|
373
404
|
}
|
|
374
405
|
if (m.decodedMessage?.sourceDomain !== void 0 && Number(m.decodedMessage.sourceDomain) !== parsed.src.domain) {
|
|
375
|
-
throw
|
|
406
|
+
throw (0, import_errors.refusal)("policy_refused", "cctp: attested message is for another source domain");
|
|
376
407
|
}
|
|
377
408
|
const exp = m.decodedMessage?.decodedMessageBody?.expirationBlock;
|
|
378
409
|
const c = client(parsed.dst.caip2);
|
|
@@ -399,24 +430,26 @@ function cctpProvider(config = {}) {
|
|
|
399
430
|
}
|
|
400
431
|
};
|
|
401
432
|
}
|
|
433
|
+
var notes = (0, import_errors.refusalNotes)();
|
|
434
|
+
var why = (text, reason) => notes.note(text, reason);
|
|
402
435
|
function cctpVerifyQuote(params, quote) {
|
|
403
436
|
const src = Object.prototype.hasOwnProperty.call(CCTP_DOMAINS, params.sourceChain) ? CCTP_DOMAINS[params.sourceChain] : void 0;
|
|
404
437
|
const dst = Object.prototype.hasOwnProperty.call(CCTP_DOMAINS, params.destChain) ? CCTP_DOMAINS[params.destChain] : void 0;
|
|
405
|
-
if (!src || !dst || src === dst) return "not a CCTP route between two domains";
|
|
406
|
-
if (params.sourceToken.toUpperCase() !== "USDC" || !(same(params.destToken, dst.usdc) || params.destToken.toUpperCase() === "USDC")) return "not USDC to USDC";
|
|
438
|
+
if (!src || !dst || src === dst) return why("not a CCTP route between two domains", "unsupported_pair");
|
|
439
|
+
if (params.sourceToken.toUpperCase() !== "USDC" || !(same(params.destToken, dst.usdc) || params.destToken.toUpperCase() === "USDC")) return why("not USDC to USDC", "unsupported_pair");
|
|
407
440
|
const tx = quote.txRequest;
|
|
408
|
-
if (!tx?.data || !tx.to || tx.serializedTx !== void 0) return "the quote carries no TokenMessenger call";
|
|
409
|
-
if (!same(tx.to, src.tokenMessenger)) return `the call targets ${tx.to}, not the TokenMessengerV2
|
|
410
|
-
if (BigInt(tx.value ?? "0") !== 0n) return "a burn attaches no value";
|
|
411
|
-
if (!tx.approvalAddress || !same(tx.approvalAddress, src.tokenMessenger)) return "the burn approves another spender than the TokenMessengerV2";
|
|
412
|
-
if (tx.chainId !== void 0 && tx.chainId !== src.chainId) return `the call is for chain ${tx.chainId}, not ${src.chainId}
|
|
441
|
+
if (!tx?.data || !tx.to || tx.serializedTx !== void 0) return why("the quote carries no TokenMessenger call", "policy_refused");
|
|
442
|
+
if (!same(tx.to, src.tokenMessenger)) return why(`the call targets ${tx.to}, not the TokenMessengerV2`, "vault_mismatch");
|
|
443
|
+
if (BigInt(tx.value ?? "0") !== 0n) return why("a burn attaches no value", "policy_refused");
|
|
444
|
+
if (!tx.approvalAddress || !same(tx.approvalAddress, src.tokenMessenger)) return why("the burn approves another spender than the TokenMessengerV2", "vault_mismatch");
|
|
445
|
+
if (tx.chainId !== void 0 && tx.chainId !== src.chainId) return why(`the call is for chain ${tx.chainId}, not ${src.chainId}`, "policy_refused");
|
|
413
446
|
let args;
|
|
414
447
|
try {
|
|
415
448
|
const d2 = (0, import_viem.decodeFunctionData)({ abi: TOKEN_MESSENGER_ABI, data: tx.data });
|
|
416
|
-
if (d2.functionName !== "depositForBurn") return `${d2.functionName} is not depositForBurn
|
|
449
|
+
if (d2.functionName !== "depositForBurn") return why(`${d2.functionName} is not depositForBurn`, "policy_refused");
|
|
417
450
|
args = d2.args;
|
|
418
451
|
} catch {
|
|
419
|
-
return "the call is not depositForBurn";
|
|
452
|
+
return why("the call is not depositForBurn", "policy_refused");
|
|
420
453
|
}
|
|
421
454
|
const [amount, domain, mintRecipient, burnToken, caller, maxFee, threshold] = args;
|
|
422
455
|
let amountIn, floor;
|
|
@@ -425,27 +458,28 @@ function cctpVerifyQuote(params, quote) {
|
|
|
425
458
|
floor = BigInt(quote.minDestAmount);
|
|
426
459
|
if (params.minAmountOut !== void 0 && BigInt(params.minAmountOut) > floor) floor = BigInt(params.minAmountOut);
|
|
427
460
|
} catch {
|
|
428
|
-
return "the request does not name amounts";
|
|
461
|
+
return why("the request does not name amounts", "upstream_unavailable");
|
|
429
462
|
}
|
|
430
|
-
if (amount !== amountIn || BigInt(quote.sourceAmount) !== amountIn) return `the burn moves ${amount}, not the ${amountIn} input
|
|
431
|
-
if (domain !== dst.domain) return `the burn mints on domain ${domain}, not ${dst.name} (${dst.domain})
|
|
463
|
+
if (amount !== amountIn || BigInt(quote.sourceAmount) !== amountIn) return why(`the burn moves ${amount}, not the ${amountIn} input`, "policy_refused");
|
|
464
|
+
if (domain !== dst.domain) return why(`the burn mints on domain ${domain}, not ${dst.name} (${dst.domain})`, "recipient_mismatch");
|
|
432
465
|
if (params.destAddress || params.dry === false) {
|
|
433
466
|
if (!(0, import_viem.isAddress)(params.destAddress)) return "the recipient is not an EVM address";
|
|
434
|
-
if (mintRecipient.toLowerCase() !== (0, import_viem.pad)((0, import_viem.getAddress)(params.destAddress), { size: 32 }).toLowerCase()) return `the burn mints to ${mintRecipient}, not the recipient
|
|
467
|
+
if (mintRecipient.toLowerCase() !== (0, import_viem.pad)((0, import_viem.getAddress)(params.destAddress), { size: 32 }).toLowerCase()) return why(`the burn mints to ${mintRecipient}, not the recipient`, "recipient_mismatch");
|
|
435
468
|
}
|
|
436
|
-
if (!same(burnToken, src.usdc)) return `the burn spends ${burnToken}, not the source domain's USDC
|
|
437
|
-
if (caller !== import_viem.zeroHash) return "the burn names a destination caller";
|
|
438
|
-
if (threshold !== FINALITY_FAST && threshold !== FINALITY_STANDARD) return `finality threshold ${threshold} is neither Fast nor Standard
|
|
439
|
-
if (maxFee >= amount || amount - maxFee < floor) return `the burn's maxFee ${maxFee} leaves less than the ${floor} minimum
|
|
440
|
-
if ((/^([\s\S]+)~[0-9a-f]{32}$/.exec(quote.intentId)?.[1] ?? quote.intentId) !== `cctp:${src.domain}:${dst.domain}:${threshold}`) return "the intent id does not name this burn";
|
|
441
|
-
if (quote.providerData?.maxFee !== void 0 && quote.providerData.maxFee !== maxFee.toString()) return "the quoted maxFee is not the burn's";
|
|
469
|
+
if (!same(burnToken, src.usdc)) return why(`the burn spends ${burnToken}, not the source domain's USDC`, "policy_refused");
|
|
470
|
+
if (caller !== import_viem.zeroHash) return why("the burn names a destination caller", "policy_refused");
|
|
471
|
+
if (threshold !== FINALITY_FAST && threshold !== FINALITY_STANDARD) return why(`finality threshold ${threshold} is neither Fast nor Standard`, "policy_refused");
|
|
472
|
+
if (maxFee >= amount || amount - maxFee < floor) return why(`the burn's maxFee ${maxFee} leaves less than the ${floor} minimum`, "price_check_failed");
|
|
473
|
+
if ((/^([\s\S]+)~[0-9a-f]{32}$/.exec(quote.intentId)?.[1] ?? quote.intentId) !== `cctp:${src.domain}:${dst.domain}:${threshold}`) return why("the intent id does not name this burn", "policy_refused");
|
|
474
|
+
if (quote.providerData?.maxFee !== void 0 && quote.providerData.maxFee !== maxFee.toString()) return why("the quoted maxFee is not the burn's", "policy_refused");
|
|
442
475
|
return null;
|
|
443
476
|
}
|
|
444
477
|
var cctpPins = Object.freeze({
|
|
445
478
|
callTargets: (chain) => cctpMessengerFor(chain),
|
|
446
479
|
spenders: (chain) => cctpMessengerFor(chain),
|
|
447
480
|
claimTargets: cctpClaimTargets,
|
|
448
|
-
verifyQuote: cctpVerifyQuote
|
|
481
|
+
verifyQuote: cctpVerifyQuote,
|
|
482
|
+
reasonOf: notes.reasonOf
|
|
449
483
|
});
|
|
450
484
|
function cctpMessengerFor(chain) {
|
|
451
485
|
const d2 = Object.prototype.hasOwnProperty.call(CCTP_DOMAINS, chain) ? CCTP_DOMAINS[chain] : void 0;
|