@anywalletkit/protocol-swap2-cctp 0.1.4 → 0.1.6
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-I33XRHH3.js → chunk-L7BRMDBN.js} +4 -3
- package/dist/chunk-L7BRMDBN.js.map +1 -0
- package/dist/{chunk-TFQR5KQB.js → chunk-MX5VWQYN.js} +2 -2
- package/dist/index.cjs +3 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +2 -2
- package/dist/protocol.cjs +3 -2
- package/dist/protocol.cjs.map +1 -1
- package/dist/protocol.js +2 -2
- package/dist/provider.cjs +3 -2
- package/dist/provider.cjs.map +1 -1
- package/dist/provider.js +1 -1
- package/package.json +10 -7
- package/dist/chunk-I33XRHH3.js.map +0 -1
- /package/dist/{chunk-TFQR5KQB.js.map → chunk-MX5VWQYN.js.map} +0 -0
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
import { createPublicClient, encodeFunctionData, getAddress, http, isAddress, pad, parseAbi, zeroHash } from "viem";
|
|
15
15
|
import { ccAsset } from "@anywalletkit/swap2-assets";
|
|
16
16
|
import { timeoutSignal } from "@anywalletkit/protocol-swap2-core/util";
|
|
17
|
+
import { bigintToNumber } from "@anywalletkit/core";
|
|
17
18
|
var TOKEN_MESSENGER_ABI = parseAbi([
|
|
18
19
|
"function depositForBurn(uint256 amount, uint32 destinationDomain, bytes32 mintRecipient, address burnToken, bytes32 destinationCaller, uint256 maxFee, uint32 minFinalityThreshold)",
|
|
19
20
|
"function localMessageTransmitter() view returns (address)"
|
|
@@ -141,7 +142,7 @@ function cctpProvider(config = {}) {
|
|
|
141
142
|
let fastOk = !!fast;
|
|
142
143
|
if (fastOk) {
|
|
143
144
|
const allowance = await getJson("/v2/fastBurn/USDC/allowance", signal).catch(() => null);
|
|
144
|
-
if (typeof allowance?.allowance === "number" && allowance.allowance * 1e6 <
|
|
145
|
+
if (typeof allowance?.allowance === "number" && allowance.allowance * 1e6 < bigintToNumber(amount)) fastOk = false;
|
|
145
146
|
}
|
|
146
147
|
if (fastOk) {
|
|
147
148
|
threshold = FINALITY_FAST;
|
|
@@ -180,7 +181,7 @@ function cctpProvider(config = {}) {
|
|
|
180
181
|
sourceAmount: amount.toString(),
|
|
181
182
|
destAmount: out.toString(),
|
|
182
183
|
minDestAmount: out.toString(),
|
|
183
|
-
feeUsd:
|
|
184
|
+
feeUsd: bigintToNumber(maxFee) / 1e6,
|
|
184
185
|
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)` }] : [],
|
|
185
186
|
etaSeconds: eta,
|
|
186
187
|
reliability: 0.99,
|
|
@@ -298,4 +299,4 @@ function cctpProvider(config = {}) {
|
|
|
298
299
|
export {
|
|
299
300
|
cctpProvider
|
|
300
301
|
};
|
|
301
|
-
//# sourceMappingURL=chunk-
|
|
302
|
+
//# sourceMappingURL=chunk-L7BRMDBN.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/provider.ts"],"sourcesContent":["import {createPublicClient, 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`) so the status reaches \"completed\" by itself.\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\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)}) : 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 async function minted(dst: CctpDomain, nonce: Hex): Promise<boolean | null> {\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 null;\n }\n }\n\n return {\n name: \"cctp\",\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 const recipient = params.destAddress || EVM_PLACEHOLDER;\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 const done = isHexData(nonce) && nonce.length === 66 ? await minted(parsed.dst, nonce) : null;\n if (done) return {state: \"completed\", claim: {...claim, ready: false}, ...(ref.destTxHash ? {destTxHash: ref.destTxHash} : {})};\n // No destination RPC: a recorded claim hash is the best evidence we have.\n if (done === null && ref.destTxHash) return {state: \"completed\", destTxHash: ref.destTxHash, claim: {...claim, ready: false}};\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"],"mappings":"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","names":[]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
cctpProvider
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-L7BRMDBN.js";
|
|
4
4
|
import {
|
|
5
5
|
cctp
|
|
6
6
|
} from "./chunk-ZR5XR5RO.js";
|
|
@@ -24,4 +24,4 @@ var CctpSwap2Protocol = class extends SingleProviderSwap2 {
|
|
|
24
24
|
export {
|
|
25
25
|
CctpSwap2Protocol
|
|
26
26
|
};
|
|
27
|
-
//# sourceMappingURL=chunk-
|
|
27
|
+
//# sourceMappingURL=chunk-MX5VWQYN.js.map
|
package/dist/index.cjs
CHANGED
|
@@ -117,6 +117,7 @@ function describeCctpActivity(tx, ctx) {
|
|
|
117
117
|
// src/provider.ts
|
|
118
118
|
var import_swap2_assets = require("@anywalletkit/swap2-assets");
|
|
119
119
|
var import_util2 = require("@anywalletkit/protocol-swap2-core/util");
|
|
120
|
+
var import_core = require("@anywalletkit/core");
|
|
120
121
|
var TOKEN_MESSENGER_ABI = (0, import_viem.parseAbi)([
|
|
121
122
|
"function depositForBurn(uint256 amount, uint32 destinationDomain, bytes32 mintRecipient, address burnToken, bytes32 destinationCaller, uint256 maxFee, uint32 minFinalityThreshold)",
|
|
122
123
|
"function localMessageTransmitter() view returns (address)"
|
|
@@ -244,7 +245,7 @@ function cctpProvider(config = {}) {
|
|
|
244
245
|
let fastOk = !!fast;
|
|
245
246
|
if (fastOk) {
|
|
246
247
|
const allowance = await getJson("/v2/fastBurn/USDC/allowance", signal).catch(() => null);
|
|
247
|
-
if (typeof allowance?.allowance === "number" && allowance.allowance * 1e6 <
|
|
248
|
+
if (typeof allowance?.allowance === "number" && allowance.allowance * 1e6 < (0, import_core.bigintToNumber)(amount)) fastOk = false;
|
|
248
249
|
}
|
|
249
250
|
if (fastOk) {
|
|
250
251
|
threshold = FINALITY_FAST;
|
|
@@ -283,7 +284,7 @@ function cctpProvider(config = {}) {
|
|
|
283
284
|
sourceAmount: amount.toString(),
|
|
284
285
|
destAmount: out.toString(),
|
|
285
286
|
minDestAmount: out.toString(),
|
|
286
|
-
feeUsd:
|
|
287
|
+
feeUsd: (0, import_core.bigintToNumber)(maxFee) / 1e6,
|
|
287
288
|
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)` }] : [],
|
|
288
289
|
etaSeconds: eta,
|
|
289
290
|
reliability: 0.99,
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/config.ts","../src/provider.ts","../src/activity.ts","../src/protocol.ts"],"sourcesContent":["export * from \"./config.js\";\nexport * from \"./provider.js\";\nexport {CctpSwap2Protocol, type CctpSwap2Config} from \"./protocol.js\";\nexport {CctpSwap2Protocol as default} from \"./protocol.js\";\nexport * from \"./activity.js\";\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 {createPublicClient, 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\";\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`) so the status reaches \"completed\" by itself.\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\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)}) : 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 async function minted(dst: CctpDomain, nonce: Hex): Promise<boolean | null> {\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 null;\n }\n }\n\n return {\n name: \"cctp\",\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 const recipient = params.destAddress || EVM_PLACEHOLDER;\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 < Number(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: Number(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 const done = isHexData(nonce) && nonce.length === 66 ? await minted(parsed.dst, nonce) : null;\n if (done) return {state: \"completed\", claim: {...claim, ready: false}, ...(ref.destTxHash ? {destTxHash: ref.destTxHash} : {})};\n // No destination RPC: a recorded claim hash is the best evidence we have.\n if (done === null && ref.destTxHash) return {state: \"completed\", destTxHash: ref.destTxHash, claim: {...claim, ready: false}};\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 * 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","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"],"mappings":"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","names":["import_util"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/config.ts","../src/provider.ts","../src/activity.ts","../src/protocol.ts"],"sourcesContent":["export * from \"./config.js\";\nexport * from \"./provider.js\";\nexport {CctpSwap2Protocol, type CctpSwap2Config} from \"./protocol.js\";\nexport {CctpSwap2Protocol as default} from \"./protocol.js\";\nexport * from \"./activity.js\";\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 {createPublicClient, 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`) so the status reaches \"completed\" by itself.\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\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)}) : 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 async function minted(dst: CctpDomain, nonce: Hex): Promise<boolean | null> {\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 null;\n }\n }\n\n return {\n name: \"cctp\",\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 const recipient = params.destAddress || EVM_PLACEHOLDER;\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 const done = isHexData(nonce) && nonce.length === 66 ? await minted(parsed.dst, nonce) : null;\n if (done) return {state: \"completed\", claim: {...claim, ready: false}, ...(ref.destTxHash ? {destTxHash: ref.destTxHash} : {})};\n // No destination RPC: a recorded claim hash is the best evidence we have.\n if (done === null && ref.destTxHash) return {state: \"completed\", destTxHash: ref.destTxHash, claim: {...claim, ready: false}};\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 * 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","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"],"mappings":"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","names":["import_util"]}
|
package/dist/index.js
CHANGED
package/dist/protocol.cjs
CHANGED
|
@@ -102,6 +102,7 @@ function describeCctpActivity(tx, ctx) {
|
|
|
102
102
|
// src/provider.ts
|
|
103
103
|
var import_swap2_assets = require("@anywalletkit/swap2-assets");
|
|
104
104
|
var import_util2 = require("@anywalletkit/protocol-swap2-core/util");
|
|
105
|
+
var import_core = require("@anywalletkit/core");
|
|
105
106
|
var TOKEN_MESSENGER_ABI = (0, import_viem.parseAbi)([
|
|
106
107
|
"function depositForBurn(uint256 amount, uint32 destinationDomain, bytes32 mintRecipient, address burnToken, bytes32 destinationCaller, uint256 maxFee, uint32 minFinalityThreshold)",
|
|
107
108
|
"function localMessageTransmitter() view returns (address)"
|
|
@@ -229,7 +230,7 @@ function cctpProvider(config = {}) {
|
|
|
229
230
|
let fastOk = !!fast;
|
|
230
231
|
if (fastOk) {
|
|
231
232
|
const allowance = await getJson("/v2/fastBurn/USDC/allowance", signal).catch(() => null);
|
|
232
|
-
if (typeof allowance?.allowance === "number" && allowance.allowance * 1e6 <
|
|
233
|
+
if (typeof allowance?.allowance === "number" && allowance.allowance * 1e6 < (0, import_core.bigintToNumber)(amount)) fastOk = false;
|
|
233
234
|
}
|
|
234
235
|
if (fastOk) {
|
|
235
236
|
threshold = FINALITY_FAST;
|
|
@@ -268,7 +269,7 @@ function cctpProvider(config = {}) {
|
|
|
268
269
|
sourceAmount: amount.toString(),
|
|
269
270
|
destAmount: out.toString(),
|
|
270
271
|
minDestAmount: out.toString(),
|
|
271
|
-
feeUsd:
|
|
272
|
+
feeUsd: (0, import_core.bigintToNumber)(maxFee) / 1e6,
|
|
272
273
|
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)` }] : [],
|
|
273
274
|
etaSeconds: eta,
|
|
274
275
|
reliability: 0.99,
|
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 {createPublicClient, 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\";\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`) so the status reaches \"completed\" by itself.\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\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)}) : 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 async function minted(dst: CctpDomain, nonce: Hex): Promise<boolean | null> {\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 null;\n }\n }\n\n return {\n name: \"cctp\",\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 const recipient = params.destAddress || EVM_PLACEHOLDER;\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 < Number(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: Number(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 const done = isHexData(nonce) && nonce.length === 66 ? await minted(parsed.dst, nonce) : null;\n if (done) return {state: \"completed\", claim: {...claim, ready: false}, ...(ref.destTxHash ? {destTxHash: ref.destTxHash} : {})};\n // No destination RPC: a recorded claim hash is the best evidence we have.\n if (done === null && ref.destTxHash) return {state: \"completed\", destTxHash: ref.destTxHash, claim: {...claim, ready: false}};\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 * 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"]}
|
|
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 {createPublicClient, 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`) so the status reaches \"completed\" by itself.\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\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)}) : 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 async function minted(dst: CctpDomain, nonce: Hex): Promise<boolean | null> {\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 null;\n }\n }\n\n return {\n name: \"cctp\",\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 const recipient = params.destAddress || EVM_PLACEHOLDER;\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 const done = isHexData(nonce) && nonce.length === 66 ? await minted(parsed.dst, nonce) : null;\n if (done) return {state: \"completed\", claim: {...claim, ready: false}, ...(ref.destTxHash ? {destTxHash: ref.destTxHash} : {})};\n // No destination RPC: a recorded claim hash is the best evidence we have.\n if (done === null && ref.destTxHash) return {state: \"completed\", destTxHash: ref.destTxHash, claim: {...claim, ready: false}};\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 * 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"]}
|
package/dist/protocol.js
CHANGED
package/dist/provider.cjs
CHANGED
|
@@ -101,6 +101,7 @@ function describeCctpActivity(tx, ctx) {
|
|
|
101
101
|
// src/provider.ts
|
|
102
102
|
var import_swap2_assets = require("@anywalletkit/swap2-assets");
|
|
103
103
|
var import_util2 = require("@anywalletkit/protocol-swap2-core/util");
|
|
104
|
+
var import_core = require("@anywalletkit/core");
|
|
104
105
|
var TOKEN_MESSENGER_ABI = (0, import_viem.parseAbi)([
|
|
105
106
|
"function depositForBurn(uint256 amount, uint32 destinationDomain, bytes32 mintRecipient, address burnToken, bytes32 destinationCaller, uint256 maxFee, uint32 minFinalityThreshold)",
|
|
106
107
|
"function localMessageTransmitter() view returns (address)"
|
|
@@ -228,7 +229,7 @@ function cctpProvider(config = {}) {
|
|
|
228
229
|
let fastOk = !!fast;
|
|
229
230
|
if (fastOk) {
|
|
230
231
|
const allowance = await getJson("/v2/fastBurn/USDC/allowance", signal).catch(() => null);
|
|
231
|
-
if (typeof allowance?.allowance === "number" && allowance.allowance * 1e6 <
|
|
232
|
+
if (typeof allowance?.allowance === "number" && allowance.allowance * 1e6 < (0, import_core.bigintToNumber)(amount)) fastOk = false;
|
|
232
233
|
}
|
|
233
234
|
if (fastOk) {
|
|
234
235
|
threshold = FINALITY_FAST;
|
|
@@ -267,7 +268,7 @@ function cctpProvider(config = {}) {
|
|
|
267
268
|
sourceAmount: amount.toString(),
|
|
268
269
|
destAmount: out.toString(),
|
|
269
270
|
minDestAmount: out.toString(),
|
|
270
|
-
feeUsd:
|
|
271
|
+
feeUsd: (0, import_core.bigintToNumber)(maxFee) / 1e6,
|
|
271
272
|
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)` }] : [],
|
|
272
273
|
etaSeconds: eta,
|
|
273
274
|
reliability: 0.99,
|
package/dist/provider.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/provider.ts","../src/activity.ts","../src/config.ts"],"sourcesContent":["import {createPublicClient, 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\";\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`) so the status reaches \"completed\" by itself.\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\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)}) : 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 async function minted(dst: CctpDomain, nonce: Hex): Promise<boolean | null> {\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 null;\n }\n }\n\n return {\n name: \"cctp\",\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 const recipient = params.destAddress || EVM_PLACEHOLDER;\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 < Number(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: Number(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 const done = isHexData(nonce) && nonce.length === 66 ? await minted(parsed.dst, nonce) : null;\n if (done) return {state: \"completed\", claim: {...claim, ready: false}, ...(ref.destTxHash ? {destTxHash: ref.destTxHash} : {})};\n // No destination RPC: a recorded claim hash is the best evidence we have.\n if (done === null && ref.destTxHash) return {state: \"completed\", destTxHash: ref.destTxHash, claim: {...claim, ready: false}};\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 * 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","// 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"],"mappings":"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","names":["import_util"]}
|
|
1
|
+
{"version":3,"sources":["../src/provider.ts","../src/activity.ts","../src/config.ts"],"sourcesContent":["import {createPublicClient, 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`) so the status reaches \"completed\" by itself.\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\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)}) : 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 async function minted(dst: CctpDomain, nonce: Hex): Promise<boolean | null> {\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 null;\n }\n }\n\n return {\n name: \"cctp\",\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 const recipient = params.destAddress || EVM_PLACEHOLDER;\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 const done = isHexData(nonce) && nonce.length === 66 ? await minted(parsed.dst, nonce) : null;\n if (done) return {state: \"completed\", claim: {...claim, ready: false}, ...(ref.destTxHash ? {destTxHash: ref.destTxHash} : {})};\n // No destination RPC: a recorded claim hash is the best evidence we have.\n if (done === null && ref.destTxHash) return {state: \"completed\", destTxHash: ref.destTxHash, claim: {...claim, ready: false}};\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 * 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","// 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"],"mappings":"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","names":["import_util"]}
|
package/dist/provider.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@anywalletkit/protocol-swap2-cctp",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.6",
|
|
4
4
|
"description": "Circle CCTP V2 for the swap2 engine: native USDC between EVM chains by burn-and-mint (Fast Transfer or Standard), attestation via Circle's Iris API, two-phase delivery with the user's own receiveMessage claim. Bound to Circle's documented contracts and native USDC per domain.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"homepage": "https://docs.anywallet.tech",
|
|
@@ -13,6 +13,9 @@
|
|
|
13
13
|
"directory": "packages/protocol-swap2-cctp"
|
|
14
14
|
},
|
|
15
15
|
"type": "module",
|
|
16
|
+
"engines": {
|
|
17
|
+
"node": ">=20"
|
|
18
|
+
},
|
|
16
19
|
"sideEffects": false,
|
|
17
20
|
"main": "./dist/index.cjs",
|
|
18
21
|
"module": "./dist/index.js",
|
|
@@ -47,17 +50,17 @@
|
|
|
47
50
|
],
|
|
48
51
|
"dependencies": {
|
|
49
52
|
"viem": "^2.57.2",
|
|
50
|
-
"@anywalletkit/protocol-swap2-core": "0.
|
|
51
|
-
"@anywalletkit/swap2-assets": "0.1.
|
|
53
|
+
"@anywalletkit/protocol-swap2-core": "0.4.1",
|
|
54
|
+
"@anywalletkit/swap2-assets": "0.1.5"
|
|
52
55
|
},
|
|
53
56
|
"peerDependencies": {
|
|
54
|
-
"@anywalletkit/core": "0.
|
|
57
|
+
"@anywalletkit/core": "0.4.1"
|
|
55
58
|
},
|
|
56
59
|
"devDependencies": {
|
|
57
60
|
"@types/node": "^22",
|
|
58
61
|
"vitest": "^5.0.3",
|
|
59
|
-
"@anywalletkit/core": "0.
|
|
60
|
-
"@anywalletkit/conformance": "0.
|
|
62
|
+
"@anywalletkit/core": "0.4.1",
|
|
63
|
+
"@anywalletkit/conformance": "0.4.1"
|
|
61
64
|
},
|
|
62
65
|
"keywords": [
|
|
63
66
|
"swap2",
|
|
@@ -76,7 +79,7 @@
|
|
|
76
79
|
"build": "tsup",
|
|
77
80
|
"typecheck": "tsc --noEmit",
|
|
78
81
|
"test": "vitest run",
|
|
79
|
-
"lint": "
|
|
82
|
+
"lint": "eslint src",
|
|
80
83
|
"verify:live": "node scripts/verify-live.mjs"
|
|
81
84
|
}
|
|
82
85
|
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/provider.ts"],"sourcesContent":["import {createPublicClient, 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\";\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`) so the status reaches \"completed\" by itself.\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\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)}) : 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 async function minted(dst: CctpDomain, nonce: Hex): Promise<boolean | null> {\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 null;\n }\n }\n\n return {\n name: \"cctp\",\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 const recipient = params.destAddress || EVM_PLACEHOLDER;\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 < Number(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: Number(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 const done = isHexData(nonce) && nonce.length === 66 ? await minted(parsed.dst, nonce) : null;\n if (done) return {state: \"completed\", claim: {...claim, ready: false}, ...(ref.destTxHash ? {destTxHash: ref.destTxHash} : {})};\n // No destination RPC: a recorded claim hash is the best evidence we have.\n if (done === null && ref.destTxHash) return {state: \"completed\", destTxHash: ref.destTxHash, claim: {...claim, ready: false}};\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"],"mappings":"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","names":[]}
|
|
File without changes
|