@anywalletkit/protocol-swap2-router 0.4.0 → 0.5.0
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-CVLYC637.js → chunk-R47JJEOO.js} +2 -1
- package/dist/chunk-R47JJEOO.js.map +1 -0
- package/dist/{chunk-4WSAFBPT.js → chunk-S5DBSOWP.js} +2 -2
- package/dist/index.cjs +1 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +2 -2
- package/dist/router.cjs +1 -0
- package/dist/router.cjs.map +1 -1
- package/dist/router.js +1 -1
- package/dist/swap2/router.cjs +1 -0
- package/dist/swap2/router.cjs.map +1 -1
- package/dist/swap2/router.js +2 -2
- package/package.json +2 -2
- package/dist/chunk-CVLYC637.js.map +0 -1
- /package/dist/{chunk-4WSAFBPT.js.map → chunk-S5DBSOWP.js.map} +0 -0
|
@@ -65,6 +65,7 @@ var CrossChainRouter = class _CrossChainRouter {
|
|
|
65
65
|
// remote provider for a local one and checked its calldata against the backend's own addresses.
|
|
66
66
|
...provider.remote === true ? { remote: true } : {},
|
|
67
67
|
...provider.verifiesBuilds === true ? { verifiesBuilds: true } : {},
|
|
68
|
+
...provider.verifiesQuotes === true ? { verifiesQuotes: true } : {},
|
|
68
69
|
...provider.depositAddressRoutes === true ? { depositAddressRoutes: true } : {},
|
|
69
70
|
...provider.callTargets ? { callTargets: provider.callTargets.bind(provider) } : {},
|
|
70
71
|
...provider.spenders ? { spenders: provider.spenders.bind(provider) } : {},
|
|
@@ -309,4 +310,4 @@ function fraction(num, den) {
|
|
|
309
310
|
export {
|
|
310
311
|
CrossChainRouter
|
|
311
312
|
};
|
|
312
|
-
//# sourceMappingURL=chunk-
|
|
313
|
+
//# sourceMappingURL=chunk-R47JJEOO.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/router.ts"],"sourcesContent":["/**\n * The auction engine of the optional aggregator: routes a cross-chain delivery\n * over whichever providers the caller installed and passed in. Protocol\n * modules never need it — each one runs standalone on @anywalletkit/protocol-swap2-core.\n */\nimport type {\n CrossChainProvider,\n IntentRef,\n IntentStatus,\n Quote,\n QuoteParams,\n RoutedQuote,\n ScoreWeights,\n} from \"@anywalletkit/protocol-swap2-core/types\";\nimport {remotePinRefusal, validQuote} from \"@anywalletkit/protocol-swap2-core/validate\";\nimport type {ActivityItem, ChainTx, DescribeActivityContext} from \"@anywalletkit/core\";\nimport {bigintToNumber} from \"@anywalletkit/core\";\n\nconst DEFAULT_WEIGHTS: ScoreWeights = {price: 0.6, speed: 0.3, reliability: 0.1};\n/** Quotes within 0.2% of the best net value count as the same price. */\nconst DEFAULT_TIE_BAND = 0.002;\n\nexport interface RouterOptions {\n /**\n * \"price:0.6,speed:0.3,reliability:0.1\" — how quotes inside the tie band\n * (same price, within `tieBand`) are ordered. Price itself always leads.\n */\n weights?: string;\n /**\n * What a quote is worth to the user in USD: its guaranteed output minus what\n * the route charges on top (a native bridge fee, the source gas). Return null\n * when it cannot be priced — the auction then compares guaranteed outputs.\n * `usdValue(prices)` builds one from a symbol → USD price map.\n */\n valueUsd?: (quote: Quote, params: QuoteParams) => number | null;\n /** Fraction of the best net value inside which quotes tie on price (default 0.002). */\n tieBand?: number;\n}\n\n/** A validated quote with its place in the auction. */\nexport interface RankedQuote extends Quote {\n /** Net USD value (`valueUsd`), or null when the auction compared raw outputs. */\n netValueUsd: number | null;\n /** This quote's value against the best one, 0..1 (1 = the best price). */\n relativeValue: number;\n /** \"best\": the pick (best price; faster/more reliable among equal prices). \"fastest\": the lowest ETA. */\n tags: (\"best\" | \"fastest\")[];\n}\n\n/** Every validated route for one request, ranked by value. */\nexport interface RouteSet {\n /** Every validated route, best first. */\n quotes: RankedQuote[];\n /** Most delivered value (net of fees when priced) within the tie band. */\n best: RankedQuote;\n /** Lowest ETA. */\n fastest: RankedQuote;\n /** Providers still quoting (only non-empty in progressive `onUpdate` snapshots). */\n pending: string[];\n /** Why the venues that sat out did (same as `lastRejections`). */\n rejections: string[];\n}\n// LI.FI's /quote routinely takes ~3.5s (it builds executable calldata) — 4s\n// raced it out of every round. All providers still run in parallel.\nconst QUOTE_TIMEOUT_MS = 8000;\n/** Pinned single-venue (execution) budget — see the comment at the call site. */\nconst SOLO_QUOTE_TIMEOUT_MS = 25_000;\n\nfunction parseWeights(spec?: string): ScoreWeights {\n if (!spec) return DEFAULT_WEIGHTS;\n const w = {...DEFAULT_WEIGHTS};\n for (const part of spec.split(\",\")) {\n const [k, v] = part.split(\":\");\n const n = Number(v);\n if ((k === \"price\" || k === \"speed\" || k === \"reliability\") && Number.isFinite(n)) {\n w[k] = Math.max(0, n);\n }\n }\n return w;\n}\n\nasync function withTimeout<T>(p: Promise<T>, ms: number): Promise<T | null> {\n return new Promise((resolve, reject) => {\n // Timeouts and failures must REJECT: the old `() => resolve(null)` arm\n // swallowed every provider error — including forwarded venue refusals —\n // into a null indistinguishable from \"no route\", which made execution\n // failures undiagnosable from the surface (the '(c2)' hunt of 2026-08-31).\n const timer = setTimeout(() => reject(new Error(`quote timed out after ${ms}ms`)), ms);\n p.then(resolve, reject).finally(() => clearTimeout(timer));\n });\n}\n\n/**\n * Routes a cross-chain delivery over pluggable providers: queries all that\n * support the route in parallel (with a timeout so a slow provider can't block),\n * normalizes their quotes, scores by configurable weights, and returns the best\n * tagged with `routeScore`. A failed/slow provider simply doesn't participate.\n */\nexport class CrossChainRouter {\n private readonly providers: CrossChainProvider[];\n /** Why the venues of the LAST getBestQuote call sat out — for error surfaces. */\n private _lastRejections: string[] = [];\n /** Why providers sat out the last auction, one line each. */\n get lastRejections(): readonly string[] {\n return this._lastRejections;\n }\n private readonly weights: ScoreWeights;\n private readonly valueUsd: RouterOptions[\"valueUsd\"];\n private readonly tieBand: number;\n private readonly options: RouterOptions;\n\n constructor(providers: CrossChainProvider[], options?: string | RouterOptions) {\n const opts: RouterOptions = typeof options === \"string\" ? {weights: options} : {...(options ?? {})};\n if (opts.tieBand !== undefined && !(Number.isFinite(opts.tieBand) && opts.tieBand >= 0 && opts.tieBand < 1)) {\n throw new Error(\"cross-chain router: tieBand must be a fraction in [0, 1)\");\n }\n const names = new Set<string>();\n for (const provider of providers) {\n if (typeof provider.name !== \"string\" || !/^[A-Za-z0-9_-]+$/.test(provider.name) || names.has(provider.name)) {\n throw new Error(`cross-chain router: invalid or duplicate provider name '${String(provider.name)}'`);\n }\n names.add(provider.name);\n }\n // Snapshot the dispatch surface. A caller mutating provider.name or method\n // properties after construction must not redirect quote→build/status.\n this.providers = providers.map((provider) => ({\n name: provider.name,\n enabled: provider.enabled.bind(provider),\n supportsRoute: provider.supportsRoute.bind(provider),\n getQuote: provider.getQuote.bind(provider),\n buildDeposit: provider.buildDeposit.bind(provider),\n trackIntent: provider.trackIntent.bind(provider),\n ...(provider.preflightDeposit ? {preflightDeposit: provider.preflightDeposit.bind(provider)} : {}),\n ...(provider.notifyDeposit ? {notifyDeposit: provider.notifyDeposit.bind(provider)} : {}),\n ...(provider.registerSignedOrder ? {registerSignedOrder: provider.registerSignedOrder.bind(provider)} : {}),\n // Two-phase routes (CCTP): the destination claim. Missing here, the engine\n // and the server both reported \"provider 'cctp' has no claim step\" (2026-10-13).\n ...(provider.buildClaim ? {buildClaim: provider.buildClaim.bind(provider)} : {}),\n ...(provider.claimTargets ? {claimTargets: provider.claimTargets.bind(provider)} : {}),\n // A remote stub's marker and the app's pins (scan 2026-10-27 modules, F8/F9/F16): dropped here, the engine took a\n // remote provider for a local one and checked its calldata against the backend's own addresses.\n ...(provider.remote === true ? {remote: true} : {}),\n ...(provider.verifiesBuilds === true ? {verifiesBuilds: true} : {}),\n ...(provider.verifiesQuotes === true ? {verifiesQuotes: true} : {}),\n ...(provider.depositAddressRoutes === true ? {depositAddressRoutes: true} : {}),\n ...(provider.callTargets ? {callTargets: provider.callTargets.bind(provider)} : {}),\n ...(provider.spenders ? {spenders: provider.spenders.bind(provider)} : {}),\n ...(provider.close ? {close: provider.close.bind(provider)} : {}),\n ...(provider.supportsChain ? {supportsChain: provider.supportsChain.bind(provider)} : {}),\n ...(provider.supportsChainPair ? {supportsChainPair: provider.supportsChainPair.bind(provider)} : {}),\n ...(provider.describeActivity ? {describeActivity: provider.describeActivity.bind(provider)} : {}),\n ...(provider.supportsSameChain !== undefined ? {supportsSameChain: provider.supportsSameChain} : {}),\n }));\n this.weights = parseWeights(opts.weights);\n this.valueUsd = opts.valueUsd;\n this.tieBand = opts.tieBand ?? DEFAULT_TIE_BAND;\n this.options = opts;\n }\n\n /** The same auction restricted to one provider — to execute the route a user picked. */\n only(name: string): CrossChainRouter {\n const provider = this.getProvider(name);\n if (!provider) throw new Error(`cross-chain router: provider '${name}' is not registered`);\n return new CrossChainRouter([provider], this.options);\n }\n\n /**\n * Activity recognition across the installed providers: the first one that\n * claims the transaction describes it. Null when none does (or none is held).\n */\n describeActivity(tx: ChainTx, ctx: DescribeActivityContext): ActivityItem | null {\n for (const provider of this.providers) {\n const item = provider.describeActivity?.(tx, ctx);\n if (item) return item;\n }\n return null;\n }\n\n /** A provider by name. */\n getProvider(name: string): CrossChainProvider | undefined {\n return this.providers.find((p) => p.name === name);\n }\n\n /** True when a provider of that name is installed. */\n hasProvider(name: string): boolean {\n return this.providers.some((p) => p.name === name);\n }\n\n /** True when that provider is installed and enabled. */\n hasEnabledProvider(name: string): boolean {\n return this.providers.some((p) => {\n try { return p.name === name && p.enabled(); } catch { return false; }\n });\n }\n\n /** True when any enabled provider declares the chain. */\n supportsChain(caip2: string): boolean {\n return this.providers.some((p) => {\n try { return p.enabled() && !!p.supportsChain?.(caip2); } catch { return false; }\n });\n }\n\n /** True when any enabled provider declares the chain pair. */\n supportsChainPair(fromChain: string, toChain: string): boolean {\n return this.providers.some((p) => {\n try {\n return p.enabled() && (p.supportsChainPair?.(fromChain, toChain) ?? false);\n } catch { return false; }\n });\n }\n\n /**\n * The auction's pick: the best price (net of native fees and gas when\n * `valueUsd` is set; faster, then more reliable, among equal prices), or\n * the fastest route with `prefer: \"fastest\"`.\n */\n async getBestQuote(\n params: QuoteParams,\n options?: {requireImmediateExecution?: boolean; prefer?: \"best\" | \"fastest\"},\n ): Promise<RoutedQuote | null> {\n const set = await this.getQuotes(params, options);\n if (!set) return null;\n const pick = options?.prefer === \"fastest\" ? set.fastest : set.best;\n const {netValueUsd: _n, relativeValue: _r, tags: _t, ...quote} = pick;\n return {\n ...quote,\n routeScore: {\n score: pick.relativeValue,\n weights: this.weights,\n candidates: set.quotes.map((q) => ({\n provider: q.provider,\n sourceAmount: q.sourceAmount,\n etaSeconds: q.etaSeconds,\n score: q.relativeValue,\n minDestAmount: q.minDestAmount,\n netValueUsd: q.netValueUsd,\n })),\n },\n };\n }\n\n /**\n * Every validated route, ranked — for a route picker that shows the best and\n * the fastest and lets the user choose. Providers run in parallel; with\n * `onUpdate` each one that answers re-publishes the ranked set at once (the\n * first price shows in the time of the fastest venue, not the slowest).\n */\n async getQuotes(\n params: QuoteParams,\n options?: {requireImmediateExecution?: boolean; onUpdate?: (set: RouteSet) => void},\n ): Promise<RouteSet | null> {\n // A public engine caller — or one provider running in the same auction —\n // must not be able to rewrite another provider's request while async quote\n // work is in flight. QuoteParams is intentionally flat, so a frozen copy is\n // a complete execution snapshot.\n const rejections: string[] = [];\n this._lastRejections = rejections;\n const snapshot = Object.freeze({...params});\n const from = Object.freeze({chain: snapshot.sourceChain, token: snapshot.sourceToken});\n const to = Object.freeze({chain: snapshot.destChain, token: snapshot.destToken});\n // Only enabled (validated) providers that can serve the route participate.\n let eligible = this.providers.filter((p) => {\n try { return p.enabled() && p.supportsRoute(from, to); } catch { return false; }\n });\n if (snapshot.sourceChain === snapshot.destChain) {\n eligible = eligible.filter((p) => p.supportsSameChain === true);\n }\n if (eligible.length === 0) return null;\n\n // The short timeout protects the AUCTION — one slow venue must not hold\n // the others hostage. With a single eligible provider (a pinned execution\n // re-quote) there is nobody to protect, and a live deposit-creating quote\n // legitimately takes longer than a dry one (serverless hop + upstream\n // retries) — starving it surfaced as a terminal \"no route\" on execution.\n const timeoutMs = eligible.length === 1 ? SOLO_QUOTE_TIMEOUT_MS : QUOTE_TIMEOUT_MS;\n // Each venue names its own refusal (per call, so concurrent quotes cannot race).\n const refusals: (string | undefined)[] = [];\n const accepted: Quote[] = [];\n const pending = new Set(eligible.map((p) => p.name));\n const publish = () => {\n if (!options?.onUpdate || accepted.length === 0) return;\n const set = this.rank(accepted, snapshot, [...pending], rejections);\n try { options.onUpdate(set); } catch { /* an observer must not break the auction */ }\n };\n await Promise.all(eligible.map(async (p, i) => {\n const controller = new AbortController();\n const own = Object.freeze({...snapshot, onRefusal: (reason: string) => {\n refusals[i] ??= reason.startsWith(`${p.name}:`) ? reason : `${p.name}: ${reason}`;\n try { snapshot.onRefusal?.(reason); } catch { /* diagnostics only */ }\n }});\n let q: Quote | null = null;\n try {\n q = await withTimeout(p.getQuote(own, controller.signal), timeoutMs);\n if (!q) {\n // A provider RETURNING null (vs throwing) was the one silent path\n // left — record it so the surfaced no-route error names the venue.\n rejections.push(refusals[i] ?? `${p.name}: returned no quote`);\n } else if (!validQuote(q, snapshot, p.name)) {\n const reason = `${p.name}: rejected by validation (minDest=${q.minDestAmount} vs floor=${snapshot.minAmountOut ?? \"-\"}, validUntil=${q.validUntilMs}, now=${Date.now()})`;\n rejections.push(reason);\n console.warn(`swap2-router: ${reason}`);\n q = null;\n } else {\n // A remote stub's route that calls or approves an address the app did not pin: execution would refuse it.\n const unpinned = remotePinRefusal(p, q, snapshot.sourceChain);\n if (unpinned) {\n rejections.push(unpinned);\n console.warn(`swap2-router: ${unpinned}`);\n q = null;\n } else if (options?.requireImmediateExecution && !(q.depositAddress.length > 0 || q.txRequest !== undefined)) {\n // Legacy deposit-address screens cannot execute order-based quotes that\n // require a separate build/sign/register lifecycle.\n q = null;\n }\n }\n } catch (err) {\n // A failed venue sitting out silently is indistinguishable from \"no\n // route\" — record why (surfaced through lastRejections) and say it in\n // the console (same posture as onModuleSkipped).\n const reason = `${p.name}: ${err instanceof Error ? err.message.slice(0, 160) : String(err).slice(0, 160)}`;\n rejections.push(reason);\n console.warn(`swap2-router: quote failed — ${reason}`);\n q = null;\n } finally {\n controller.abort();\n }\n pending.delete(p.name);\n // Provider identity is an execution security boundary. Never trust the\n // provider field returned by an untrusted adapter; bind it to its slot.\n if (q) accepted.push({...q, provider: p.name});\n publish();\n }));\n if (accepted.length === 0) return null;\n return this.rank(accepted, snapshot, [], rejections);\n }\n\n /** Status from the named provider; `failed` when it is not installed. */\n async trackIntent(providerName: string, ref: IntentRef): Promise<IntentStatus> {\n const provider = this.getProvider(providerName);\n if (!provider) return {state: \"failed\"};\n return provider.trackIntent(ref);\n }\n\n /** Forward a source-broadcast notification to the intent's provider. */\n async notifyDeposit(providerName: string, intentId: string, txHash: string): Promise<void> {\n await this.getProvider(providerName)?.notifyDeposit?.(intentId, txHash);\n }\n\n /** Release every provider's resources. */\n close(): void {\n for (const provider of this.providers) provider.close?.();\n }\n\n /**\n * Price first: each quote's value is its net USD (`valueUsd`) — or, when any\n * quote cannot be priced, its guaranteed output — against the best one.\n * Quotes within `tieBand` of the best are the same price; among those the\n * weights order speed and reliability. A $0.01 edge no longer beats a route\n * that lands in seconds instead of twenty minutes, and a route that charges\n * a native bridge fee on top no longer wins on its gross output.\n */\n private rank(quotes: Quote[], params: QuoteParams, pending: string[], rejections: string[]): RouteSet {\n const usd = this.valueUsd ? quotes.map((q) => {\n try {\n const v = this.valueUsd!(q, params);\n return typeof v === \"number\" && Number.isFinite(v) ? v : null;\n } catch { return null; }\n }) : quotes.map(() => null);\n const priced = usd.every((v) => v !== null);\n let relative: number[];\n if (priced) {\n const values = usd as number[];\n const max = Math.max(...values);\n relative = values.map((v) => (max > 0 ? Math.max(0, v) / max : v >= max ? 1 : 0));\n } else {\n const outs = quotes.map((q) => BigInt(q.minDestAmount));\n const max = outs.reduce((a, b) => (b > a ? b : a));\n relative = outs.map((o) => fraction(o, max));\n }\n const ranked: RankedQuote[] = quotes.map((q, i) => ({\n ...q,\n netValueUsd: priced ? usd[i]! : null,\n relativeValue: relative[i]!,\n tags: [],\n }));\n\n const tier = ranked.filter((q) => q.relativeValue >= 1 - this.tieBand - 1e-12);\n const etas = tier.map((q) => q.etaSeconds);\n const minEta = Math.min(...etas);\n const maxEta = Math.max(...etas);\n const w = this.weights;\n const tieScore = (q: RankedQuote) =>\n w.price * q.relativeValue +\n w.speed * (maxEta === minEta ? 1 : (maxEta - q.etaSeconds) / (maxEta - minEta)) +\n w.reliability * q.reliability;\n const best = tier.reduce((a, b) => (tieScore(b) > tieScore(a) ? b : a));\n const fastest = ranked.reduce((a, b) =>\n b.etaSeconds < a.etaSeconds || (b.etaSeconds === a.etaSeconds && b.relativeValue > a.relativeValue) ? b : a);\n best.tags.push(\"best\");\n fastest.tags.push(\"fastest\");\n\n // The list reads top-down by value; the pick leads its price tier.\n ranked.sort((a, b) => (a === best ? -1 : b === best ? 1 : b.relativeValue - a.relativeValue || a.etaSeconds - b.etaSeconds));\n return {quotes: ranked, best, fastest, pending, rejections: [...rejections]};\n }\n}\n\n/** Ratio of two non-negative bigints as a 0..1 number. */\nfunction fraction(num: bigint, den: bigint): number {\n if (den === 0n) return 1;\n // scale to keep precision, then to float\n return bigintToNumber((num * 10_000n) / den) / 10_000;\n}\n"],"mappings":";AAcA,SAAQ,kBAAkB,kBAAiB;AAE3C,SAAQ,sBAAqB;AAE7B,IAAM,kBAAgC,EAAC,OAAO,KAAK,OAAO,KAAK,aAAa,IAAG;AAE/E,IAAM,mBAAmB;AA4CzB,IAAM,mBAAmB;AAEzB,IAAM,wBAAwB;AAE9B,SAAS,aAAa,MAA6B;AACjD,MAAI,CAAC,KAAM,QAAO;AAClB,QAAM,IAAI,EAAC,GAAG,gBAAe;AAC7B,aAAW,QAAQ,KAAK,MAAM,GAAG,GAAG;AAClC,UAAM,CAAC,GAAG,CAAC,IAAI,KAAK,MAAM,GAAG;AAC7B,UAAM,IAAI,OAAO,CAAC;AAClB,SAAK,MAAM,WAAW,MAAM,WAAW,MAAM,kBAAkB,OAAO,SAAS,CAAC,GAAG;AACjF,QAAE,CAAC,IAAI,KAAK,IAAI,GAAG,CAAC;AAAA,IACtB;AAAA,EACF;AACA,SAAO;AACT;AAEA,eAAe,YAAe,GAAe,IAA+B;AAC1E,SAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AAKtC,UAAM,QAAQ,WAAW,MAAM,OAAO,IAAI,MAAM,yBAAyB,EAAE,IAAI,CAAC,GAAG,EAAE;AACrF,MAAE,KAAK,SAAS,MAAM,EAAE,QAAQ,MAAM,aAAa,KAAK,CAAC;AAAA,EAC3D,CAAC;AACH;AAQO,IAAM,mBAAN,MAAM,kBAAiB;AAAA,EACX;AAAA;AAAA,EAET,kBAA4B,CAAC;AAAA;AAAA,EAErC,IAAI,iBAAoC;AACtC,WAAO,KAAK;AAAA,EACd;AAAA,EACiB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAEjB,YAAY,WAAiC,SAAkC;AAC7E,UAAM,OAAsB,OAAO,YAAY,WAAW,EAAC,SAAS,QAAO,IAAI,EAAC,GAAI,WAAW,CAAC,EAAE;AAClG,QAAI,KAAK,YAAY,UAAa,EAAE,OAAO,SAAS,KAAK,OAAO,KAAK,KAAK,WAAW,KAAK,KAAK,UAAU,IAAI;AAC3G,YAAM,IAAI,MAAM,0DAA0D;AAAA,IAC5E;AACA,UAAM,QAAQ,oBAAI,IAAY;AAC9B,eAAW,YAAY,WAAW;AAChC,UAAI,OAAO,SAAS,SAAS,YAAY,CAAC,mBAAmB,KAAK,SAAS,IAAI,KAAK,MAAM,IAAI,SAAS,IAAI,GAAG;AAC5G,cAAM,IAAI,MAAM,2DAA2D,OAAO,SAAS,IAAI,CAAC,GAAG;AAAA,MACrG;AACA,YAAM,IAAI,SAAS,IAAI;AAAA,IACzB;AAGA,SAAK,YAAY,UAAU,IAAI,CAAC,cAAc;AAAA,MAC5C,MAAM,SAAS;AAAA,MACf,SAAS,SAAS,QAAQ,KAAK,QAAQ;AAAA,MACvC,eAAe,SAAS,cAAc,KAAK,QAAQ;AAAA,MACnD,UAAU,SAAS,SAAS,KAAK,QAAQ;AAAA,MACzC,cAAc,SAAS,aAAa,KAAK,QAAQ;AAAA,MACjD,aAAa,SAAS,YAAY,KAAK,QAAQ;AAAA,MAC/C,GAAI,SAAS,mBAAmB,EAAC,kBAAkB,SAAS,iBAAiB,KAAK,QAAQ,EAAC,IAAI,CAAC;AAAA,MAChG,GAAI,SAAS,gBAAgB,EAAC,eAAe,SAAS,cAAc,KAAK,QAAQ,EAAC,IAAI,CAAC;AAAA,MACvF,GAAI,SAAS,sBAAsB,EAAC,qBAAqB,SAAS,oBAAoB,KAAK,QAAQ,EAAC,IAAI,CAAC;AAAA;AAAA;AAAA,MAGzG,GAAI,SAAS,aAAa,EAAC,YAAY,SAAS,WAAW,KAAK,QAAQ,EAAC,IAAI,CAAC;AAAA,MAC9E,GAAI,SAAS,eAAe,EAAC,cAAc,SAAS,aAAa,KAAK,QAAQ,EAAC,IAAI,CAAC;AAAA;AAAA;AAAA,MAGpF,GAAI,SAAS,WAAW,OAAO,EAAC,QAAQ,KAAI,IAAI,CAAC;AAAA,MACjD,GAAI,SAAS,mBAAmB,OAAO,EAAC,gBAAgB,KAAI,IAAI,CAAC;AAAA,MACjE,GAAI,SAAS,mBAAmB,OAAO,EAAC,gBAAgB,KAAI,IAAI,CAAC;AAAA,MACjE,GAAI,SAAS,yBAAyB,OAAO,EAAC,sBAAsB,KAAI,IAAI,CAAC;AAAA,MAC7E,GAAI,SAAS,cAAc,EAAC,aAAa,SAAS,YAAY,KAAK,QAAQ,EAAC,IAAI,CAAC;AAAA,MACjF,GAAI,SAAS,WAAW,EAAC,UAAU,SAAS,SAAS,KAAK,QAAQ,EAAC,IAAI,CAAC;AAAA,MACxE,GAAI,SAAS,QAAQ,EAAC,OAAO,SAAS,MAAM,KAAK,QAAQ,EAAC,IAAI,CAAC;AAAA,MAC/D,GAAI,SAAS,gBAAgB,EAAC,eAAe,SAAS,cAAc,KAAK,QAAQ,EAAC,IAAI,CAAC;AAAA,MACvF,GAAI,SAAS,oBAAoB,EAAC,mBAAmB,SAAS,kBAAkB,KAAK,QAAQ,EAAC,IAAI,CAAC;AAAA,MACnG,GAAI,SAAS,mBAAmB,EAAC,kBAAkB,SAAS,iBAAiB,KAAK,QAAQ,EAAC,IAAI,CAAC;AAAA,MAChG,GAAI,SAAS,sBAAsB,SAAY,EAAC,mBAAmB,SAAS,kBAAiB,IAAI,CAAC;AAAA,IACpG,EAAE;AACF,SAAK,UAAU,aAAa,KAAK,OAAO;AACxC,SAAK,WAAW,KAAK;AACrB,SAAK,UAAU,KAAK,WAAW;AAC/B,SAAK,UAAU;AAAA,EACjB;AAAA;AAAA,EAGA,KAAK,MAAgC;AACnC,UAAM,WAAW,KAAK,YAAY,IAAI;AACtC,QAAI,CAAC,SAAU,OAAM,IAAI,MAAM,iCAAiC,IAAI,qBAAqB;AACzF,WAAO,IAAI,kBAAiB,CAAC,QAAQ,GAAG,KAAK,OAAO;AAAA,EACtD;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,iBAAiB,IAAa,KAAmD;AAC/E,eAAW,YAAY,KAAK,WAAW;AACrC,YAAM,OAAO,SAAS,mBAAmB,IAAI,GAAG;AAChD,UAAI,KAAM,QAAO;AAAA,IACnB;AACA,WAAO;AAAA,EACT;AAAA;AAAA,EAGA,YAAY,MAA8C;AACxD,WAAO,KAAK,UAAU,KAAK,CAAC,MAAM,EAAE,SAAS,IAAI;AAAA,EACnD;AAAA;AAAA,EAGA,YAAY,MAAuB;AACjC,WAAO,KAAK,UAAU,KAAK,CAAC,MAAM,EAAE,SAAS,IAAI;AAAA,EACnD;AAAA;AAAA,EAGA,mBAAmB,MAAuB;AACxC,WAAO,KAAK,UAAU,KAAK,CAAC,MAAM;AAChC,UAAI;AAAE,eAAO,EAAE,SAAS,QAAQ,EAAE,QAAQ;AAAA,MAAG,QAAQ;AAAE,eAAO;AAAA,MAAO;AAAA,IACvE,CAAC;AAAA,EACH;AAAA;AAAA,EAGA,cAAc,OAAwB;AACpC,WAAO,KAAK,UAAU,KAAK,CAAC,MAAM;AAChC,UAAI;AAAE,eAAO,EAAE,QAAQ,KAAK,CAAC,CAAC,EAAE,gBAAgB,KAAK;AAAA,MAAG,QAAQ;AAAE,eAAO;AAAA,MAAO;AAAA,IAClF,CAAC;AAAA,EACH;AAAA;AAAA,EAGA,kBAAkB,WAAmB,SAA0B;AAC7D,WAAO,KAAK,UAAU,KAAK,CAAC,MAAM;AAChC,UAAI;AACF,eAAO,EAAE,QAAQ,MAAM,EAAE,oBAAoB,WAAW,OAAO,KAAK;AAAA,MACtE,QAAQ;AAAE,eAAO;AAAA,MAAO;AAAA,IAC1B,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,aACJ,QACA,SAC6B;AAC7B,UAAM,MAAM,MAAM,KAAK,UAAU,QAAQ,OAAO;AAChD,QAAI,CAAC,IAAK,QAAO;AACjB,UAAM,OAAO,SAAS,WAAW,YAAY,IAAI,UAAU,IAAI;AAC/D,UAAM,EAAC,aAAa,IAAI,eAAe,IAAI,MAAM,IAAI,GAAG,MAAK,IAAI;AACjE,WAAO;AAAA,MACL,GAAG;AAAA,MACH,YAAY;AAAA,QACV,OAAO,KAAK;AAAA,QACZ,SAAS,KAAK;AAAA,QACd,YAAY,IAAI,OAAO,IAAI,CAAC,OAAO;AAAA,UACjC,UAAU,EAAE;AAAA,UACZ,cAAc,EAAE;AAAA,UAChB,YAAY,EAAE;AAAA,UACd,OAAO,EAAE;AAAA,UACT,eAAe,EAAE;AAAA,UACjB,aAAa,EAAE;AAAA,QACjB,EAAE;AAAA,MACJ;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,UACJ,QACA,SAC0B;AAK1B,UAAM,aAAuB,CAAC;AAC9B,SAAK,kBAAkB;AACvB,UAAM,WAAW,OAAO,OAAO,EAAC,GAAG,OAAM,CAAC;AAC1C,UAAM,OAAO,OAAO,OAAO,EAAC,OAAO,SAAS,aAAa,OAAO,SAAS,YAAW,CAAC;AACrF,UAAM,KAAK,OAAO,OAAO,EAAC,OAAO,SAAS,WAAW,OAAO,SAAS,UAAS,CAAC;AAE/E,QAAI,WAAW,KAAK,UAAU,OAAO,CAAC,MAAM;AAC1C,UAAI;AAAE,eAAO,EAAE,QAAQ,KAAK,EAAE,cAAc,MAAM,EAAE;AAAA,MAAG,QAAQ;AAAE,eAAO;AAAA,MAAO;AAAA,IACjF,CAAC;AACD,QAAI,SAAS,gBAAgB,SAAS,WAAW;AAC/C,iBAAW,SAAS,OAAO,CAAC,MAAM,EAAE,sBAAsB,IAAI;AAAA,IAChE;AACA,QAAI,SAAS,WAAW,EAAG,QAAO;AAOlC,UAAM,YAAY,SAAS,WAAW,IAAI,wBAAwB;AAElE,UAAM,WAAmC,CAAC;AAC1C,UAAM,WAAoB,CAAC;AAC3B,UAAM,UAAU,IAAI,IAAI,SAAS,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC;AACnD,UAAM,UAAU,MAAM;AACpB,UAAI,CAAC,SAAS,YAAY,SAAS,WAAW,EAAG;AACjD,YAAM,MAAM,KAAK,KAAK,UAAU,UAAU,CAAC,GAAG,OAAO,GAAG,UAAU;AAClE,UAAI;AAAE,gBAAQ,SAAS,GAAG;AAAA,MAAG,QAAQ;AAAA,MAA+C;AAAA,IACtF;AACA,UAAM,QAAQ,IAAI,SAAS,IAAI,OAAO,GAAG,MAAM;AAC7C,YAAM,aAAa,IAAI,gBAAgB;AACvC,YAAM,MAAM,OAAO,OAAO,EAAC,GAAG,UAAU,WAAW,CAAC,WAAmB;AACrE,iBAAS,CAAC,MAAM,OAAO,WAAW,GAAG,EAAE,IAAI,GAAG,IAAI,SAAS,GAAG,EAAE,IAAI,KAAK,MAAM;AAC/E,YAAI;AAAE,mBAAS,YAAY,MAAM;AAAA,QAAG,QAAQ;AAAA,QAAyB;AAAA,MACvE,EAAC,CAAC;AACF,UAAI,IAAkB;AACtB,UAAI;AACF,YAAI,MAAM,YAAY,EAAE,SAAS,KAAK,WAAW,MAAM,GAAG,SAAS;AACnE,YAAI,CAAC,GAAG;AAGN,qBAAW,KAAK,SAAS,CAAC,KAAK,GAAG,EAAE,IAAI,qBAAqB;AAAA,QAC/D,WAAW,CAAC,WAAW,GAAG,UAAU,EAAE,IAAI,GAAG;AAC3C,gBAAM,SAAS,GAAG,EAAE,IAAI,qCAAqC,EAAE,aAAa,aAAa,SAAS,gBAAgB,GAAG,gBAAgB,EAAE,YAAY,SAAS,KAAK,IAAI,CAAC;AACtK,qBAAW,KAAK,MAAM;AACtB,kBAAQ,KAAK,iBAAiB,MAAM,EAAE;AACtC,cAAI;AAAA,QACN,OAAO;AAEL,gBAAM,WAAW,iBAAiB,GAAG,GAAG,SAAS,WAAW;AAC5D,cAAI,UAAU;AACZ,uBAAW,KAAK,QAAQ;AACxB,oBAAQ,KAAK,iBAAiB,QAAQ,EAAE;AACxC,gBAAI;AAAA,UACN,WAAW,SAAS,6BAA6B,EAAE,EAAE,eAAe,SAAS,KAAK,EAAE,cAAc,SAAY;AAG5G,gBAAI;AAAA,UACN;AAAA,QACF;AAAA,MACF,SAAS,KAAK;AAIZ,cAAM,SAAS,GAAG,EAAE,IAAI,KAAK,eAAe,QAAQ,IAAI,QAAQ,MAAM,GAAG,GAAG,IAAI,OAAO,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;AACzG,mBAAW,KAAK,MAAM;AACtB,gBAAQ,KAAK,qCAAgC,MAAM,EAAE;AACrD,YAAI;AAAA,MACN,UAAE;AACA,mBAAW,MAAM;AAAA,MACnB;AACA,cAAQ,OAAO,EAAE,IAAI;AAGrB,UAAI,EAAG,UAAS,KAAK,EAAC,GAAG,GAAG,UAAU,EAAE,KAAI,CAAC;AAC7C,cAAQ;AAAA,IACV,CAAC,CAAC;AACF,QAAI,SAAS,WAAW,EAAG,QAAO;AAClC,WAAO,KAAK,KAAK,UAAU,UAAU,CAAC,GAAG,UAAU;AAAA,EACrD;AAAA;AAAA,EAGA,MAAM,YAAY,cAAsB,KAAuC;AAC7E,UAAM,WAAW,KAAK,YAAY,YAAY;AAC9C,QAAI,CAAC,SAAU,QAAO,EAAC,OAAO,SAAQ;AACtC,WAAO,SAAS,YAAY,GAAG;AAAA,EACjC;AAAA;AAAA,EAGA,MAAM,cAAc,cAAsB,UAAkB,QAA+B;AACzF,UAAM,KAAK,YAAY,YAAY,GAAG,gBAAgB,UAAU,MAAM;AAAA,EACxE;AAAA;AAAA,EAGA,QAAc;AACZ,eAAW,YAAY,KAAK,UAAW,UAAS,QAAQ;AAAA,EAC1D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUQ,KAAK,QAAiB,QAAqB,SAAmB,YAAgC;AACpG,UAAM,MAAM,KAAK,WAAW,OAAO,IAAI,CAAC,MAAM;AAC5C,UAAI;AACF,cAAM,IAAI,KAAK,SAAU,GAAG,MAAM;AAClC,eAAO,OAAO,MAAM,YAAY,OAAO,SAAS,CAAC,IAAI,IAAI;AAAA,MAC3D,QAAQ;AAAE,eAAO;AAAA,MAAM;AAAA,IACzB,CAAC,IAAI,OAAO,IAAI,MAAM,IAAI;AAC1B,UAAM,SAAS,IAAI,MAAM,CAAC,MAAM,MAAM,IAAI;AAC1C,QAAI;AACJ,QAAI,QAAQ;AACV,YAAM,SAAS;AACf,YAAM,MAAM,KAAK,IAAI,GAAG,MAAM;AAC9B,iBAAW,OAAO,IAAI,CAAC,MAAO,MAAM,IAAI,KAAK,IAAI,GAAG,CAAC,IAAI,MAAM,KAAK,MAAM,IAAI,CAAE;AAAA,IAClF,OAAO;AACL,YAAM,OAAO,OAAO,IAAI,CAAC,MAAM,OAAO,EAAE,aAAa,CAAC;AACtD,YAAM,MAAM,KAAK,OAAO,CAAC,GAAG,MAAO,IAAI,IAAI,IAAI,CAAE;AACjD,iBAAW,KAAK,IAAI,CAAC,MAAM,SAAS,GAAG,GAAG,CAAC;AAAA,IAC7C;AACA,UAAM,SAAwB,OAAO,IAAI,CAAC,GAAG,OAAO;AAAA,MAClD,GAAG;AAAA,MACH,aAAa,SAAS,IAAI,CAAC,IAAK;AAAA,MAChC,eAAe,SAAS,CAAC;AAAA,MACzB,MAAM,CAAC;AAAA,IACT,EAAE;AAEF,UAAM,OAAO,OAAO,OAAO,CAAC,MAAM,EAAE,iBAAiB,IAAI,KAAK,UAAU,KAAK;AAC7E,UAAM,OAAO,KAAK,IAAI,CAAC,MAAM,EAAE,UAAU;AACzC,UAAM,SAAS,KAAK,IAAI,GAAG,IAAI;AAC/B,UAAM,SAAS,KAAK,IAAI,GAAG,IAAI;AAC/B,UAAM,IAAI,KAAK;AACf,UAAM,WAAW,CAAC,MAChB,EAAE,QAAQ,EAAE,gBACZ,EAAE,SAAS,WAAW,SAAS,KAAK,SAAS,EAAE,eAAe,SAAS,WACvE,EAAE,cAAc,EAAE;AACpB,UAAM,OAAO,KAAK,OAAO,CAAC,GAAG,MAAO,SAAS,CAAC,IAAI,SAAS,CAAC,IAAI,IAAI,CAAE;AACtE,UAAM,UAAU,OAAO,OAAO,CAAC,GAAG,MAChC,EAAE,aAAa,EAAE,cAAe,EAAE,eAAe,EAAE,cAAc,EAAE,gBAAgB,EAAE,gBAAiB,IAAI,CAAC;AAC7G,SAAK,KAAK,KAAK,MAAM;AACrB,YAAQ,KAAK,KAAK,SAAS;AAG3B,WAAO,KAAK,CAAC,GAAG,MAAO,MAAM,OAAO,KAAK,MAAM,OAAO,IAAI,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,aAAa,EAAE,UAAW;AAC3H,WAAO,EAAC,QAAQ,QAAQ,MAAM,SAAS,SAAS,YAAY,CAAC,GAAG,UAAU,EAAC;AAAA,EAC7E;AACF;AAGA,SAAS,SAAS,KAAa,KAAqB;AAClD,MAAI,QAAQ,GAAI,QAAO;AAEvB,SAAO,eAAgB,MAAM,SAAW,GAAG,IAAI;AACjD;","names":[]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
CrossChainRouter
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-R47JJEOO.js";
|
|
4
4
|
|
|
5
5
|
// src/swap2/router.ts
|
|
6
6
|
import {
|
|
@@ -75,4 +75,4 @@ var RouterSwap2Protocol = class _RouterSwap2Protocol extends BaseSwap2Protocol {
|
|
|
75
75
|
export {
|
|
76
76
|
RouterSwap2Protocol
|
|
77
77
|
};
|
|
78
|
-
//# sourceMappingURL=chunk-
|
|
78
|
+
//# sourceMappingURL=chunk-S5DBSOWP.js.map
|
package/dist/index.cjs
CHANGED
|
@@ -96,6 +96,7 @@ var CrossChainRouter = class _CrossChainRouter {
|
|
|
96
96
|
// remote provider for a local one and checked its calldata against the backend's own addresses.
|
|
97
97
|
...provider.remote === true ? { remote: true } : {},
|
|
98
98
|
...provider.verifiesBuilds === true ? { verifiesBuilds: true } : {},
|
|
99
|
+
...provider.verifiesQuotes === true ? { verifiesQuotes: true } : {},
|
|
99
100
|
...provider.depositAddressRoutes === true ? { depositAddressRoutes: true } : {},
|
|
100
101
|
...provider.callTargets ? { callTargets: provider.callTargets.bind(provider) } : {},
|
|
101
102
|
...provider.spenders ? { spenders: provider.spenders.bind(provider) } : {},
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/router.ts","../src/value.ts","../src/swap2/router.ts"],"sourcesContent":["/**\n * @anywalletkit/protocol-swap2-router — the OPTIONAL swap2 aggregator.\n *\n * Every swap2 provider module runs on its own (install only\n * `@anywalletkit/protocol-swap2-lifi` and use `LifiSwap2Protocol`). Install\n * this package when you want one protocol that auctions a route across several\n * providers: pass the providers you installed and it quotes them in parallel,\n * validates every quote, scores them and executes the winner.\n *\n * ```ts\n * import {RouterSwap2Protocol} from \"@anywalletkit/protocol-swap2-router\";\n * import {lifiProvider} from \"@anywalletkit/protocol-swap2-lifi/provider\";\n * import {nearIntentsProvider} from \"@anywalletkit/protocol-swap2-near-intents/provider\";\n *\n * const swap2 = new RouterSwap2Protocol(account, {\n * fromChain: \"eip155:1\",\n * providers: [lifiProvider({}), nearIntentsProvider({})],\n * });\n * ```\n *\n * Providers reached through a backend use `remoteProvider` (re-exported from\n * the core package); give it `supportsChain`/`supportsChainPair` — e.g. from\n * the provider package's `config` export — so discovery knows its coverage.\n */\nexport {CrossChainRouter, type RouterOptions, type RankedQuote, type RouteSet} from \"./router.js\";\nexport {usdValue, quoteValues} from \"./value.js\";\nexport type {QuoteValue, QuoteValueOptions} from \"./value.js\";\nexport {RouterSwap2Protocol, type RouterSwap2Config, type Swap2Route} from \"./swap2/router.js\";\nexport {RouterSwap2Protocol as default} from \"./swap2/router.js\";\nexport {remoteProvider, type RemoteProviderOptions} from \"@anywalletkit/protocol-swap2-core/remote\";\nexport type * from \"@anywalletkit/protocol-swap2-core/types\";\nexport type { ValueParams, ValueQuote } from \"./value.js\"\n","/**\n * The auction engine of the optional aggregator: routes a cross-chain delivery\n * over whichever providers the caller installed and passed in. Protocol\n * modules never need it — each one runs standalone on @anywalletkit/protocol-swap2-core.\n */\nimport type {\n CrossChainProvider,\n IntentRef,\n IntentStatus,\n Quote,\n QuoteParams,\n RoutedQuote,\n ScoreWeights,\n} from \"@anywalletkit/protocol-swap2-core/types\";\nimport {remotePinRefusal, validQuote} from \"@anywalletkit/protocol-swap2-core/validate\";\nimport type {ActivityItem, ChainTx, DescribeActivityContext} from \"@anywalletkit/core\";\nimport {bigintToNumber} from \"@anywalletkit/core\";\n\nconst DEFAULT_WEIGHTS: ScoreWeights = {price: 0.6, speed: 0.3, reliability: 0.1};\n/** Quotes within 0.2% of the best net value count as the same price. */\nconst DEFAULT_TIE_BAND = 0.002;\n\nexport interface RouterOptions {\n /**\n * \"price:0.6,speed:0.3,reliability:0.1\" — how quotes inside the tie band\n * (same price, within `tieBand`) are ordered. Price itself always leads.\n */\n weights?: string;\n /**\n * What a quote is worth to the user in USD: its guaranteed output minus what\n * the route charges on top (a native bridge fee, the source gas). Return null\n * when it cannot be priced — the auction then compares guaranteed outputs.\n * `usdValue(prices)` builds one from a symbol → USD price map.\n */\n valueUsd?: (quote: Quote, params: QuoteParams) => number | null;\n /** Fraction of the best net value inside which quotes tie on price (default 0.002). */\n tieBand?: number;\n}\n\n/** A validated quote with its place in the auction. */\nexport interface RankedQuote extends Quote {\n /** Net USD value (`valueUsd`), or null when the auction compared raw outputs. */\n netValueUsd: number | null;\n /** This quote's value against the best one, 0..1 (1 = the best price). */\n relativeValue: number;\n /** \"best\": the pick (best price; faster/more reliable among equal prices). \"fastest\": the lowest ETA. */\n tags: (\"best\" | \"fastest\")[];\n}\n\n/** Every validated route for one request, ranked by value. */\nexport interface RouteSet {\n /** Every validated route, best first. */\n quotes: RankedQuote[];\n /** Most delivered value (net of fees when priced) within the tie band. */\n best: RankedQuote;\n /** Lowest ETA. */\n fastest: RankedQuote;\n /** Providers still quoting (only non-empty in progressive `onUpdate` snapshots). */\n pending: string[];\n /** Why the venues that sat out did (same as `lastRejections`). */\n rejections: string[];\n}\n// LI.FI's /quote routinely takes ~3.5s (it builds executable calldata) — 4s\n// raced it out of every round. All providers still run in parallel.\nconst QUOTE_TIMEOUT_MS = 8000;\n/** Pinned single-venue (execution) budget — see the comment at the call site. */\nconst SOLO_QUOTE_TIMEOUT_MS = 25_000;\n\nfunction parseWeights(spec?: string): ScoreWeights {\n if (!spec) return DEFAULT_WEIGHTS;\n const w = {...DEFAULT_WEIGHTS};\n for (const part of spec.split(\",\")) {\n const [k, v] = part.split(\":\");\n const n = Number(v);\n if ((k === \"price\" || k === \"speed\" || k === \"reliability\") && Number.isFinite(n)) {\n w[k] = Math.max(0, n);\n }\n }\n return w;\n}\n\nasync function withTimeout<T>(p: Promise<T>, ms: number): Promise<T | null> {\n return new Promise((resolve, reject) => {\n // Timeouts and failures must REJECT: the old `() => resolve(null)` arm\n // swallowed every provider error — including forwarded venue refusals —\n // into a null indistinguishable from \"no route\", which made execution\n // failures undiagnosable from the surface (the '(c2)' hunt of 2026-08-31).\n const timer = setTimeout(() => reject(new Error(`quote timed out after ${ms}ms`)), ms);\n p.then(resolve, reject).finally(() => clearTimeout(timer));\n });\n}\n\n/**\n * Routes a cross-chain delivery over pluggable providers: queries all that\n * support the route in parallel (with a timeout so a slow provider can't block),\n * normalizes their quotes, scores by configurable weights, and returns the best\n * tagged with `routeScore`. A failed/slow provider simply doesn't participate.\n */\nexport class CrossChainRouter {\n private readonly providers: CrossChainProvider[];\n /** Why the venues of the LAST getBestQuote call sat out — for error surfaces. */\n private _lastRejections: string[] = [];\n /** Why providers sat out the last auction, one line each. */\n get lastRejections(): readonly string[] {\n return this._lastRejections;\n }\n private readonly weights: ScoreWeights;\n private readonly valueUsd: RouterOptions[\"valueUsd\"];\n private readonly tieBand: number;\n private readonly options: RouterOptions;\n\n constructor(providers: CrossChainProvider[], options?: string | RouterOptions) {\n const opts: RouterOptions = typeof options === \"string\" ? {weights: options} : {...(options ?? {})};\n if (opts.tieBand !== undefined && !(Number.isFinite(opts.tieBand) && opts.tieBand >= 0 && opts.tieBand < 1)) {\n throw new Error(\"cross-chain router: tieBand must be a fraction in [0, 1)\");\n }\n const names = new Set<string>();\n for (const provider of providers) {\n if (typeof provider.name !== \"string\" || !/^[A-Za-z0-9_-]+$/.test(provider.name) || names.has(provider.name)) {\n throw new Error(`cross-chain router: invalid or duplicate provider name '${String(provider.name)}'`);\n }\n names.add(provider.name);\n }\n // Snapshot the dispatch surface. A caller mutating provider.name or method\n // properties after construction must not redirect quote→build/status.\n this.providers = providers.map((provider) => ({\n name: provider.name,\n enabled: provider.enabled.bind(provider),\n supportsRoute: provider.supportsRoute.bind(provider),\n getQuote: provider.getQuote.bind(provider),\n buildDeposit: provider.buildDeposit.bind(provider),\n trackIntent: provider.trackIntent.bind(provider),\n ...(provider.preflightDeposit ? {preflightDeposit: provider.preflightDeposit.bind(provider)} : {}),\n ...(provider.notifyDeposit ? {notifyDeposit: provider.notifyDeposit.bind(provider)} : {}),\n ...(provider.registerSignedOrder ? {registerSignedOrder: provider.registerSignedOrder.bind(provider)} : {}),\n // Two-phase routes (CCTP): the destination claim. Missing here, the engine\n // and the server both reported \"provider 'cctp' has no claim step\" (2026-10-13).\n ...(provider.buildClaim ? {buildClaim: provider.buildClaim.bind(provider)} : {}),\n ...(provider.claimTargets ? {claimTargets: provider.claimTargets.bind(provider)} : {}),\n // A remote stub's marker and the app's pins (scan 2026-10-27 modules, F8/F9/F16): dropped here, the engine took a\n // remote provider for a local one and checked its calldata against the backend's own addresses.\n ...(provider.remote === true ? {remote: true} : {}),\n ...(provider.verifiesBuilds === true ? {verifiesBuilds: true} : {}),\n ...(provider.depositAddressRoutes === true ? {depositAddressRoutes: true} : {}),\n ...(provider.callTargets ? {callTargets: provider.callTargets.bind(provider)} : {}),\n ...(provider.spenders ? {spenders: provider.spenders.bind(provider)} : {}),\n ...(provider.close ? {close: provider.close.bind(provider)} : {}),\n ...(provider.supportsChain ? {supportsChain: provider.supportsChain.bind(provider)} : {}),\n ...(provider.supportsChainPair ? {supportsChainPair: provider.supportsChainPair.bind(provider)} : {}),\n ...(provider.describeActivity ? {describeActivity: provider.describeActivity.bind(provider)} : {}),\n ...(provider.supportsSameChain !== undefined ? {supportsSameChain: provider.supportsSameChain} : {}),\n }));\n this.weights = parseWeights(opts.weights);\n this.valueUsd = opts.valueUsd;\n this.tieBand = opts.tieBand ?? DEFAULT_TIE_BAND;\n this.options = opts;\n }\n\n /** The same auction restricted to one provider — to execute the route a user picked. */\n only(name: string): CrossChainRouter {\n const provider = this.getProvider(name);\n if (!provider) throw new Error(`cross-chain router: provider '${name}' is not registered`);\n return new CrossChainRouter([provider], this.options);\n }\n\n /**\n * Activity recognition across the installed providers: the first one that\n * claims the transaction describes it. Null when none does (or none is held).\n */\n describeActivity(tx: ChainTx, ctx: DescribeActivityContext): ActivityItem | null {\n for (const provider of this.providers) {\n const item = provider.describeActivity?.(tx, ctx);\n if (item) return item;\n }\n return null;\n }\n\n /** A provider by name. */\n getProvider(name: string): CrossChainProvider | undefined {\n return this.providers.find((p) => p.name === name);\n }\n\n /** True when a provider of that name is installed. */\n hasProvider(name: string): boolean {\n return this.providers.some((p) => p.name === name);\n }\n\n /** True when that provider is installed and enabled. */\n hasEnabledProvider(name: string): boolean {\n return this.providers.some((p) => {\n try { return p.name === name && p.enabled(); } catch { return false; }\n });\n }\n\n /** True when any enabled provider declares the chain. */\n supportsChain(caip2: string): boolean {\n return this.providers.some((p) => {\n try { return p.enabled() && !!p.supportsChain?.(caip2); } catch { return false; }\n });\n }\n\n /** True when any enabled provider declares the chain pair. */\n supportsChainPair(fromChain: string, toChain: string): boolean {\n return this.providers.some((p) => {\n try {\n return p.enabled() && (p.supportsChainPair?.(fromChain, toChain) ?? false);\n } catch { return false; }\n });\n }\n\n /**\n * The auction's pick: the best price (net of native fees and gas when\n * `valueUsd` is set; faster, then more reliable, among equal prices), or\n * the fastest route with `prefer: \"fastest\"`.\n */\n async getBestQuote(\n params: QuoteParams,\n options?: {requireImmediateExecution?: boolean; prefer?: \"best\" | \"fastest\"},\n ): Promise<RoutedQuote | null> {\n const set = await this.getQuotes(params, options);\n if (!set) return null;\n const pick = options?.prefer === \"fastest\" ? set.fastest : set.best;\n const {netValueUsd: _n, relativeValue: _r, tags: _t, ...quote} = pick;\n return {\n ...quote,\n routeScore: {\n score: pick.relativeValue,\n weights: this.weights,\n candidates: set.quotes.map((q) => ({\n provider: q.provider,\n sourceAmount: q.sourceAmount,\n etaSeconds: q.etaSeconds,\n score: q.relativeValue,\n minDestAmount: q.minDestAmount,\n netValueUsd: q.netValueUsd,\n })),\n },\n };\n }\n\n /**\n * Every validated route, ranked — for a route picker that shows the best and\n * the fastest and lets the user choose. Providers run in parallel; with\n * `onUpdate` each one that answers re-publishes the ranked set at once (the\n * first price shows in the time of the fastest venue, not the slowest).\n */\n async getQuotes(\n params: QuoteParams,\n options?: {requireImmediateExecution?: boolean; onUpdate?: (set: RouteSet) => void},\n ): Promise<RouteSet | null> {\n // A public engine caller — or one provider running in the same auction —\n // must not be able to rewrite another provider's request while async quote\n // work is in flight. QuoteParams is intentionally flat, so a frozen copy is\n // a complete execution snapshot.\n const rejections: string[] = [];\n this._lastRejections = rejections;\n const snapshot = Object.freeze({...params});\n const from = Object.freeze({chain: snapshot.sourceChain, token: snapshot.sourceToken});\n const to = Object.freeze({chain: snapshot.destChain, token: snapshot.destToken});\n // Only enabled (validated) providers that can serve the route participate.\n let eligible = this.providers.filter((p) => {\n try { return p.enabled() && p.supportsRoute(from, to); } catch { return false; }\n });\n if (snapshot.sourceChain === snapshot.destChain) {\n eligible = eligible.filter((p) => p.supportsSameChain === true);\n }\n if (eligible.length === 0) return null;\n\n // The short timeout protects the AUCTION — one slow venue must not hold\n // the others hostage. With a single eligible provider (a pinned execution\n // re-quote) there is nobody to protect, and a live deposit-creating quote\n // legitimately takes longer than a dry one (serverless hop + upstream\n // retries) — starving it surfaced as a terminal \"no route\" on execution.\n const timeoutMs = eligible.length === 1 ? SOLO_QUOTE_TIMEOUT_MS : QUOTE_TIMEOUT_MS;\n // Each venue names its own refusal (per call, so concurrent quotes cannot race).\n const refusals: (string | undefined)[] = [];\n const accepted: Quote[] = [];\n const pending = new Set(eligible.map((p) => p.name));\n const publish = () => {\n if (!options?.onUpdate || accepted.length === 0) return;\n const set = this.rank(accepted, snapshot, [...pending], rejections);\n try { options.onUpdate(set); } catch { /* an observer must not break the auction */ }\n };\n await Promise.all(eligible.map(async (p, i) => {\n const controller = new AbortController();\n const own = Object.freeze({...snapshot, onRefusal: (reason: string) => {\n refusals[i] ??= reason.startsWith(`${p.name}:`) ? reason : `${p.name}: ${reason}`;\n try { snapshot.onRefusal?.(reason); } catch { /* diagnostics only */ }\n }});\n let q: Quote | null = null;\n try {\n q = await withTimeout(p.getQuote(own, controller.signal), timeoutMs);\n if (!q) {\n // A provider RETURNING null (vs throwing) was the one silent path\n // left — record it so the surfaced no-route error names the venue.\n rejections.push(refusals[i] ?? `${p.name}: returned no quote`);\n } else if (!validQuote(q, snapshot, p.name)) {\n const reason = `${p.name}: rejected by validation (minDest=${q.minDestAmount} vs floor=${snapshot.minAmountOut ?? \"-\"}, validUntil=${q.validUntilMs}, now=${Date.now()})`;\n rejections.push(reason);\n console.warn(`swap2-router: ${reason}`);\n q = null;\n } else {\n // A remote stub's route that calls or approves an address the app did not pin: execution would refuse it.\n const unpinned = remotePinRefusal(p, q, snapshot.sourceChain);\n if (unpinned) {\n rejections.push(unpinned);\n console.warn(`swap2-router: ${unpinned}`);\n q = null;\n } else if (options?.requireImmediateExecution && !(q.depositAddress.length > 0 || q.txRequest !== undefined)) {\n // Legacy deposit-address screens cannot execute order-based quotes that\n // require a separate build/sign/register lifecycle.\n q = null;\n }\n }\n } catch (err) {\n // A failed venue sitting out silently is indistinguishable from \"no\n // route\" — record why (surfaced through lastRejections) and say it in\n // the console (same posture as onModuleSkipped).\n const reason = `${p.name}: ${err instanceof Error ? err.message.slice(0, 160) : String(err).slice(0, 160)}`;\n rejections.push(reason);\n console.warn(`swap2-router: quote failed — ${reason}`);\n q = null;\n } finally {\n controller.abort();\n }\n pending.delete(p.name);\n // Provider identity is an execution security boundary. Never trust the\n // provider field returned by an untrusted adapter; bind it to its slot.\n if (q) accepted.push({...q, provider: p.name});\n publish();\n }));\n if (accepted.length === 0) return null;\n return this.rank(accepted, snapshot, [], rejections);\n }\n\n /** Status from the named provider; `failed` when it is not installed. */\n async trackIntent(providerName: string, ref: IntentRef): Promise<IntentStatus> {\n const provider = this.getProvider(providerName);\n if (!provider) return {state: \"failed\"};\n return provider.trackIntent(ref);\n }\n\n /** Forward a source-broadcast notification to the intent's provider. */\n async notifyDeposit(providerName: string, intentId: string, txHash: string): Promise<void> {\n await this.getProvider(providerName)?.notifyDeposit?.(intentId, txHash);\n }\n\n /** Release every provider's resources. */\n close(): void {\n for (const provider of this.providers) provider.close?.();\n }\n\n /**\n * Price first: each quote's value is its net USD (`valueUsd`) — or, when any\n * quote cannot be priced, its guaranteed output — against the best one.\n * Quotes within `tieBand` of the best are the same price; among those the\n * weights order speed and reliability. A $0.01 edge no longer beats a route\n * that lands in seconds instead of twenty minutes, and a route that charges\n * a native bridge fee on top no longer wins on its gross output.\n */\n private rank(quotes: Quote[], params: QuoteParams, pending: string[], rejections: string[]): RouteSet {\n const usd = this.valueUsd ? quotes.map((q) => {\n try {\n const v = this.valueUsd!(q, params);\n return typeof v === \"number\" && Number.isFinite(v) ? v : null;\n } catch { return null; }\n }) : quotes.map(() => null);\n const priced = usd.every((v) => v !== null);\n let relative: number[];\n if (priced) {\n const values = usd as number[];\n const max = Math.max(...values);\n relative = values.map((v) => (max > 0 ? Math.max(0, v) / max : v >= max ? 1 : 0));\n } else {\n const outs = quotes.map((q) => BigInt(q.minDestAmount));\n const max = outs.reduce((a, b) => (b > a ? b : a));\n relative = outs.map((o) => fraction(o, max));\n }\n const ranked: RankedQuote[] = quotes.map((q, i) => ({\n ...q,\n netValueUsd: priced ? usd[i]! : null,\n relativeValue: relative[i]!,\n tags: [],\n }));\n\n const tier = ranked.filter((q) => q.relativeValue >= 1 - this.tieBand - 1e-12);\n const etas = tier.map((q) => q.etaSeconds);\n const minEta = Math.min(...etas);\n const maxEta = Math.max(...etas);\n const w = this.weights;\n const tieScore = (q: RankedQuote) =>\n w.price * q.relativeValue +\n w.speed * (maxEta === minEta ? 1 : (maxEta - q.etaSeconds) / (maxEta - minEta)) +\n w.reliability * q.reliability;\n const best = tier.reduce((a, b) => (tieScore(b) > tieScore(a) ? b : a));\n const fastest = ranked.reduce((a, b) =>\n b.etaSeconds < a.etaSeconds || (b.etaSeconds === a.etaSeconds && b.relativeValue > a.relativeValue) ? b : a);\n best.tags.push(\"best\");\n fastest.tags.push(\"fastest\");\n\n // The list reads top-down by value; the pick leads its price tier.\n ranked.sort((a, b) => (a === best ? -1 : b === best ? 1 : b.relativeValue - a.relativeValue || a.etaSeconds - b.etaSeconds));\n return {quotes: ranked, best, fastest, pending, rejections: [...rejections]};\n }\n}\n\n/** Ratio of two non-negative bigints as a 0..1 number. */\nfunction fraction(num: bigint, den: bigint): number {\n if (den === 0n) return 1;\n // scale to keep precision, then to float\n return bigintToNumber((num * 10_000n) / den) / 10_000;\n}\n","import {bigintToNumber, bigintToUnits} from \"@anywalletkit/core\";\nimport {ccAssetByToken, ccChain} from \"@anywalletkit/swap2-assets\";\nimport type {Quote, QuoteParams} from \"@anywalletkit/protocol-swap2-core/types\";\n\n/** Stables priced at par when the map has no entry for them. */\nconst PAR = /^(USDC|USDT|USDT0|USD₮0|DAI|USDC\\.E)$/i;\n\n/** symbol → USD, trying the exact symbol, upper case, the unwrapped native (WETH → ETH, wS → S), then par for stables. */\nfunction priceOf(prices: Readonly<Record<string, number>>, symbol: string): number | null {\n const tries = [symbol, symbol.toUpperCase()];\n if (/^w/i.test(symbol) && symbol.length > 2) tries.push(symbol.slice(1), symbol.slice(1).toUpperCase());\n for (const t of tries) {\n const p = prices[t];\n if (typeof p === \"number\" && Number.isFinite(p) && p > 0) return p;\n }\n return PAR.test(symbol) ? 1 : null;\n}\n\nconst units = (amount: string | bigint, decimals: number) => bigintToUnits(BigInt(amount), decimals);\n\n/**\n * A `valueUsd` for the router: the guaranteed output in USD, minus the native\n * fee the route charges on top of the input (bridge messaging fees), minus\n * the source gas when `gasUsd` can say it. null when a needed price is missing\n * — the auction then falls back to comparing guaranteed outputs.\n */\nexport function usdValue(\n prices: Readonly<Record<string, number>>,\n options?: {gasUsd?: (quote: Quote, params: QuoteParams) => number | null},\n): (quote: Quote, params: QuoteParams) => number | null {\n return (quote, params) => {\n const dest = ccAssetByToken(params.destChain, params.destToken);\n if (!dest) return null;\n const destPrice = priceOf(prices, dest.symbol);\n if (destPrice === null) return null;\n let value = units(quote.minDestAmount, dest.decimals) * destPrice;\n const nativeFee = quote.txRequest?.nativeFee;\n if (nativeFee && BigInt(nativeFee) > 0n) {\n const native = ccAssetByToken(params.sourceChain, \"\");\n const nativePrice = native ? priceOf(prices, native.symbol) : null;\n if (!native || nativePrice === null) return null;\n value -= units(nativeFee, native.decimals) * nativePrice;\n }\n if (options?.gasUsd) {\n const gas = options.gasUsd(quote, params);\n if (gas === null || !Number.isFinite(gas)) return null;\n value -= gas;\n }\n return value;\n };\n}\n\n// ---------------------------------------------------------------------------\n// Value information for the user (SDK-127): never a refusal, always a fact.\n// ---------------------------------------------------------------------------\n\n/**\n * A quote's value in USD: what the user pays, what arrives, the loss, and a better alternative when\n * one exists. Use it to warn before a bad-value swap.\n */\nexport interface QuoteValue {\n provider: string;\n /** USD the user pays: the source amount at the current price. null when unpriced. */\n valueUsdIn: number | null;\n /** USD the quote delivers: the expected `destAmount` at the current price, minus a native fee paid on top. null when unpriced. */\n valueUsdOut: number | null;\n /** (in − out) / in × 100. Positive = the user receives less value than they pay. null when either side is unpriced. */\n lossPct: number | null;\n /** Another provider in the same set that delivers more than `betterByPct` more. Every quote of a request pays out the\n * same destination token, so the comparison is by delivered USD when priced and by raw `destAmount` otherwise. */\n betterAlternative?: {provider: string; valueUsdOut: number | null; destAmount: string; byPct: number};\n /** The venue's own price impact in basis points (`providerData.priceImpactBps`), when it measures one. */\n priceImpactBps?: number;\n}\n\n/** Options for quote valuation. */\nexport interface QuoteValueOptions {\n /** How much more (percent of this quote's value) another provider must deliver to be named as the better alternative. Default 2. */\n betterByPct?: number;\n}\n\nexport type ValueParams = Pick<QuoteParams, \"sourceChain\" | \"sourceToken\" | \"destChain\" | \"destToken\" | \"amountIn\">;\nexport type ValueQuote = Pick<Quote, \"provider\" | \"destAmount\"> & Partial<Pick<Quote, \"txRequest\" | \"providerData\">>;\n\n/** The catalog asset for a token given as a contract / asset id (the wire form) or as a symbol (what apps pass for the source). */\nfunction assetFor(chain: string, token: string) {\n const byToken = ccAssetByToken(chain, token);\n if (byToken) return byToken;\n const want = token.toLowerCase();\n return ccChain(chain)?.assets.find((a) => a.symbol.toLowerCase() === want);\n}\n\n/**\n * USD in / out / loss for every quote of one request, and the better\n * alternative inside the set. Prices are the caller's current spot prices\n * (symbol → USD). The owner's rule (2026-10-16): the wallet shows this and\n * says \"be careful\"; it never blocks — the Oct 16 funded run lost ~$33 on\n * two Uniswap legs that nothing compared to the other venues' quotes.\n */\nexport function quoteValues(prices: Readonly<Record<string, number>>, params: ValueParams, quotes: readonly ValueQuote[], options: QuoteValueOptions = {}): QuoteValue[] {\n const betterBy = options.betterByPct ?? 2;\n const src = assetFor(params.sourceChain, params.sourceToken);\n const dest = assetFor(params.destChain, params.destToken);\n const srcPrice = src ? priceOf(prices, src.symbol) : null;\n const destPrice = dest ? priceOf(prices, dest.symbol) : null;\n let valueUsdIn: number | null = null;\n if (src && srcPrice !== null) {\n try {\n valueUsdIn = units(params.amountIn, src.decimals) * srcPrice;\n } catch {\n valueUsdIn = null;\n }\n }\n const out: QuoteValue[] = quotes.map((q) => {\n let valueUsdOut: number | null = null;\n if (dest && destPrice !== null) {\n try {\n valueUsdOut = units(q.destAmount, dest.decimals) * destPrice;\n const nativeFee = q.txRequest?.nativeFee;\n if (nativeFee && BigInt(nativeFee) > 0n) {\n const native = ccAssetByToken(params.sourceChain, \"\");\n const nativePrice = native ? priceOf(prices, native.symbol) : null;\n if (native && nativePrice !== null) valueUsdOut -= units(nativeFee, native.decimals) * nativePrice;\n }\n } catch {\n valueUsdOut = null;\n }\n }\n const lossPct = valueUsdIn !== null && valueUsdIn > 0 && valueUsdOut !== null ? ((valueUsdIn - valueUsdOut) / valueUsdIn) * 100 : null;\n const impact = q.providerData?.priceImpactBps;\n const priceImpactBps = typeof impact === \"string\" && /^\\d+$/.test(impact) ? Number(impact) : undefined;\n const v: QuoteValue = {provider: q.provider, valueUsdIn, valueUsdOut, lossPct};\n if (priceImpactBps !== undefined) v.priceImpactBps = priceImpactBps;\n return v;\n });\n // The best delivery in the set names itself as the alternative for every quote it beats by more than betterBy %.\n // Priced: by delivered USD (native fees netted). Unpriced: by raw destAmount — same token for every quote, so the ratio is exact.\n const allPriced = out.length > 1 && out.every((v) => v.valueUsdOut !== null);\n if (out.length > 1) {\n const measure = (v: QuoteValue): number => (allPriced ? v.valueUsdOut! : bigintToNumber(BigInt(quotes.find((q) => q.provider === v.provider)!.destAmount)));\n const top = out.reduce((a, b) => (measure(b) > measure(a) ? b : a));\n const topQuote = quotes.find((q) => q.provider === top.provider)!;\n for (const v of out) {\n if (v === top) continue;\n const mine = measure(v);\n const byPct = mine > 0 ? ((measure(top) - mine) / mine) * 100 : Infinity;\n if (byPct > betterBy) v.betterAlternative = {provider: top.provider, valueUsdOut: top.valueUsdOut, destAmount: topQuote.destAmount, byPct};\n }\n }\n return out;\n}\n","/**\n * The optional aggregator: one swap2 protocol that quotes every provider the\n * caller installed and passed in, in parallel, and executes the best route.\n *\n * Every provider package (`@anywalletkit/protocol-swap2-lifi`, `-near-intents`,\n * `-thorchain`, `-omniston`) also works on its own through its single-provider\n * protocol class; this package is only for callers who want an auction across\n * several of them. It has no dependency on any provider: capabilities\n * (supported chains / pairs) come from the providers themselves, or — for a\n * `remoteProvider` stub — from the `supportsChain`/`supportsChainPair` options\n * the caller fills in.\n *\n * ```ts\n * const swap2 = new RouterSwap2Protocol(account, {\n * fromChain: \"eip155:1\",\n * providers: [lifiProvider({...}), nearIntentsProvider({...})],\n * })\n * ```\n */\nimport {\n BaseSwap2Protocol,\n type Swap2Account,\n type Swap2EngineConfig,\n} from \"@anywalletkit/protocol-swap2-core/swap2/base\";\nimport type {CrossChainProvider, Quote, QuoteParams} from \"@anywalletkit/protocol-swap2-core/types\";\nimport type {ActivityItem, ChainTx, DescribeActivityContext, Swap2Options, Swap2Quote} from \"@anywalletkit/core\";\nimport {CrossChainRouter, type RouteSet, type RouterOptions} from \"../router.js\";\n\n/** One route in a picker: the public quote plus its place in the auction. */\nexport interface Swap2Route {\n /** Provider name. */\n provider: string;\n /** The provider's quote. */\n quote: Swap2Quote;\n /** Net USD value when the router prices routes (`valueUsd`), else null. */\n netValueUsd: number | null;\n /** Value against the best route, 0..1. */\n relativeValue: number;\n /** `best` (most value within the tie band) and/or `fastest` (lowest ETA). */\n tags: (\"best\" | \"fastest\")[];\n}\n\n/**\n * Options for {@link RouterSwap2Protocol}: the providers (or a ready router), route preference and\n * the engine options.\n */\nexport interface RouterSwap2Config extends Swap2EngineConfig {\n /** The providers to aggregate over. Only what the caller installs is bundled. */\n providers?: CrossChainProvider[];\n /**\n * Or a ready auction engine (e.g. to share one between protocols or tune its\n * score weights). Exactly one of `providers` / `router` is required.\n */\n router?: CrossChainRouter;\n /** Order inside a price tie for a router built from `providers`, e.g. \"price:0.7,speed:0.2,reliability:0.1\". */\n weights?: string;\n /** Net USD value of a quote for a router built from `providers` — see `usdValue(prices)`. */\n valueUsd?: RouterOptions[\"valueUsd\"];\n /** Fraction of the best value inside which routes tie on price (default 0.002). */\n tieBand?: number;\n /** What `swap2()` / `quoteSwap2()` execute when several routes answer: the best (default) or the fastest. */\n prefer?: \"best\" | \"fastest\";\n}\n\n/**\n * A swap2 protocol that asks every installed provider in parallel, checks each quote the same way,\n * and executes the chosen route. Pass exactly one of `providers` or `router`.\n *\n * ```ts\n * const swap2 = new RouterSwap2Protocol(account, {\n * fromChain: 'eip155:1',\n * providers: [lifiProvider(), nearIntentsProvider(), cctpProvider()],\n * })\n * const quote = await swap2.quoteSwap2({ fromToken: 'USDC', toToken: 'USDC', toChain: 'eip155:8453', fromTokenAmount: 100_000_000n })\n * ```\n */\nexport class RouterSwap2Protocol extends BaseSwap2Protocol {\n private readonly router: CrossChainRouter;\n private readonly account: Swap2Account | undefined;\n private readonly routerConfig: RouterSwap2Config;\n\n constructor(account: Swap2Account | undefined, config: RouterSwap2Config) {\n super(account, config);\n if (!!config.router === !!config.providers) {\n throw new Error(\"swap2: RouterSwap2Protocol needs exactly one of `providers` or `router`\");\n }\n if (config.prefer !== undefined && config.prefer !== \"best\" && config.prefer !== \"fastest\") {\n throw new Error(\"swap2: prefer must be \\\"best\\\" or \\\"fastest\\\"\");\n }\n this.router = config.router ?? new CrossChainRouter(config.providers!, {\n ...(config.weights !== undefined ? {weights: config.weights} : {}),\n ...(config.valueUsd ? {valueUsd: config.valueUsd} : {}),\n ...(config.tieBand !== undefined ? {tieBand: config.tieBand} : {}),\n });\n this.account = account;\n this.routerConfig = config;\n }\n\n protected resolveQuote(params: QuoteParams): Promise<Quote | null> {\n return this.router.getBestQuote(params, this.routerConfig.prefer ? {prefer: this.routerConfig.prefer} : undefined);\n }\n\n /**\n * Every route for a picker, ranked, with the best and the fastest tagged.\n * `onUpdate` gets the ranked list each time another provider answers, so a\n * UI shows the first price as soon as the fastest venue replies. Routes the\n * caller's floor or fee caps refuse are left out. Execute the one the user\n * picks with `using(route.provider).swap2(...)`.\n */\n async quoteSwap2Routes(options: Swap2Options, opts?: {onUpdate?: (routes: Swap2Route[], pending: string[]) => void}): Promise<Swap2Route[]> {\n const snapshot = await this.prepareOptions(this.snapshotOf(options));\n const view = (set: RouteSet): Swap2Route[] =>\n set.quotes.flatMap((q) => {\n const quote = this.routeQuote(q, snapshot);\n return quote ? [{provider: q.provider, quote, netValueUsd: q.netValueUsd, relativeValue: q.relativeValue, tags: [...q.tags]}] : [];\n });\n const set = await this.router.getQuotes(this.toParams(snapshot, true), opts?.onUpdate\n ? {onUpdate: (partial) => opts.onUpdate!(view(partial), partial.pending)}\n : undefined);\n return set ? view(set) : [];\n }\n\n /** This protocol pinned to one provider — the route a user picked from `quoteSwap2Routes`. */\n using(provider: string): RouterSwap2Protocol {\n const {providers: _p, router: _r, ...rest} = this.routerConfig;\n return new RouterSwap2Protocol(this.account, {...rest, router: this.router.only(provider)});\n }\n\n protected override noRouteDetail(): string {\n return this.router.lastRejections.join(\"; \").slice(0, 400);\n }\n\n protected providerFor(name: string): CrossChainProvider | undefined {\n return this.router.getProvider(name);\n }\n\n /** Delegates to every provider the router holds (first match wins); null with no providers. */\n override describeActivity(tx: ChainTx, ctx: DescribeActivityContext): ActivityItem | null {\n return this.router.describeActivity(tx, ctx);\n }\n\n protected chainSupported(caip2: string): boolean {\n return this.router.supportsChain(caip2);\n }\n\n protected override pairSupported(fromChain: string, toChain: string): boolean {\n return this.router.supportsChainPair(fromChain, toChain);\n }\n\n /** Release the providers' resources (timers, sockets). */\n close(): void {\n this.router.close();\n }\n}\n"],"mappings":"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","names":["import_core","set"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/router.ts","../src/value.ts","../src/swap2/router.ts"],"sourcesContent":["/**\n * @anywalletkit/protocol-swap2-router — the OPTIONAL swap2 aggregator.\n *\n * Every swap2 provider module runs on its own (install only\n * `@anywalletkit/protocol-swap2-lifi` and use `LifiSwap2Protocol`). Install\n * this package when you want one protocol that auctions a route across several\n * providers: pass the providers you installed and it quotes them in parallel,\n * validates every quote, scores them and executes the winner.\n *\n * ```ts\n * import {RouterSwap2Protocol} from \"@anywalletkit/protocol-swap2-router\";\n * import {lifiProvider} from \"@anywalletkit/protocol-swap2-lifi/provider\";\n * import {nearIntentsProvider} from \"@anywalletkit/protocol-swap2-near-intents/provider\";\n *\n * const swap2 = new RouterSwap2Protocol(account, {\n * fromChain: \"eip155:1\",\n * providers: [lifiProvider({}), nearIntentsProvider({})],\n * });\n * ```\n *\n * Providers reached through a backend use `remoteProvider` (re-exported from\n * the core package); give it `supportsChain`/`supportsChainPair` — e.g. from\n * the provider package's `config` export — so discovery knows its coverage.\n */\nexport {CrossChainRouter, type RouterOptions, type RankedQuote, type RouteSet} from \"./router.js\";\nexport {usdValue, quoteValues} from \"./value.js\";\nexport type {QuoteValue, QuoteValueOptions} from \"./value.js\";\nexport {RouterSwap2Protocol, type RouterSwap2Config, type Swap2Route} from \"./swap2/router.js\";\nexport {RouterSwap2Protocol as default} from \"./swap2/router.js\";\nexport {remoteProvider, type RemoteProviderOptions} from \"@anywalletkit/protocol-swap2-core/remote\";\nexport type * from \"@anywalletkit/protocol-swap2-core/types\";\nexport type { ValueParams, ValueQuote } from \"./value.js\"\n","/**\n * The auction engine of the optional aggregator: routes a cross-chain delivery\n * over whichever providers the caller installed and passed in. Protocol\n * modules never need it — each one runs standalone on @anywalletkit/protocol-swap2-core.\n */\nimport type {\n CrossChainProvider,\n IntentRef,\n IntentStatus,\n Quote,\n QuoteParams,\n RoutedQuote,\n ScoreWeights,\n} from \"@anywalletkit/protocol-swap2-core/types\";\nimport {remotePinRefusal, validQuote} from \"@anywalletkit/protocol-swap2-core/validate\";\nimport type {ActivityItem, ChainTx, DescribeActivityContext} from \"@anywalletkit/core\";\nimport {bigintToNumber} from \"@anywalletkit/core\";\n\nconst DEFAULT_WEIGHTS: ScoreWeights = {price: 0.6, speed: 0.3, reliability: 0.1};\n/** Quotes within 0.2% of the best net value count as the same price. */\nconst DEFAULT_TIE_BAND = 0.002;\n\nexport interface RouterOptions {\n /**\n * \"price:0.6,speed:0.3,reliability:0.1\" — how quotes inside the tie band\n * (same price, within `tieBand`) are ordered. Price itself always leads.\n */\n weights?: string;\n /**\n * What a quote is worth to the user in USD: its guaranteed output minus what\n * the route charges on top (a native bridge fee, the source gas). Return null\n * when it cannot be priced — the auction then compares guaranteed outputs.\n * `usdValue(prices)` builds one from a symbol → USD price map.\n */\n valueUsd?: (quote: Quote, params: QuoteParams) => number | null;\n /** Fraction of the best net value inside which quotes tie on price (default 0.002). */\n tieBand?: number;\n}\n\n/** A validated quote with its place in the auction. */\nexport interface RankedQuote extends Quote {\n /** Net USD value (`valueUsd`), or null when the auction compared raw outputs. */\n netValueUsd: number | null;\n /** This quote's value against the best one, 0..1 (1 = the best price). */\n relativeValue: number;\n /** \"best\": the pick (best price; faster/more reliable among equal prices). \"fastest\": the lowest ETA. */\n tags: (\"best\" | \"fastest\")[];\n}\n\n/** Every validated route for one request, ranked by value. */\nexport interface RouteSet {\n /** Every validated route, best first. */\n quotes: RankedQuote[];\n /** Most delivered value (net of fees when priced) within the tie band. */\n best: RankedQuote;\n /** Lowest ETA. */\n fastest: RankedQuote;\n /** Providers still quoting (only non-empty in progressive `onUpdate` snapshots). */\n pending: string[];\n /** Why the venues that sat out did (same as `lastRejections`). */\n rejections: string[];\n}\n// LI.FI's /quote routinely takes ~3.5s (it builds executable calldata) — 4s\n// raced it out of every round. All providers still run in parallel.\nconst QUOTE_TIMEOUT_MS = 8000;\n/** Pinned single-venue (execution) budget — see the comment at the call site. */\nconst SOLO_QUOTE_TIMEOUT_MS = 25_000;\n\nfunction parseWeights(spec?: string): ScoreWeights {\n if (!spec) return DEFAULT_WEIGHTS;\n const w = {...DEFAULT_WEIGHTS};\n for (const part of spec.split(\",\")) {\n const [k, v] = part.split(\":\");\n const n = Number(v);\n if ((k === \"price\" || k === \"speed\" || k === \"reliability\") && Number.isFinite(n)) {\n w[k] = Math.max(0, n);\n }\n }\n return w;\n}\n\nasync function withTimeout<T>(p: Promise<T>, ms: number): Promise<T | null> {\n return new Promise((resolve, reject) => {\n // Timeouts and failures must REJECT: the old `() => resolve(null)` arm\n // swallowed every provider error — including forwarded venue refusals —\n // into a null indistinguishable from \"no route\", which made execution\n // failures undiagnosable from the surface (the '(c2)' hunt of 2026-08-31).\n const timer = setTimeout(() => reject(new Error(`quote timed out after ${ms}ms`)), ms);\n p.then(resolve, reject).finally(() => clearTimeout(timer));\n });\n}\n\n/**\n * Routes a cross-chain delivery over pluggable providers: queries all that\n * support the route in parallel (with a timeout so a slow provider can't block),\n * normalizes their quotes, scores by configurable weights, and returns the best\n * tagged with `routeScore`. A failed/slow provider simply doesn't participate.\n */\nexport class CrossChainRouter {\n private readonly providers: CrossChainProvider[];\n /** Why the venues of the LAST getBestQuote call sat out — for error surfaces. */\n private _lastRejections: string[] = [];\n /** Why providers sat out the last auction, one line each. */\n get lastRejections(): readonly string[] {\n return this._lastRejections;\n }\n private readonly weights: ScoreWeights;\n private readonly valueUsd: RouterOptions[\"valueUsd\"];\n private readonly tieBand: number;\n private readonly options: RouterOptions;\n\n constructor(providers: CrossChainProvider[], options?: string | RouterOptions) {\n const opts: RouterOptions = typeof options === \"string\" ? {weights: options} : {...(options ?? {})};\n if (opts.tieBand !== undefined && !(Number.isFinite(opts.tieBand) && opts.tieBand >= 0 && opts.tieBand < 1)) {\n throw new Error(\"cross-chain router: tieBand must be a fraction in [0, 1)\");\n }\n const names = new Set<string>();\n for (const provider of providers) {\n if (typeof provider.name !== \"string\" || !/^[A-Za-z0-9_-]+$/.test(provider.name) || names.has(provider.name)) {\n throw new Error(`cross-chain router: invalid or duplicate provider name '${String(provider.name)}'`);\n }\n names.add(provider.name);\n }\n // Snapshot the dispatch surface. A caller mutating provider.name or method\n // properties after construction must not redirect quote→build/status.\n this.providers = providers.map((provider) => ({\n name: provider.name,\n enabled: provider.enabled.bind(provider),\n supportsRoute: provider.supportsRoute.bind(provider),\n getQuote: provider.getQuote.bind(provider),\n buildDeposit: provider.buildDeposit.bind(provider),\n trackIntent: provider.trackIntent.bind(provider),\n ...(provider.preflightDeposit ? {preflightDeposit: provider.preflightDeposit.bind(provider)} : {}),\n ...(provider.notifyDeposit ? {notifyDeposit: provider.notifyDeposit.bind(provider)} : {}),\n ...(provider.registerSignedOrder ? {registerSignedOrder: provider.registerSignedOrder.bind(provider)} : {}),\n // Two-phase routes (CCTP): the destination claim. Missing here, the engine\n // and the server both reported \"provider 'cctp' has no claim step\" (2026-10-13).\n ...(provider.buildClaim ? {buildClaim: provider.buildClaim.bind(provider)} : {}),\n ...(provider.claimTargets ? {claimTargets: provider.claimTargets.bind(provider)} : {}),\n // A remote stub's marker and the app's pins (scan 2026-10-27 modules, F8/F9/F16): dropped here, the engine took a\n // remote provider for a local one and checked its calldata against the backend's own addresses.\n ...(provider.remote === true ? {remote: true} : {}),\n ...(provider.verifiesBuilds === true ? {verifiesBuilds: true} : {}),\n ...(provider.verifiesQuotes === true ? {verifiesQuotes: true} : {}),\n ...(provider.depositAddressRoutes === true ? {depositAddressRoutes: true} : {}),\n ...(provider.callTargets ? {callTargets: provider.callTargets.bind(provider)} : {}),\n ...(provider.spenders ? {spenders: provider.spenders.bind(provider)} : {}),\n ...(provider.close ? {close: provider.close.bind(provider)} : {}),\n ...(provider.supportsChain ? {supportsChain: provider.supportsChain.bind(provider)} : {}),\n ...(provider.supportsChainPair ? {supportsChainPair: provider.supportsChainPair.bind(provider)} : {}),\n ...(provider.describeActivity ? {describeActivity: provider.describeActivity.bind(provider)} : {}),\n ...(provider.supportsSameChain !== undefined ? {supportsSameChain: provider.supportsSameChain} : {}),\n }));\n this.weights = parseWeights(opts.weights);\n this.valueUsd = opts.valueUsd;\n this.tieBand = opts.tieBand ?? DEFAULT_TIE_BAND;\n this.options = opts;\n }\n\n /** The same auction restricted to one provider — to execute the route a user picked. */\n only(name: string): CrossChainRouter {\n const provider = this.getProvider(name);\n if (!provider) throw new Error(`cross-chain router: provider '${name}' is not registered`);\n return new CrossChainRouter([provider], this.options);\n }\n\n /**\n * Activity recognition across the installed providers: the first one that\n * claims the transaction describes it. Null when none does (or none is held).\n */\n describeActivity(tx: ChainTx, ctx: DescribeActivityContext): ActivityItem | null {\n for (const provider of this.providers) {\n const item = provider.describeActivity?.(tx, ctx);\n if (item) return item;\n }\n return null;\n }\n\n /** A provider by name. */\n getProvider(name: string): CrossChainProvider | undefined {\n return this.providers.find((p) => p.name === name);\n }\n\n /** True when a provider of that name is installed. */\n hasProvider(name: string): boolean {\n return this.providers.some((p) => p.name === name);\n }\n\n /** True when that provider is installed and enabled. */\n hasEnabledProvider(name: string): boolean {\n return this.providers.some((p) => {\n try { return p.name === name && p.enabled(); } catch { return false; }\n });\n }\n\n /** True when any enabled provider declares the chain. */\n supportsChain(caip2: string): boolean {\n return this.providers.some((p) => {\n try { return p.enabled() && !!p.supportsChain?.(caip2); } catch { return false; }\n });\n }\n\n /** True when any enabled provider declares the chain pair. */\n supportsChainPair(fromChain: string, toChain: string): boolean {\n return this.providers.some((p) => {\n try {\n return p.enabled() && (p.supportsChainPair?.(fromChain, toChain) ?? false);\n } catch { return false; }\n });\n }\n\n /**\n * The auction's pick: the best price (net of native fees and gas when\n * `valueUsd` is set; faster, then more reliable, among equal prices), or\n * the fastest route with `prefer: \"fastest\"`.\n */\n async getBestQuote(\n params: QuoteParams,\n options?: {requireImmediateExecution?: boolean; prefer?: \"best\" | \"fastest\"},\n ): Promise<RoutedQuote | null> {\n const set = await this.getQuotes(params, options);\n if (!set) return null;\n const pick = options?.prefer === \"fastest\" ? set.fastest : set.best;\n const {netValueUsd: _n, relativeValue: _r, tags: _t, ...quote} = pick;\n return {\n ...quote,\n routeScore: {\n score: pick.relativeValue,\n weights: this.weights,\n candidates: set.quotes.map((q) => ({\n provider: q.provider,\n sourceAmount: q.sourceAmount,\n etaSeconds: q.etaSeconds,\n score: q.relativeValue,\n minDestAmount: q.minDestAmount,\n netValueUsd: q.netValueUsd,\n })),\n },\n };\n }\n\n /**\n * Every validated route, ranked — for a route picker that shows the best and\n * the fastest and lets the user choose. Providers run in parallel; with\n * `onUpdate` each one that answers re-publishes the ranked set at once (the\n * first price shows in the time of the fastest venue, not the slowest).\n */\n async getQuotes(\n params: QuoteParams,\n options?: {requireImmediateExecution?: boolean; onUpdate?: (set: RouteSet) => void},\n ): Promise<RouteSet | null> {\n // A public engine caller — or one provider running in the same auction —\n // must not be able to rewrite another provider's request while async quote\n // work is in flight. QuoteParams is intentionally flat, so a frozen copy is\n // a complete execution snapshot.\n const rejections: string[] = [];\n this._lastRejections = rejections;\n const snapshot = Object.freeze({...params});\n const from = Object.freeze({chain: snapshot.sourceChain, token: snapshot.sourceToken});\n const to = Object.freeze({chain: snapshot.destChain, token: snapshot.destToken});\n // Only enabled (validated) providers that can serve the route participate.\n let eligible = this.providers.filter((p) => {\n try { return p.enabled() && p.supportsRoute(from, to); } catch { return false; }\n });\n if (snapshot.sourceChain === snapshot.destChain) {\n eligible = eligible.filter((p) => p.supportsSameChain === true);\n }\n if (eligible.length === 0) return null;\n\n // The short timeout protects the AUCTION — one slow venue must not hold\n // the others hostage. With a single eligible provider (a pinned execution\n // re-quote) there is nobody to protect, and a live deposit-creating quote\n // legitimately takes longer than a dry one (serverless hop + upstream\n // retries) — starving it surfaced as a terminal \"no route\" on execution.\n const timeoutMs = eligible.length === 1 ? SOLO_QUOTE_TIMEOUT_MS : QUOTE_TIMEOUT_MS;\n // Each venue names its own refusal (per call, so concurrent quotes cannot race).\n const refusals: (string | undefined)[] = [];\n const accepted: Quote[] = [];\n const pending = new Set(eligible.map((p) => p.name));\n const publish = () => {\n if (!options?.onUpdate || accepted.length === 0) return;\n const set = this.rank(accepted, snapshot, [...pending], rejections);\n try { options.onUpdate(set); } catch { /* an observer must not break the auction */ }\n };\n await Promise.all(eligible.map(async (p, i) => {\n const controller = new AbortController();\n const own = Object.freeze({...snapshot, onRefusal: (reason: string) => {\n refusals[i] ??= reason.startsWith(`${p.name}:`) ? reason : `${p.name}: ${reason}`;\n try { snapshot.onRefusal?.(reason); } catch { /* diagnostics only */ }\n }});\n let q: Quote | null = null;\n try {\n q = await withTimeout(p.getQuote(own, controller.signal), timeoutMs);\n if (!q) {\n // A provider RETURNING null (vs throwing) was the one silent path\n // left — record it so the surfaced no-route error names the venue.\n rejections.push(refusals[i] ?? `${p.name}: returned no quote`);\n } else if (!validQuote(q, snapshot, p.name)) {\n const reason = `${p.name}: rejected by validation (minDest=${q.minDestAmount} vs floor=${snapshot.minAmountOut ?? \"-\"}, validUntil=${q.validUntilMs}, now=${Date.now()})`;\n rejections.push(reason);\n console.warn(`swap2-router: ${reason}`);\n q = null;\n } else {\n // A remote stub's route that calls or approves an address the app did not pin: execution would refuse it.\n const unpinned = remotePinRefusal(p, q, snapshot.sourceChain);\n if (unpinned) {\n rejections.push(unpinned);\n console.warn(`swap2-router: ${unpinned}`);\n q = null;\n } else if (options?.requireImmediateExecution && !(q.depositAddress.length > 0 || q.txRequest !== undefined)) {\n // Legacy deposit-address screens cannot execute order-based quotes that\n // require a separate build/sign/register lifecycle.\n q = null;\n }\n }\n } catch (err) {\n // A failed venue sitting out silently is indistinguishable from \"no\n // route\" — record why (surfaced through lastRejections) and say it in\n // the console (same posture as onModuleSkipped).\n const reason = `${p.name}: ${err instanceof Error ? err.message.slice(0, 160) : String(err).slice(0, 160)}`;\n rejections.push(reason);\n console.warn(`swap2-router: quote failed — ${reason}`);\n q = null;\n } finally {\n controller.abort();\n }\n pending.delete(p.name);\n // Provider identity is an execution security boundary. Never trust the\n // provider field returned by an untrusted adapter; bind it to its slot.\n if (q) accepted.push({...q, provider: p.name});\n publish();\n }));\n if (accepted.length === 0) return null;\n return this.rank(accepted, snapshot, [], rejections);\n }\n\n /** Status from the named provider; `failed` when it is not installed. */\n async trackIntent(providerName: string, ref: IntentRef): Promise<IntentStatus> {\n const provider = this.getProvider(providerName);\n if (!provider) return {state: \"failed\"};\n return provider.trackIntent(ref);\n }\n\n /** Forward a source-broadcast notification to the intent's provider. */\n async notifyDeposit(providerName: string, intentId: string, txHash: string): Promise<void> {\n await this.getProvider(providerName)?.notifyDeposit?.(intentId, txHash);\n }\n\n /** Release every provider's resources. */\n close(): void {\n for (const provider of this.providers) provider.close?.();\n }\n\n /**\n * Price first: each quote's value is its net USD (`valueUsd`) — or, when any\n * quote cannot be priced, its guaranteed output — against the best one.\n * Quotes within `tieBand` of the best are the same price; among those the\n * weights order speed and reliability. A $0.01 edge no longer beats a route\n * that lands in seconds instead of twenty minutes, and a route that charges\n * a native bridge fee on top no longer wins on its gross output.\n */\n private rank(quotes: Quote[], params: QuoteParams, pending: string[], rejections: string[]): RouteSet {\n const usd = this.valueUsd ? quotes.map((q) => {\n try {\n const v = this.valueUsd!(q, params);\n return typeof v === \"number\" && Number.isFinite(v) ? v : null;\n } catch { return null; }\n }) : quotes.map(() => null);\n const priced = usd.every((v) => v !== null);\n let relative: number[];\n if (priced) {\n const values = usd as number[];\n const max = Math.max(...values);\n relative = values.map((v) => (max > 0 ? Math.max(0, v) / max : v >= max ? 1 : 0));\n } else {\n const outs = quotes.map((q) => BigInt(q.minDestAmount));\n const max = outs.reduce((a, b) => (b > a ? b : a));\n relative = outs.map((o) => fraction(o, max));\n }\n const ranked: RankedQuote[] = quotes.map((q, i) => ({\n ...q,\n netValueUsd: priced ? usd[i]! : null,\n relativeValue: relative[i]!,\n tags: [],\n }));\n\n const tier = ranked.filter((q) => q.relativeValue >= 1 - this.tieBand - 1e-12);\n const etas = tier.map((q) => q.etaSeconds);\n const minEta = Math.min(...etas);\n const maxEta = Math.max(...etas);\n const w = this.weights;\n const tieScore = (q: RankedQuote) =>\n w.price * q.relativeValue +\n w.speed * (maxEta === minEta ? 1 : (maxEta - q.etaSeconds) / (maxEta - minEta)) +\n w.reliability * q.reliability;\n const best = tier.reduce((a, b) => (tieScore(b) > tieScore(a) ? b : a));\n const fastest = ranked.reduce((a, b) =>\n b.etaSeconds < a.etaSeconds || (b.etaSeconds === a.etaSeconds && b.relativeValue > a.relativeValue) ? b : a);\n best.tags.push(\"best\");\n fastest.tags.push(\"fastest\");\n\n // The list reads top-down by value; the pick leads its price tier.\n ranked.sort((a, b) => (a === best ? -1 : b === best ? 1 : b.relativeValue - a.relativeValue || a.etaSeconds - b.etaSeconds));\n return {quotes: ranked, best, fastest, pending, rejections: [...rejections]};\n }\n}\n\n/** Ratio of two non-negative bigints as a 0..1 number. */\nfunction fraction(num: bigint, den: bigint): number {\n if (den === 0n) return 1;\n // scale to keep precision, then to float\n return bigintToNumber((num * 10_000n) / den) / 10_000;\n}\n","import {bigintToNumber, bigintToUnits} from \"@anywalletkit/core\";\nimport {ccAssetByToken, ccChain} from \"@anywalletkit/swap2-assets\";\nimport type {Quote, QuoteParams} from \"@anywalletkit/protocol-swap2-core/types\";\n\n/** Stables priced at par when the map has no entry for them. */\nconst PAR = /^(USDC|USDT|USDT0|USD₮0|DAI|USDC\\.E)$/i;\n\n/** symbol → USD, trying the exact symbol, upper case, the unwrapped native (WETH → ETH, wS → S), then par for stables. */\nfunction priceOf(prices: Readonly<Record<string, number>>, symbol: string): number | null {\n const tries = [symbol, symbol.toUpperCase()];\n if (/^w/i.test(symbol) && symbol.length > 2) tries.push(symbol.slice(1), symbol.slice(1).toUpperCase());\n for (const t of tries) {\n const p = prices[t];\n if (typeof p === \"number\" && Number.isFinite(p) && p > 0) return p;\n }\n return PAR.test(symbol) ? 1 : null;\n}\n\nconst units = (amount: string | bigint, decimals: number) => bigintToUnits(BigInt(amount), decimals);\n\n/**\n * A `valueUsd` for the router: the guaranteed output in USD, minus the native\n * fee the route charges on top of the input (bridge messaging fees), minus\n * the source gas when `gasUsd` can say it. null when a needed price is missing\n * — the auction then falls back to comparing guaranteed outputs.\n */\nexport function usdValue(\n prices: Readonly<Record<string, number>>,\n options?: {gasUsd?: (quote: Quote, params: QuoteParams) => number | null},\n): (quote: Quote, params: QuoteParams) => number | null {\n return (quote, params) => {\n const dest = ccAssetByToken(params.destChain, params.destToken);\n if (!dest) return null;\n const destPrice = priceOf(prices, dest.symbol);\n if (destPrice === null) return null;\n let value = units(quote.minDestAmount, dest.decimals) * destPrice;\n const nativeFee = quote.txRequest?.nativeFee;\n if (nativeFee && BigInt(nativeFee) > 0n) {\n const native = ccAssetByToken(params.sourceChain, \"\");\n const nativePrice = native ? priceOf(prices, native.symbol) : null;\n if (!native || nativePrice === null) return null;\n value -= units(nativeFee, native.decimals) * nativePrice;\n }\n if (options?.gasUsd) {\n const gas = options.gasUsd(quote, params);\n if (gas === null || !Number.isFinite(gas)) return null;\n value -= gas;\n }\n return value;\n };\n}\n\n// ---------------------------------------------------------------------------\n// Value information for the user (SDK-127): never a refusal, always a fact.\n// ---------------------------------------------------------------------------\n\n/**\n * A quote's value in USD: what the user pays, what arrives, the loss, and a better alternative when\n * one exists. Use it to warn before a bad-value swap.\n */\nexport interface QuoteValue {\n provider: string;\n /** USD the user pays: the source amount at the current price. null when unpriced. */\n valueUsdIn: number | null;\n /** USD the quote delivers: the expected `destAmount` at the current price, minus a native fee paid on top. null when unpriced. */\n valueUsdOut: number | null;\n /** (in − out) / in × 100. Positive = the user receives less value than they pay. null when either side is unpriced. */\n lossPct: number | null;\n /** Another provider in the same set that delivers more than `betterByPct` more. Every quote of a request pays out the\n * same destination token, so the comparison is by delivered USD when priced and by raw `destAmount` otherwise. */\n betterAlternative?: {provider: string; valueUsdOut: number | null; destAmount: string; byPct: number};\n /** The venue's own price impact in basis points (`providerData.priceImpactBps`), when it measures one. */\n priceImpactBps?: number;\n}\n\n/** Options for quote valuation. */\nexport interface QuoteValueOptions {\n /** How much more (percent of this quote's value) another provider must deliver to be named as the better alternative. Default 2. */\n betterByPct?: number;\n}\n\nexport type ValueParams = Pick<QuoteParams, \"sourceChain\" | \"sourceToken\" | \"destChain\" | \"destToken\" | \"amountIn\">;\nexport type ValueQuote = Pick<Quote, \"provider\" | \"destAmount\"> & Partial<Pick<Quote, \"txRequest\" | \"providerData\">>;\n\n/** The catalog asset for a token given as a contract / asset id (the wire form) or as a symbol (what apps pass for the source). */\nfunction assetFor(chain: string, token: string) {\n const byToken = ccAssetByToken(chain, token);\n if (byToken) return byToken;\n const want = token.toLowerCase();\n return ccChain(chain)?.assets.find((a) => a.symbol.toLowerCase() === want);\n}\n\n/**\n * USD in / out / loss for every quote of one request, and the better\n * alternative inside the set. Prices are the caller's current spot prices\n * (symbol → USD). The owner's rule (2026-10-16): the wallet shows this and\n * says \"be careful\"; it never blocks — the Oct 16 funded run lost ~$33 on\n * two Uniswap legs that nothing compared to the other venues' quotes.\n */\nexport function quoteValues(prices: Readonly<Record<string, number>>, params: ValueParams, quotes: readonly ValueQuote[], options: QuoteValueOptions = {}): QuoteValue[] {\n const betterBy = options.betterByPct ?? 2;\n const src = assetFor(params.sourceChain, params.sourceToken);\n const dest = assetFor(params.destChain, params.destToken);\n const srcPrice = src ? priceOf(prices, src.symbol) : null;\n const destPrice = dest ? priceOf(prices, dest.symbol) : null;\n let valueUsdIn: number | null = null;\n if (src && srcPrice !== null) {\n try {\n valueUsdIn = units(params.amountIn, src.decimals) * srcPrice;\n } catch {\n valueUsdIn = null;\n }\n }\n const out: QuoteValue[] = quotes.map((q) => {\n let valueUsdOut: number | null = null;\n if (dest && destPrice !== null) {\n try {\n valueUsdOut = units(q.destAmount, dest.decimals) * destPrice;\n const nativeFee = q.txRequest?.nativeFee;\n if (nativeFee && BigInt(nativeFee) > 0n) {\n const native = ccAssetByToken(params.sourceChain, \"\");\n const nativePrice = native ? priceOf(prices, native.symbol) : null;\n if (native && nativePrice !== null) valueUsdOut -= units(nativeFee, native.decimals) * nativePrice;\n }\n } catch {\n valueUsdOut = null;\n }\n }\n const lossPct = valueUsdIn !== null && valueUsdIn > 0 && valueUsdOut !== null ? ((valueUsdIn - valueUsdOut) / valueUsdIn) * 100 : null;\n const impact = q.providerData?.priceImpactBps;\n const priceImpactBps = typeof impact === \"string\" && /^\\d+$/.test(impact) ? Number(impact) : undefined;\n const v: QuoteValue = {provider: q.provider, valueUsdIn, valueUsdOut, lossPct};\n if (priceImpactBps !== undefined) v.priceImpactBps = priceImpactBps;\n return v;\n });\n // The best delivery in the set names itself as the alternative for every quote it beats by more than betterBy %.\n // Priced: by delivered USD (native fees netted). Unpriced: by raw destAmount — same token for every quote, so the ratio is exact.\n const allPriced = out.length > 1 && out.every((v) => v.valueUsdOut !== null);\n if (out.length > 1) {\n const measure = (v: QuoteValue): number => (allPriced ? v.valueUsdOut! : bigintToNumber(BigInt(quotes.find((q) => q.provider === v.provider)!.destAmount)));\n const top = out.reduce((a, b) => (measure(b) > measure(a) ? b : a));\n const topQuote = quotes.find((q) => q.provider === top.provider)!;\n for (const v of out) {\n if (v === top) continue;\n const mine = measure(v);\n const byPct = mine > 0 ? ((measure(top) - mine) / mine) * 100 : Infinity;\n if (byPct > betterBy) v.betterAlternative = {provider: top.provider, valueUsdOut: top.valueUsdOut, destAmount: topQuote.destAmount, byPct};\n }\n }\n return out;\n}\n","/**\n * The optional aggregator: one swap2 protocol that quotes every provider the\n * caller installed and passed in, in parallel, and executes the best route.\n *\n * Every provider package (`@anywalletkit/protocol-swap2-lifi`, `-near-intents`,\n * `-thorchain`, `-omniston`) also works on its own through its single-provider\n * protocol class; this package is only for callers who want an auction across\n * several of them. It has no dependency on any provider: capabilities\n * (supported chains / pairs) come from the providers themselves, or — for a\n * `remoteProvider` stub — from the `supportsChain`/`supportsChainPair` options\n * the caller fills in.\n *\n * ```ts\n * const swap2 = new RouterSwap2Protocol(account, {\n * fromChain: \"eip155:1\",\n * providers: [lifiProvider({...}), nearIntentsProvider({...})],\n * })\n * ```\n */\nimport {\n BaseSwap2Protocol,\n type Swap2Account,\n type Swap2EngineConfig,\n} from \"@anywalletkit/protocol-swap2-core/swap2/base\";\nimport type {CrossChainProvider, Quote, QuoteParams} from \"@anywalletkit/protocol-swap2-core/types\";\nimport type {ActivityItem, ChainTx, DescribeActivityContext, Swap2Options, Swap2Quote} from \"@anywalletkit/core\";\nimport {CrossChainRouter, type RouteSet, type RouterOptions} from \"../router.js\";\n\n/** One route in a picker: the public quote plus its place in the auction. */\nexport interface Swap2Route {\n /** Provider name. */\n provider: string;\n /** The provider's quote. */\n quote: Swap2Quote;\n /** Net USD value when the router prices routes (`valueUsd`), else null. */\n netValueUsd: number | null;\n /** Value against the best route, 0..1. */\n relativeValue: number;\n /** `best` (most value within the tie band) and/or `fastest` (lowest ETA). */\n tags: (\"best\" | \"fastest\")[];\n}\n\n/**\n * Options for {@link RouterSwap2Protocol}: the providers (or a ready router), route preference and\n * the engine options.\n */\nexport interface RouterSwap2Config extends Swap2EngineConfig {\n /** The providers to aggregate over. Only what the caller installs is bundled. */\n providers?: CrossChainProvider[];\n /**\n * Or a ready auction engine (e.g. to share one between protocols or tune its\n * score weights). Exactly one of `providers` / `router` is required.\n */\n router?: CrossChainRouter;\n /** Order inside a price tie for a router built from `providers`, e.g. \"price:0.7,speed:0.2,reliability:0.1\". */\n weights?: string;\n /** Net USD value of a quote for a router built from `providers` — see `usdValue(prices)`. */\n valueUsd?: RouterOptions[\"valueUsd\"];\n /** Fraction of the best value inside which routes tie on price (default 0.002). */\n tieBand?: number;\n /** What `swap2()` / `quoteSwap2()` execute when several routes answer: the best (default) or the fastest. */\n prefer?: \"best\" | \"fastest\";\n}\n\n/**\n * A swap2 protocol that asks every installed provider in parallel, checks each quote the same way,\n * and executes the chosen route. Pass exactly one of `providers` or `router`.\n *\n * ```ts\n * const swap2 = new RouterSwap2Protocol(account, {\n * fromChain: 'eip155:1',\n * providers: [lifiProvider(), nearIntentsProvider(), cctpProvider()],\n * })\n * const quote = await swap2.quoteSwap2({ fromToken: 'USDC', toToken: 'USDC', toChain: 'eip155:8453', fromTokenAmount: 100_000_000n })\n * ```\n */\nexport class RouterSwap2Protocol extends BaseSwap2Protocol {\n private readonly router: CrossChainRouter;\n private readonly account: Swap2Account | undefined;\n private readonly routerConfig: RouterSwap2Config;\n\n constructor(account: Swap2Account | undefined, config: RouterSwap2Config) {\n super(account, config);\n if (!!config.router === !!config.providers) {\n throw new Error(\"swap2: RouterSwap2Protocol needs exactly one of `providers` or `router`\");\n }\n if (config.prefer !== undefined && config.prefer !== \"best\" && config.prefer !== \"fastest\") {\n throw new Error(\"swap2: prefer must be \\\"best\\\" or \\\"fastest\\\"\");\n }\n this.router = config.router ?? new CrossChainRouter(config.providers!, {\n ...(config.weights !== undefined ? {weights: config.weights} : {}),\n ...(config.valueUsd ? {valueUsd: config.valueUsd} : {}),\n ...(config.tieBand !== undefined ? {tieBand: config.tieBand} : {}),\n });\n this.account = account;\n this.routerConfig = config;\n }\n\n protected resolveQuote(params: QuoteParams): Promise<Quote | null> {\n return this.router.getBestQuote(params, this.routerConfig.prefer ? {prefer: this.routerConfig.prefer} : undefined);\n }\n\n /**\n * Every route for a picker, ranked, with the best and the fastest tagged.\n * `onUpdate` gets the ranked list each time another provider answers, so a\n * UI shows the first price as soon as the fastest venue replies. Routes the\n * caller's floor or fee caps refuse are left out. Execute the one the user\n * picks with `using(route.provider).swap2(...)`.\n */\n async quoteSwap2Routes(options: Swap2Options, opts?: {onUpdate?: (routes: Swap2Route[], pending: string[]) => void}): Promise<Swap2Route[]> {\n const snapshot = await this.prepareOptions(this.snapshotOf(options));\n const view = (set: RouteSet): Swap2Route[] =>\n set.quotes.flatMap((q) => {\n const quote = this.routeQuote(q, snapshot);\n return quote ? [{provider: q.provider, quote, netValueUsd: q.netValueUsd, relativeValue: q.relativeValue, tags: [...q.tags]}] : [];\n });\n const set = await this.router.getQuotes(this.toParams(snapshot, true), opts?.onUpdate\n ? {onUpdate: (partial) => opts.onUpdate!(view(partial), partial.pending)}\n : undefined);\n return set ? view(set) : [];\n }\n\n /** This protocol pinned to one provider — the route a user picked from `quoteSwap2Routes`. */\n using(provider: string): RouterSwap2Protocol {\n const {providers: _p, router: _r, ...rest} = this.routerConfig;\n return new RouterSwap2Protocol(this.account, {...rest, router: this.router.only(provider)});\n }\n\n protected override noRouteDetail(): string {\n return this.router.lastRejections.join(\"; \").slice(0, 400);\n }\n\n protected providerFor(name: string): CrossChainProvider | undefined {\n return this.router.getProvider(name);\n }\n\n /** Delegates to every provider the router holds (first match wins); null with no providers. */\n override describeActivity(tx: ChainTx, ctx: DescribeActivityContext): ActivityItem | null {\n return this.router.describeActivity(tx, ctx);\n }\n\n protected chainSupported(caip2: string): boolean {\n return this.router.supportsChain(caip2);\n }\n\n protected override pairSupported(fromChain: string, toChain: string): boolean {\n return this.router.supportsChainPair(fromChain, toChain);\n }\n\n /** Release the providers' resources (timers, sockets). */\n close(): void {\n this.router.close();\n }\n}\n"],"mappings":"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","names":["import_core","set"]}
|
package/dist/index.js
CHANGED
|
@@ -4,10 +4,10 @@ import {
|
|
|
4
4
|
} from "./chunk-Q7MKCWWH.js";
|
|
5
5
|
import {
|
|
6
6
|
RouterSwap2Protocol
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-S5DBSOWP.js";
|
|
8
8
|
import {
|
|
9
9
|
CrossChainRouter
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-R47JJEOO.js";
|
|
11
11
|
|
|
12
12
|
// src/index.ts
|
|
13
13
|
import { remoteProvider } from "@anywalletkit/protocol-swap2-core/remote";
|
package/dist/router.cjs
CHANGED
|
@@ -89,6 +89,7 @@ var CrossChainRouter = class _CrossChainRouter {
|
|
|
89
89
|
// remote provider for a local one and checked its calldata against the backend's own addresses.
|
|
90
90
|
...provider.remote === true ? { remote: true } : {},
|
|
91
91
|
...provider.verifiesBuilds === true ? { verifiesBuilds: true } : {},
|
|
92
|
+
...provider.verifiesQuotes === true ? { verifiesQuotes: true } : {},
|
|
92
93
|
...provider.depositAddressRoutes === true ? { depositAddressRoutes: true } : {},
|
|
93
94
|
...provider.callTargets ? { callTargets: provider.callTargets.bind(provider) } : {},
|
|
94
95
|
...provider.spenders ? { spenders: provider.spenders.bind(provider) } : {},
|
package/dist/router.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/router.ts"],"sourcesContent":["/**\n * The auction engine of the optional aggregator: routes a cross-chain delivery\n * over whichever providers the caller installed and passed in. Protocol\n * modules never need it — each one runs standalone on @anywalletkit/protocol-swap2-core.\n */\nimport type {\n CrossChainProvider,\n IntentRef,\n IntentStatus,\n Quote,\n QuoteParams,\n RoutedQuote,\n ScoreWeights,\n} from \"@anywalletkit/protocol-swap2-core/types\";\nimport {remotePinRefusal, validQuote} from \"@anywalletkit/protocol-swap2-core/validate\";\nimport type {ActivityItem, ChainTx, DescribeActivityContext} from \"@anywalletkit/core\";\nimport {bigintToNumber} from \"@anywalletkit/core\";\n\nconst DEFAULT_WEIGHTS: ScoreWeights = {price: 0.6, speed: 0.3, reliability: 0.1};\n/** Quotes within 0.2% of the best net value count as the same price. */\nconst DEFAULT_TIE_BAND = 0.002;\n\nexport interface RouterOptions {\n /**\n * \"price:0.6,speed:0.3,reliability:0.1\" — how quotes inside the tie band\n * (same price, within `tieBand`) are ordered. Price itself always leads.\n */\n weights?: string;\n /**\n * What a quote is worth to the user in USD: its guaranteed output minus what\n * the route charges on top (a native bridge fee, the source gas). Return null\n * when it cannot be priced — the auction then compares guaranteed outputs.\n * `usdValue(prices)` builds one from a symbol → USD price map.\n */\n valueUsd?: (quote: Quote, params: QuoteParams) => number | null;\n /** Fraction of the best net value inside which quotes tie on price (default 0.002). */\n tieBand?: number;\n}\n\n/** A validated quote with its place in the auction. */\nexport interface RankedQuote extends Quote {\n /** Net USD value (`valueUsd`), or null when the auction compared raw outputs. */\n netValueUsd: number | null;\n /** This quote's value against the best one, 0..1 (1 = the best price). */\n relativeValue: number;\n /** \"best\": the pick (best price; faster/more reliable among equal prices). \"fastest\": the lowest ETA. */\n tags: (\"best\" | \"fastest\")[];\n}\n\n/** Every validated route for one request, ranked by value. */\nexport interface RouteSet {\n /** Every validated route, best first. */\n quotes: RankedQuote[];\n /** Most delivered value (net of fees when priced) within the tie band. */\n best: RankedQuote;\n /** Lowest ETA. */\n fastest: RankedQuote;\n /** Providers still quoting (only non-empty in progressive `onUpdate` snapshots). */\n pending: string[];\n /** Why the venues that sat out did (same as `lastRejections`). */\n rejections: string[];\n}\n// LI.FI's /quote routinely takes ~3.5s (it builds executable calldata) — 4s\n// raced it out of every round. All providers still run in parallel.\nconst QUOTE_TIMEOUT_MS = 8000;\n/** Pinned single-venue (execution) budget — see the comment at the call site. */\nconst SOLO_QUOTE_TIMEOUT_MS = 25_000;\n\nfunction parseWeights(spec?: string): ScoreWeights {\n if (!spec) return DEFAULT_WEIGHTS;\n const w = {...DEFAULT_WEIGHTS};\n for (const part of spec.split(\",\")) {\n const [k, v] = part.split(\":\");\n const n = Number(v);\n if ((k === \"price\" || k === \"speed\" || k === \"reliability\") && Number.isFinite(n)) {\n w[k] = Math.max(0, n);\n }\n }\n return w;\n}\n\nasync function withTimeout<T>(p: Promise<T>, ms: number): Promise<T | null> {\n return new Promise((resolve, reject) => {\n // Timeouts and failures must REJECT: the old `() => resolve(null)` arm\n // swallowed every provider error — including forwarded venue refusals —\n // into a null indistinguishable from \"no route\", which made execution\n // failures undiagnosable from the surface (the '(c2)' hunt of 2026-08-31).\n const timer = setTimeout(() => reject(new Error(`quote timed out after ${ms}ms`)), ms);\n p.then(resolve, reject).finally(() => clearTimeout(timer));\n });\n}\n\n/**\n * Routes a cross-chain delivery over pluggable providers: queries all that\n * support the route in parallel (with a timeout so a slow provider can't block),\n * normalizes their quotes, scores by configurable weights, and returns the best\n * tagged with `routeScore`. A failed/slow provider simply doesn't participate.\n */\nexport class CrossChainRouter {\n private readonly providers: CrossChainProvider[];\n /** Why the venues of the LAST getBestQuote call sat out — for error surfaces. */\n private _lastRejections: string[] = [];\n /** Why providers sat out the last auction, one line each. */\n get lastRejections(): readonly string[] {\n return this._lastRejections;\n }\n private readonly weights: ScoreWeights;\n private readonly valueUsd: RouterOptions[\"valueUsd\"];\n private readonly tieBand: number;\n private readonly options: RouterOptions;\n\n constructor(providers: CrossChainProvider[], options?: string | RouterOptions) {\n const opts: RouterOptions = typeof options === \"string\" ? {weights: options} : {...(options ?? {})};\n if (opts.tieBand !== undefined && !(Number.isFinite(opts.tieBand) && opts.tieBand >= 0 && opts.tieBand < 1)) {\n throw new Error(\"cross-chain router: tieBand must be a fraction in [0, 1)\");\n }\n const names = new Set<string>();\n for (const provider of providers) {\n if (typeof provider.name !== \"string\" || !/^[A-Za-z0-9_-]+$/.test(provider.name) || names.has(provider.name)) {\n throw new Error(`cross-chain router: invalid or duplicate provider name '${String(provider.name)}'`);\n }\n names.add(provider.name);\n }\n // Snapshot the dispatch surface. A caller mutating provider.name or method\n // properties after construction must not redirect quote→build/status.\n this.providers = providers.map((provider) => ({\n name: provider.name,\n enabled: provider.enabled.bind(provider),\n supportsRoute: provider.supportsRoute.bind(provider),\n getQuote: provider.getQuote.bind(provider),\n buildDeposit: provider.buildDeposit.bind(provider),\n trackIntent: provider.trackIntent.bind(provider),\n ...(provider.preflightDeposit ? {preflightDeposit: provider.preflightDeposit.bind(provider)} : {}),\n ...(provider.notifyDeposit ? {notifyDeposit: provider.notifyDeposit.bind(provider)} : {}),\n ...(provider.registerSignedOrder ? {registerSignedOrder: provider.registerSignedOrder.bind(provider)} : {}),\n // Two-phase routes (CCTP): the destination claim. Missing here, the engine\n // and the server both reported \"provider 'cctp' has no claim step\" (2026-10-13).\n ...(provider.buildClaim ? {buildClaim: provider.buildClaim.bind(provider)} : {}),\n ...(provider.claimTargets ? {claimTargets: provider.claimTargets.bind(provider)} : {}),\n // A remote stub's marker and the app's pins (scan 2026-10-27 modules, F8/F9/F16): dropped here, the engine took a\n // remote provider for a local one and checked its calldata against the backend's own addresses.\n ...(provider.remote === true ? {remote: true} : {}),\n ...(provider.verifiesBuilds === true ? {verifiesBuilds: true} : {}),\n ...(provider.depositAddressRoutes === true ? {depositAddressRoutes: true} : {}),\n ...(provider.callTargets ? {callTargets: provider.callTargets.bind(provider)} : {}),\n ...(provider.spenders ? {spenders: provider.spenders.bind(provider)} : {}),\n ...(provider.close ? {close: provider.close.bind(provider)} : {}),\n ...(provider.supportsChain ? {supportsChain: provider.supportsChain.bind(provider)} : {}),\n ...(provider.supportsChainPair ? {supportsChainPair: provider.supportsChainPair.bind(provider)} : {}),\n ...(provider.describeActivity ? {describeActivity: provider.describeActivity.bind(provider)} : {}),\n ...(provider.supportsSameChain !== undefined ? {supportsSameChain: provider.supportsSameChain} : {}),\n }));\n this.weights = parseWeights(opts.weights);\n this.valueUsd = opts.valueUsd;\n this.tieBand = opts.tieBand ?? DEFAULT_TIE_BAND;\n this.options = opts;\n }\n\n /** The same auction restricted to one provider — to execute the route a user picked. */\n only(name: string): CrossChainRouter {\n const provider = this.getProvider(name);\n if (!provider) throw new Error(`cross-chain router: provider '${name}' is not registered`);\n return new CrossChainRouter([provider], this.options);\n }\n\n /**\n * Activity recognition across the installed providers: the first one that\n * claims the transaction describes it. Null when none does (or none is held).\n */\n describeActivity(tx: ChainTx, ctx: DescribeActivityContext): ActivityItem | null {\n for (const provider of this.providers) {\n const item = provider.describeActivity?.(tx, ctx);\n if (item) return item;\n }\n return null;\n }\n\n /** A provider by name. */\n getProvider(name: string): CrossChainProvider | undefined {\n return this.providers.find((p) => p.name === name);\n }\n\n /** True when a provider of that name is installed. */\n hasProvider(name: string): boolean {\n return this.providers.some((p) => p.name === name);\n }\n\n /** True when that provider is installed and enabled. */\n hasEnabledProvider(name: string): boolean {\n return this.providers.some((p) => {\n try { return p.name === name && p.enabled(); } catch { return false; }\n });\n }\n\n /** True when any enabled provider declares the chain. */\n supportsChain(caip2: string): boolean {\n return this.providers.some((p) => {\n try { return p.enabled() && !!p.supportsChain?.(caip2); } catch { return false; }\n });\n }\n\n /** True when any enabled provider declares the chain pair. */\n supportsChainPair(fromChain: string, toChain: string): boolean {\n return this.providers.some((p) => {\n try {\n return p.enabled() && (p.supportsChainPair?.(fromChain, toChain) ?? false);\n } catch { return false; }\n });\n }\n\n /**\n * The auction's pick: the best price (net of native fees and gas when\n * `valueUsd` is set; faster, then more reliable, among equal prices), or\n * the fastest route with `prefer: \"fastest\"`.\n */\n async getBestQuote(\n params: QuoteParams,\n options?: {requireImmediateExecution?: boolean; prefer?: \"best\" | \"fastest\"},\n ): Promise<RoutedQuote | null> {\n const set = await this.getQuotes(params, options);\n if (!set) return null;\n const pick = options?.prefer === \"fastest\" ? set.fastest : set.best;\n const {netValueUsd: _n, relativeValue: _r, tags: _t, ...quote} = pick;\n return {\n ...quote,\n routeScore: {\n score: pick.relativeValue,\n weights: this.weights,\n candidates: set.quotes.map((q) => ({\n provider: q.provider,\n sourceAmount: q.sourceAmount,\n etaSeconds: q.etaSeconds,\n score: q.relativeValue,\n minDestAmount: q.minDestAmount,\n netValueUsd: q.netValueUsd,\n })),\n },\n };\n }\n\n /**\n * Every validated route, ranked — for a route picker that shows the best and\n * the fastest and lets the user choose. Providers run in parallel; with\n * `onUpdate` each one that answers re-publishes the ranked set at once (the\n * first price shows in the time of the fastest venue, not the slowest).\n */\n async getQuotes(\n params: QuoteParams,\n options?: {requireImmediateExecution?: boolean; onUpdate?: (set: RouteSet) => void},\n ): Promise<RouteSet | null> {\n // A public engine caller — or one provider running in the same auction —\n // must not be able to rewrite another provider's request while async quote\n // work is in flight. QuoteParams is intentionally flat, so a frozen copy is\n // a complete execution snapshot.\n const rejections: string[] = [];\n this._lastRejections = rejections;\n const snapshot = Object.freeze({...params});\n const from = Object.freeze({chain: snapshot.sourceChain, token: snapshot.sourceToken});\n const to = Object.freeze({chain: snapshot.destChain, token: snapshot.destToken});\n // Only enabled (validated) providers that can serve the route participate.\n let eligible = this.providers.filter((p) => {\n try { return p.enabled() && p.supportsRoute(from, to); } catch { return false; }\n });\n if (snapshot.sourceChain === snapshot.destChain) {\n eligible = eligible.filter((p) => p.supportsSameChain === true);\n }\n if (eligible.length === 0) return null;\n\n // The short timeout protects the AUCTION — one slow venue must not hold\n // the others hostage. With a single eligible provider (a pinned execution\n // re-quote) there is nobody to protect, and a live deposit-creating quote\n // legitimately takes longer than a dry one (serverless hop + upstream\n // retries) — starving it surfaced as a terminal \"no route\" on execution.\n const timeoutMs = eligible.length === 1 ? SOLO_QUOTE_TIMEOUT_MS : QUOTE_TIMEOUT_MS;\n // Each venue names its own refusal (per call, so concurrent quotes cannot race).\n const refusals: (string | undefined)[] = [];\n const accepted: Quote[] = [];\n const pending = new Set(eligible.map((p) => p.name));\n const publish = () => {\n if (!options?.onUpdate || accepted.length === 0) return;\n const set = this.rank(accepted, snapshot, [...pending], rejections);\n try { options.onUpdate(set); } catch { /* an observer must not break the auction */ }\n };\n await Promise.all(eligible.map(async (p, i) => {\n const controller = new AbortController();\n const own = Object.freeze({...snapshot, onRefusal: (reason: string) => {\n refusals[i] ??= reason.startsWith(`${p.name}:`) ? reason : `${p.name}: ${reason}`;\n try { snapshot.onRefusal?.(reason); } catch { /* diagnostics only */ }\n }});\n let q: Quote | null = null;\n try {\n q = await withTimeout(p.getQuote(own, controller.signal), timeoutMs);\n if (!q) {\n // A provider RETURNING null (vs throwing) was the one silent path\n // left — record it so the surfaced no-route error names the venue.\n rejections.push(refusals[i] ?? `${p.name}: returned no quote`);\n } else if (!validQuote(q, snapshot, p.name)) {\n const reason = `${p.name}: rejected by validation (minDest=${q.minDestAmount} vs floor=${snapshot.minAmountOut ?? \"-\"}, validUntil=${q.validUntilMs}, now=${Date.now()})`;\n rejections.push(reason);\n console.warn(`swap2-router: ${reason}`);\n q = null;\n } else {\n // A remote stub's route that calls or approves an address the app did not pin: execution would refuse it.\n const unpinned = remotePinRefusal(p, q, snapshot.sourceChain);\n if (unpinned) {\n rejections.push(unpinned);\n console.warn(`swap2-router: ${unpinned}`);\n q = null;\n } else if (options?.requireImmediateExecution && !(q.depositAddress.length > 0 || q.txRequest !== undefined)) {\n // Legacy deposit-address screens cannot execute order-based quotes that\n // require a separate build/sign/register lifecycle.\n q = null;\n }\n }\n } catch (err) {\n // A failed venue sitting out silently is indistinguishable from \"no\n // route\" — record why (surfaced through lastRejections) and say it in\n // the console (same posture as onModuleSkipped).\n const reason = `${p.name}: ${err instanceof Error ? err.message.slice(0, 160) : String(err).slice(0, 160)}`;\n rejections.push(reason);\n console.warn(`swap2-router: quote failed — ${reason}`);\n q = null;\n } finally {\n controller.abort();\n }\n pending.delete(p.name);\n // Provider identity is an execution security boundary. Never trust the\n // provider field returned by an untrusted adapter; bind it to its slot.\n if (q) accepted.push({...q, provider: p.name});\n publish();\n }));\n if (accepted.length === 0) return null;\n return this.rank(accepted, snapshot, [], rejections);\n }\n\n /** Status from the named provider; `failed` when it is not installed. */\n async trackIntent(providerName: string, ref: IntentRef): Promise<IntentStatus> {\n const provider = this.getProvider(providerName);\n if (!provider) return {state: \"failed\"};\n return provider.trackIntent(ref);\n }\n\n /** Forward a source-broadcast notification to the intent's provider. */\n async notifyDeposit(providerName: string, intentId: string, txHash: string): Promise<void> {\n await this.getProvider(providerName)?.notifyDeposit?.(intentId, txHash);\n }\n\n /** Release every provider's resources. */\n close(): void {\n for (const provider of this.providers) provider.close?.();\n }\n\n /**\n * Price first: each quote's value is its net USD (`valueUsd`) — or, when any\n * quote cannot be priced, its guaranteed output — against the best one.\n * Quotes within `tieBand` of the best are the same price; among those the\n * weights order speed and reliability. A $0.01 edge no longer beats a route\n * that lands in seconds instead of twenty minutes, and a route that charges\n * a native bridge fee on top no longer wins on its gross output.\n */\n private rank(quotes: Quote[], params: QuoteParams, pending: string[], rejections: string[]): RouteSet {\n const usd = this.valueUsd ? quotes.map((q) => {\n try {\n const v = this.valueUsd!(q, params);\n return typeof v === \"number\" && Number.isFinite(v) ? v : null;\n } catch { return null; }\n }) : quotes.map(() => null);\n const priced = usd.every((v) => v !== null);\n let relative: number[];\n if (priced) {\n const values = usd as number[];\n const max = Math.max(...values);\n relative = values.map((v) => (max > 0 ? Math.max(0, v) / max : v >= max ? 1 : 0));\n } else {\n const outs = quotes.map((q) => BigInt(q.minDestAmount));\n const max = outs.reduce((a, b) => (b > a ? b : a));\n relative = outs.map((o) => fraction(o, max));\n }\n const ranked: RankedQuote[] = quotes.map((q, i) => ({\n ...q,\n netValueUsd: priced ? usd[i]! : null,\n relativeValue: relative[i]!,\n tags: [],\n }));\n\n const tier = ranked.filter((q) => q.relativeValue >= 1 - this.tieBand - 1e-12);\n const etas = tier.map((q) => q.etaSeconds);\n const minEta = Math.min(...etas);\n const maxEta = Math.max(...etas);\n const w = this.weights;\n const tieScore = (q: RankedQuote) =>\n w.price * q.relativeValue +\n w.speed * (maxEta === minEta ? 1 : (maxEta - q.etaSeconds) / (maxEta - minEta)) +\n w.reliability * q.reliability;\n const best = tier.reduce((a, b) => (tieScore(b) > tieScore(a) ? b : a));\n const fastest = ranked.reduce((a, b) =>\n b.etaSeconds < a.etaSeconds || (b.etaSeconds === a.etaSeconds && b.relativeValue > a.relativeValue) ? b : a);\n best.tags.push(\"best\");\n fastest.tags.push(\"fastest\");\n\n // The list reads top-down by value; the pick leads its price tier.\n ranked.sort((a, b) => (a === best ? -1 : b === best ? 1 : b.relativeValue - a.relativeValue || a.etaSeconds - b.etaSeconds));\n return {quotes: ranked, best, fastest, pending, rejections: [...rejections]};\n }\n}\n\n/** Ratio of two non-negative bigints as a 0..1 number. */\nfunction fraction(num: bigint, den: bigint): number {\n if (den === 0n) return 1;\n // scale to keep precision, then to float\n return bigintToNumber((num * 10_000n) / den) / 10_000;\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/router.ts"],"sourcesContent":["/**\n * The auction engine of the optional aggregator: routes a cross-chain delivery\n * over whichever providers the caller installed and passed in. Protocol\n * modules never need it — each one runs standalone on @anywalletkit/protocol-swap2-core.\n */\nimport type {\n CrossChainProvider,\n IntentRef,\n IntentStatus,\n Quote,\n QuoteParams,\n RoutedQuote,\n ScoreWeights,\n} from \"@anywalletkit/protocol-swap2-core/types\";\nimport {remotePinRefusal, validQuote} from \"@anywalletkit/protocol-swap2-core/validate\";\nimport type {ActivityItem, ChainTx, DescribeActivityContext} from \"@anywalletkit/core\";\nimport {bigintToNumber} from \"@anywalletkit/core\";\n\nconst DEFAULT_WEIGHTS: ScoreWeights = {price: 0.6, speed: 0.3, reliability: 0.1};\n/** Quotes within 0.2% of the best net value count as the same price. */\nconst DEFAULT_TIE_BAND = 0.002;\n\nexport interface RouterOptions {\n /**\n * \"price:0.6,speed:0.3,reliability:0.1\" — how quotes inside the tie band\n * (same price, within `tieBand`) are ordered. Price itself always leads.\n */\n weights?: string;\n /**\n * What a quote is worth to the user in USD: its guaranteed output minus what\n * the route charges on top (a native bridge fee, the source gas). Return null\n * when it cannot be priced — the auction then compares guaranteed outputs.\n * `usdValue(prices)` builds one from a symbol → USD price map.\n */\n valueUsd?: (quote: Quote, params: QuoteParams) => number | null;\n /** Fraction of the best net value inside which quotes tie on price (default 0.002). */\n tieBand?: number;\n}\n\n/** A validated quote with its place in the auction. */\nexport interface RankedQuote extends Quote {\n /** Net USD value (`valueUsd`), or null when the auction compared raw outputs. */\n netValueUsd: number | null;\n /** This quote's value against the best one, 0..1 (1 = the best price). */\n relativeValue: number;\n /** \"best\": the pick (best price; faster/more reliable among equal prices). \"fastest\": the lowest ETA. */\n tags: (\"best\" | \"fastest\")[];\n}\n\n/** Every validated route for one request, ranked by value. */\nexport interface RouteSet {\n /** Every validated route, best first. */\n quotes: RankedQuote[];\n /** Most delivered value (net of fees when priced) within the tie band. */\n best: RankedQuote;\n /** Lowest ETA. */\n fastest: RankedQuote;\n /** Providers still quoting (only non-empty in progressive `onUpdate` snapshots). */\n pending: string[];\n /** Why the venues that sat out did (same as `lastRejections`). */\n rejections: string[];\n}\n// LI.FI's /quote routinely takes ~3.5s (it builds executable calldata) — 4s\n// raced it out of every round. All providers still run in parallel.\nconst QUOTE_TIMEOUT_MS = 8000;\n/** Pinned single-venue (execution) budget — see the comment at the call site. */\nconst SOLO_QUOTE_TIMEOUT_MS = 25_000;\n\nfunction parseWeights(spec?: string): ScoreWeights {\n if (!spec) return DEFAULT_WEIGHTS;\n const w = {...DEFAULT_WEIGHTS};\n for (const part of spec.split(\",\")) {\n const [k, v] = part.split(\":\");\n const n = Number(v);\n if ((k === \"price\" || k === \"speed\" || k === \"reliability\") && Number.isFinite(n)) {\n w[k] = Math.max(0, n);\n }\n }\n return w;\n}\n\nasync function withTimeout<T>(p: Promise<T>, ms: number): Promise<T | null> {\n return new Promise((resolve, reject) => {\n // Timeouts and failures must REJECT: the old `() => resolve(null)` arm\n // swallowed every provider error — including forwarded venue refusals —\n // into a null indistinguishable from \"no route\", which made execution\n // failures undiagnosable from the surface (the '(c2)' hunt of 2026-08-31).\n const timer = setTimeout(() => reject(new Error(`quote timed out after ${ms}ms`)), ms);\n p.then(resolve, reject).finally(() => clearTimeout(timer));\n });\n}\n\n/**\n * Routes a cross-chain delivery over pluggable providers: queries all that\n * support the route in parallel (with a timeout so a slow provider can't block),\n * normalizes their quotes, scores by configurable weights, and returns the best\n * tagged with `routeScore`. A failed/slow provider simply doesn't participate.\n */\nexport class CrossChainRouter {\n private readonly providers: CrossChainProvider[];\n /** Why the venues of the LAST getBestQuote call sat out — for error surfaces. */\n private _lastRejections: string[] = [];\n /** Why providers sat out the last auction, one line each. */\n get lastRejections(): readonly string[] {\n return this._lastRejections;\n }\n private readonly weights: ScoreWeights;\n private readonly valueUsd: RouterOptions[\"valueUsd\"];\n private readonly tieBand: number;\n private readonly options: RouterOptions;\n\n constructor(providers: CrossChainProvider[], options?: string | RouterOptions) {\n const opts: RouterOptions = typeof options === \"string\" ? {weights: options} : {...(options ?? {})};\n if (opts.tieBand !== undefined && !(Number.isFinite(opts.tieBand) && opts.tieBand >= 0 && opts.tieBand < 1)) {\n throw new Error(\"cross-chain router: tieBand must be a fraction in [0, 1)\");\n }\n const names = new Set<string>();\n for (const provider of providers) {\n if (typeof provider.name !== \"string\" || !/^[A-Za-z0-9_-]+$/.test(provider.name) || names.has(provider.name)) {\n throw new Error(`cross-chain router: invalid or duplicate provider name '${String(provider.name)}'`);\n }\n names.add(provider.name);\n }\n // Snapshot the dispatch surface. A caller mutating provider.name or method\n // properties after construction must not redirect quote→build/status.\n this.providers = providers.map((provider) => ({\n name: provider.name,\n enabled: provider.enabled.bind(provider),\n supportsRoute: provider.supportsRoute.bind(provider),\n getQuote: provider.getQuote.bind(provider),\n buildDeposit: provider.buildDeposit.bind(provider),\n trackIntent: provider.trackIntent.bind(provider),\n ...(provider.preflightDeposit ? {preflightDeposit: provider.preflightDeposit.bind(provider)} : {}),\n ...(provider.notifyDeposit ? {notifyDeposit: provider.notifyDeposit.bind(provider)} : {}),\n ...(provider.registerSignedOrder ? {registerSignedOrder: provider.registerSignedOrder.bind(provider)} : {}),\n // Two-phase routes (CCTP): the destination claim. Missing here, the engine\n // and the server both reported \"provider 'cctp' has no claim step\" (2026-10-13).\n ...(provider.buildClaim ? {buildClaim: provider.buildClaim.bind(provider)} : {}),\n ...(provider.claimTargets ? {claimTargets: provider.claimTargets.bind(provider)} : {}),\n // A remote stub's marker and the app's pins (scan 2026-10-27 modules, F8/F9/F16): dropped here, the engine took a\n // remote provider for a local one and checked its calldata against the backend's own addresses.\n ...(provider.remote === true ? {remote: true} : {}),\n ...(provider.verifiesBuilds === true ? {verifiesBuilds: true} : {}),\n ...(provider.verifiesQuotes === true ? {verifiesQuotes: true} : {}),\n ...(provider.depositAddressRoutes === true ? {depositAddressRoutes: true} : {}),\n ...(provider.callTargets ? {callTargets: provider.callTargets.bind(provider)} : {}),\n ...(provider.spenders ? {spenders: provider.spenders.bind(provider)} : {}),\n ...(provider.close ? {close: provider.close.bind(provider)} : {}),\n ...(provider.supportsChain ? {supportsChain: provider.supportsChain.bind(provider)} : {}),\n ...(provider.supportsChainPair ? {supportsChainPair: provider.supportsChainPair.bind(provider)} : {}),\n ...(provider.describeActivity ? {describeActivity: provider.describeActivity.bind(provider)} : {}),\n ...(provider.supportsSameChain !== undefined ? {supportsSameChain: provider.supportsSameChain} : {}),\n }));\n this.weights = parseWeights(opts.weights);\n this.valueUsd = opts.valueUsd;\n this.tieBand = opts.tieBand ?? DEFAULT_TIE_BAND;\n this.options = opts;\n }\n\n /** The same auction restricted to one provider — to execute the route a user picked. */\n only(name: string): CrossChainRouter {\n const provider = this.getProvider(name);\n if (!provider) throw new Error(`cross-chain router: provider '${name}' is not registered`);\n return new CrossChainRouter([provider], this.options);\n }\n\n /**\n * Activity recognition across the installed providers: the first one that\n * claims the transaction describes it. Null when none does (or none is held).\n */\n describeActivity(tx: ChainTx, ctx: DescribeActivityContext): ActivityItem | null {\n for (const provider of this.providers) {\n const item = provider.describeActivity?.(tx, ctx);\n if (item) return item;\n }\n return null;\n }\n\n /** A provider by name. */\n getProvider(name: string): CrossChainProvider | undefined {\n return this.providers.find((p) => p.name === name);\n }\n\n /** True when a provider of that name is installed. */\n hasProvider(name: string): boolean {\n return this.providers.some((p) => p.name === name);\n }\n\n /** True when that provider is installed and enabled. */\n hasEnabledProvider(name: string): boolean {\n return this.providers.some((p) => {\n try { return p.name === name && p.enabled(); } catch { return false; }\n });\n }\n\n /** True when any enabled provider declares the chain. */\n supportsChain(caip2: string): boolean {\n return this.providers.some((p) => {\n try { return p.enabled() && !!p.supportsChain?.(caip2); } catch { return false; }\n });\n }\n\n /** True when any enabled provider declares the chain pair. */\n supportsChainPair(fromChain: string, toChain: string): boolean {\n return this.providers.some((p) => {\n try {\n return p.enabled() && (p.supportsChainPair?.(fromChain, toChain) ?? false);\n } catch { return false; }\n });\n }\n\n /**\n * The auction's pick: the best price (net of native fees and gas when\n * `valueUsd` is set; faster, then more reliable, among equal prices), or\n * the fastest route with `prefer: \"fastest\"`.\n */\n async getBestQuote(\n params: QuoteParams,\n options?: {requireImmediateExecution?: boolean; prefer?: \"best\" | \"fastest\"},\n ): Promise<RoutedQuote | null> {\n const set = await this.getQuotes(params, options);\n if (!set) return null;\n const pick = options?.prefer === \"fastest\" ? set.fastest : set.best;\n const {netValueUsd: _n, relativeValue: _r, tags: _t, ...quote} = pick;\n return {\n ...quote,\n routeScore: {\n score: pick.relativeValue,\n weights: this.weights,\n candidates: set.quotes.map((q) => ({\n provider: q.provider,\n sourceAmount: q.sourceAmount,\n etaSeconds: q.etaSeconds,\n score: q.relativeValue,\n minDestAmount: q.minDestAmount,\n netValueUsd: q.netValueUsd,\n })),\n },\n };\n }\n\n /**\n * Every validated route, ranked — for a route picker that shows the best and\n * the fastest and lets the user choose. Providers run in parallel; with\n * `onUpdate` each one that answers re-publishes the ranked set at once (the\n * first price shows in the time of the fastest venue, not the slowest).\n */\n async getQuotes(\n params: QuoteParams,\n options?: {requireImmediateExecution?: boolean; onUpdate?: (set: RouteSet) => void},\n ): Promise<RouteSet | null> {\n // A public engine caller — or one provider running in the same auction —\n // must not be able to rewrite another provider's request while async quote\n // work is in flight. QuoteParams is intentionally flat, so a frozen copy is\n // a complete execution snapshot.\n const rejections: string[] = [];\n this._lastRejections = rejections;\n const snapshot = Object.freeze({...params});\n const from = Object.freeze({chain: snapshot.sourceChain, token: snapshot.sourceToken});\n const to = Object.freeze({chain: snapshot.destChain, token: snapshot.destToken});\n // Only enabled (validated) providers that can serve the route participate.\n let eligible = this.providers.filter((p) => {\n try { return p.enabled() && p.supportsRoute(from, to); } catch { return false; }\n });\n if (snapshot.sourceChain === snapshot.destChain) {\n eligible = eligible.filter((p) => p.supportsSameChain === true);\n }\n if (eligible.length === 0) return null;\n\n // The short timeout protects the AUCTION — one slow venue must not hold\n // the others hostage. With a single eligible provider (a pinned execution\n // re-quote) there is nobody to protect, and a live deposit-creating quote\n // legitimately takes longer than a dry one (serverless hop + upstream\n // retries) — starving it surfaced as a terminal \"no route\" on execution.\n const timeoutMs = eligible.length === 1 ? SOLO_QUOTE_TIMEOUT_MS : QUOTE_TIMEOUT_MS;\n // Each venue names its own refusal (per call, so concurrent quotes cannot race).\n const refusals: (string | undefined)[] = [];\n const accepted: Quote[] = [];\n const pending = new Set(eligible.map((p) => p.name));\n const publish = () => {\n if (!options?.onUpdate || accepted.length === 0) return;\n const set = this.rank(accepted, snapshot, [...pending], rejections);\n try { options.onUpdate(set); } catch { /* an observer must not break the auction */ }\n };\n await Promise.all(eligible.map(async (p, i) => {\n const controller = new AbortController();\n const own = Object.freeze({...snapshot, onRefusal: (reason: string) => {\n refusals[i] ??= reason.startsWith(`${p.name}:`) ? reason : `${p.name}: ${reason}`;\n try { snapshot.onRefusal?.(reason); } catch { /* diagnostics only */ }\n }});\n let q: Quote | null = null;\n try {\n q = await withTimeout(p.getQuote(own, controller.signal), timeoutMs);\n if (!q) {\n // A provider RETURNING null (vs throwing) was the one silent path\n // left — record it so the surfaced no-route error names the venue.\n rejections.push(refusals[i] ?? `${p.name}: returned no quote`);\n } else if (!validQuote(q, snapshot, p.name)) {\n const reason = `${p.name}: rejected by validation (minDest=${q.minDestAmount} vs floor=${snapshot.minAmountOut ?? \"-\"}, validUntil=${q.validUntilMs}, now=${Date.now()})`;\n rejections.push(reason);\n console.warn(`swap2-router: ${reason}`);\n q = null;\n } else {\n // A remote stub's route that calls or approves an address the app did not pin: execution would refuse it.\n const unpinned = remotePinRefusal(p, q, snapshot.sourceChain);\n if (unpinned) {\n rejections.push(unpinned);\n console.warn(`swap2-router: ${unpinned}`);\n q = null;\n } else if (options?.requireImmediateExecution && !(q.depositAddress.length > 0 || q.txRequest !== undefined)) {\n // Legacy deposit-address screens cannot execute order-based quotes that\n // require a separate build/sign/register lifecycle.\n q = null;\n }\n }\n } catch (err) {\n // A failed venue sitting out silently is indistinguishable from \"no\n // route\" — record why (surfaced through lastRejections) and say it in\n // the console (same posture as onModuleSkipped).\n const reason = `${p.name}: ${err instanceof Error ? err.message.slice(0, 160) : String(err).slice(0, 160)}`;\n rejections.push(reason);\n console.warn(`swap2-router: quote failed — ${reason}`);\n q = null;\n } finally {\n controller.abort();\n }\n pending.delete(p.name);\n // Provider identity is an execution security boundary. Never trust the\n // provider field returned by an untrusted adapter; bind it to its slot.\n if (q) accepted.push({...q, provider: p.name});\n publish();\n }));\n if (accepted.length === 0) return null;\n return this.rank(accepted, snapshot, [], rejections);\n }\n\n /** Status from the named provider; `failed` when it is not installed. */\n async trackIntent(providerName: string, ref: IntentRef): Promise<IntentStatus> {\n const provider = this.getProvider(providerName);\n if (!provider) return {state: \"failed\"};\n return provider.trackIntent(ref);\n }\n\n /** Forward a source-broadcast notification to the intent's provider. */\n async notifyDeposit(providerName: string, intentId: string, txHash: string): Promise<void> {\n await this.getProvider(providerName)?.notifyDeposit?.(intentId, txHash);\n }\n\n /** Release every provider's resources. */\n close(): void {\n for (const provider of this.providers) provider.close?.();\n }\n\n /**\n * Price first: each quote's value is its net USD (`valueUsd`) — or, when any\n * quote cannot be priced, its guaranteed output — against the best one.\n * Quotes within `tieBand` of the best are the same price; among those the\n * weights order speed and reliability. A $0.01 edge no longer beats a route\n * that lands in seconds instead of twenty minutes, and a route that charges\n * a native bridge fee on top no longer wins on its gross output.\n */\n private rank(quotes: Quote[], params: QuoteParams, pending: string[], rejections: string[]): RouteSet {\n const usd = this.valueUsd ? quotes.map((q) => {\n try {\n const v = this.valueUsd!(q, params);\n return typeof v === \"number\" && Number.isFinite(v) ? v : null;\n } catch { return null; }\n }) : quotes.map(() => null);\n const priced = usd.every((v) => v !== null);\n let relative: number[];\n if (priced) {\n const values = usd as number[];\n const max = Math.max(...values);\n relative = values.map((v) => (max > 0 ? Math.max(0, v) / max : v >= max ? 1 : 0));\n } else {\n const outs = quotes.map((q) => BigInt(q.minDestAmount));\n const max = outs.reduce((a, b) => (b > a ? b : a));\n relative = outs.map((o) => fraction(o, max));\n }\n const ranked: RankedQuote[] = quotes.map((q, i) => ({\n ...q,\n netValueUsd: priced ? usd[i]! : null,\n relativeValue: relative[i]!,\n tags: [],\n }));\n\n const tier = ranked.filter((q) => q.relativeValue >= 1 - this.tieBand - 1e-12);\n const etas = tier.map((q) => q.etaSeconds);\n const minEta = Math.min(...etas);\n const maxEta = Math.max(...etas);\n const w = this.weights;\n const tieScore = (q: RankedQuote) =>\n w.price * q.relativeValue +\n w.speed * (maxEta === minEta ? 1 : (maxEta - q.etaSeconds) / (maxEta - minEta)) +\n w.reliability * q.reliability;\n const best = tier.reduce((a, b) => (tieScore(b) > tieScore(a) ? b : a));\n const fastest = ranked.reduce((a, b) =>\n b.etaSeconds < a.etaSeconds || (b.etaSeconds === a.etaSeconds && b.relativeValue > a.relativeValue) ? b : a);\n best.tags.push(\"best\");\n fastest.tags.push(\"fastest\");\n\n // The list reads top-down by value; the pick leads its price tier.\n ranked.sort((a, b) => (a === best ? -1 : b === best ? 1 : b.relativeValue - a.relativeValue || a.etaSeconds - b.etaSeconds));\n return {quotes: ranked, best, fastest, pending, rejections: [...rejections]};\n }\n}\n\n/** Ratio of two non-negative bigints as a 0..1 number. */\nfunction fraction(num: bigint, den: bigint): number {\n if (den === 0n) return 1;\n // scale to keep precision, then to float\n return bigintToNumber((num * 10_000n) / den) / 10_000;\n}\n"],"mappings":"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","names":[]}
|
package/dist/router.js
CHANGED
package/dist/swap2/router.cjs
CHANGED
|
@@ -92,6 +92,7 @@ var CrossChainRouter = class _CrossChainRouter {
|
|
|
92
92
|
// remote provider for a local one and checked its calldata against the backend's own addresses.
|
|
93
93
|
...provider.remote === true ? { remote: true } : {},
|
|
94
94
|
...provider.verifiesBuilds === true ? { verifiesBuilds: true } : {},
|
|
95
|
+
...provider.verifiesQuotes === true ? { verifiesQuotes: true } : {},
|
|
95
96
|
...provider.depositAddressRoutes === true ? { depositAddressRoutes: true } : {},
|
|
96
97
|
...provider.callTargets ? { callTargets: provider.callTargets.bind(provider) } : {},
|
|
97
98
|
...provider.spenders ? { spenders: provider.spenders.bind(provider) } : {},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/swap2/router.ts","../../src/router.ts"],"sourcesContent":["/**\n * The optional aggregator: one swap2 protocol that quotes every provider the\n * caller installed and passed in, in parallel, and executes the best route.\n *\n * Every provider package (`@anywalletkit/protocol-swap2-lifi`, `-near-intents`,\n * `-thorchain`, `-omniston`) also works on its own through its single-provider\n * protocol class; this package is only for callers who want an auction across\n * several of them. It has no dependency on any provider: capabilities\n * (supported chains / pairs) come from the providers themselves, or — for a\n * `remoteProvider` stub — from the `supportsChain`/`supportsChainPair` options\n * the caller fills in.\n *\n * ```ts\n * const swap2 = new RouterSwap2Protocol(account, {\n * fromChain: \"eip155:1\",\n * providers: [lifiProvider({...}), nearIntentsProvider({...})],\n * })\n * ```\n */\nimport {\n BaseSwap2Protocol,\n type Swap2Account,\n type Swap2EngineConfig,\n} from \"@anywalletkit/protocol-swap2-core/swap2/base\";\nimport type {CrossChainProvider, Quote, QuoteParams} from \"@anywalletkit/protocol-swap2-core/types\";\nimport type {ActivityItem, ChainTx, DescribeActivityContext, Swap2Options, Swap2Quote} from \"@anywalletkit/core\";\nimport {CrossChainRouter, type RouteSet, type RouterOptions} from \"../router.js\";\n\n/** One route in a picker: the public quote plus its place in the auction. */\nexport interface Swap2Route {\n /** Provider name. */\n provider: string;\n /** The provider's quote. */\n quote: Swap2Quote;\n /** Net USD value when the router prices routes (`valueUsd`), else null. */\n netValueUsd: number | null;\n /** Value against the best route, 0..1. */\n relativeValue: number;\n /** `best` (most value within the tie band) and/or `fastest` (lowest ETA). */\n tags: (\"best\" | \"fastest\")[];\n}\n\n/**\n * Options for {@link RouterSwap2Protocol}: the providers (or a ready router), route preference and\n * the engine options.\n */\nexport interface RouterSwap2Config extends Swap2EngineConfig {\n /** The providers to aggregate over. Only what the caller installs is bundled. */\n providers?: CrossChainProvider[];\n /**\n * Or a ready auction engine (e.g. to share one between protocols or tune its\n * score weights). Exactly one of `providers` / `router` is required.\n */\n router?: CrossChainRouter;\n /** Order inside a price tie for a router built from `providers`, e.g. \"price:0.7,speed:0.2,reliability:0.1\". */\n weights?: string;\n /** Net USD value of a quote for a router built from `providers` — see `usdValue(prices)`. */\n valueUsd?: RouterOptions[\"valueUsd\"];\n /** Fraction of the best value inside which routes tie on price (default 0.002). */\n tieBand?: number;\n /** What `swap2()` / `quoteSwap2()` execute when several routes answer: the best (default) or the fastest. */\n prefer?: \"best\" | \"fastest\";\n}\n\n/**\n * A swap2 protocol that asks every installed provider in parallel, checks each quote the same way,\n * and executes the chosen route. Pass exactly one of `providers` or `router`.\n *\n * ```ts\n * const swap2 = new RouterSwap2Protocol(account, {\n * fromChain: 'eip155:1',\n * providers: [lifiProvider(), nearIntentsProvider(), cctpProvider()],\n * })\n * const quote = await swap2.quoteSwap2({ fromToken: 'USDC', toToken: 'USDC', toChain: 'eip155:8453', fromTokenAmount: 100_000_000n })\n * ```\n */\nexport class RouterSwap2Protocol extends BaseSwap2Protocol {\n private readonly router: CrossChainRouter;\n private readonly account: Swap2Account | undefined;\n private readonly routerConfig: RouterSwap2Config;\n\n constructor(account: Swap2Account | undefined, config: RouterSwap2Config) {\n super(account, config);\n if (!!config.router === !!config.providers) {\n throw new Error(\"swap2: RouterSwap2Protocol needs exactly one of `providers` or `router`\");\n }\n if (config.prefer !== undefined && config.prefer !== \"best\" && config.prefer !== \"fastest\") {\n throw new Error(\"swap2: prefer must be \\\"best\\\" or \\\"fastest\\\"\");\n }\n this.router = config.router ?? new CrossChainRouter(config.providers!, {\n ...(config.weights !== undefined ? {weights: config.weights} : {}),\n ...(config.valueUsd ? {valueUsd: config.valueUsd} : {}),\n ...(config.tieBand !== undefined ? {tieBand: config.tieBand} : {}),\n });\n this.account = account;\n this.routerConfig = config;\n }\n\n protected resolveQuote(params: QuoteParams): Promise<Quote | null> {\n return this.router.getBestQuote(params, this.routerConfig.prefer ? {prefer: this.routerConfig.prefer} : undefined);\n }\n\n /**\n * Every route for a picker, ranked, with the best and the fastest tagged.\n * `onUpdate` gets the ranked list each time another provider answers, so a\n * UI shows the first price as soon as the fastest venue replies. Routes the\n * caller's floor or fee caps refuse are left out. Execute the one the user\n * picks with `using(route.provider).swap2(...)`.\n */\n async quoteSwap2Routes(options: Swap2Options, opts?: {onUpdate?: (routes: Swap2Route[], pending: string[]) => void}): Promise<Swap2Route[]> {\n const snapshot = await this.prepareOptions(this.snapshotOf(options));\n const view = (set: RouteSet): Swap2Route[] =>\n set.quotes.flatMap((q) => {\n const quote = this.routeQuote(q, snapshot);\n return quote ? [{provider: q.provider, quote, netValueUsd: q.netValueUsd, relativeValue: q.relativeValue, tags: [...q.tags]}] : [];\n });\n const set = await this.router.getQuotes(this.toParams(snapshot, true), opts?.onUpdate\n ? {onUpdate: (partial) => opts.onUpdate!(view(partial), partial.pending)}\n : undefined);\n return set ? view(set) : [];\n }\n\n /** This protocol pinned to one provider — the route a user picked from `quoteSwap2Routes`. */\n using(provider: string): RouterSwap2Protocol {\n const {providers: _p, router: _r, ...rest} = this.routerConfig;\n return new RouterSwap2Protocol(this.account, {...rest, router: this.router.only(provider)});\n }\n\n protected override noRouteDetail(): string {\n return this.router.lastRejections.join(\"; \").slice(0, 400);\n }\n\n protected providerFor(name: string): CrossChainProvider | undefined {\n return this.router.getProvider(name);\n }\n\n /** Delegates to every provider the router holds (first match wins); null with no providers. */\n override describeActivity(tx: ChainTx, ctx: DescribeActivityContext): ActivityItem | null {\n return this.router.describeActivity(tx, ctx);\n }\n\n protected chainSupported(caip2: string): boolean {\n return this.router.supportsChain(caip2);\n }\n\n protected override pairSupported(fromChain: string, toChain: string): boolean {\n return this.router.supportsChainPair(fromChain, toChain);\n }\n\n /** Release the providers' resources (timers, sockets). */\n close(): void {\n this.router.close();\n }\n}\n","/**\n * The auction engine of the optional aggregator: routes a cross-chain delivery\n * over whichever providers the caller installed and passed in. Protocol\n * modules never need it — each one runs standalone on @anywalletkit/protocol-swap2-core.\n */\nimport type {\n CrossChainProvider,\n IntentRef,\n IntentStatus,\n Quote,\n QuoteParams,\n RoutedQuote,\n ScoreWeights,\n} from \"@anywalletkit/protocol-swap2-core/types\";\nimport {remotePinRefusal, validQuote} from \"@anywalletkit/protocol-swap2-core/validate\";\nimport type {ActivityItem, ChainTx, DescribeActivityContext} from \"@anywalletkit/core\";\nimport {bigintToNumber} from \"@anywalletkit/core\";\n\nconst DEFAULT_WEIGHTS: ScoreWeights = {price: 0.6, speed: 0.3, reliability: 0.1};\n/** Quotes within 0.2% of the best net value count as the same price. */\nconst DEFAULT_TIE_BAND = 0.002;\n\nexport interface RouterOptions {\n /**\n * \"price:0.6,speed:0.3,reliability:0.1\" — how quotes inside the tie band\n * (same price, within `tieBand`) are ordered. Price itself always leads.\n */\n weights?: string;\n /**\n * What a quote is worth to the user in USD: its guaranteed output minus what\n * the route charges on top (a native bridge fee, the source gas). Return null\n * when it cannot be priced — the auction then compares guaranteed outputs.\n * `usdValue(prices)` builds one from a symbol → USD price map.\n */\n valueUsd?: (quote: Quote, params: QuoteParams) => number | null;\n /** Fraction of the best net value inside which quotes tie on price (default 0.002). */\n tieBand?: number;\n}\n\n/** A validated quote with its place in the auction. */\nexport interface RankedQuote extends Quote {\n /** Net USD value (`valueUsd`), or null when the auction compared raw outputs. */\n netValueUsd: number | null;\n /** This quote's value against the best one, 0..1 (1 = the best price). */\n relativeValue: number;\n /** \"best\": the pick (best price; faster/more reliable among equal prices). \"fastest\": the lowest ETA. */\n tags: (\"best\" | \"fastest\")[];\n}\n\n/** Every validated route for one request, ranked by value. */\nexport interface RouteSet {\n /** Every validated route, best first. */\n quotes: RankedQuote[];\n /** Most delivered value (net of fees when priced) within the tie band. */\n best: RankedQuote;\n /** Lowest ETA. */\n fastest: RankedQuote;\n /** Providers still quoting (only non-empty in progressive `onUpdate` snapshots). */\n pending: string[];\n /** Why the venues that sat out did (same as `lastRejections`). */\n rejections: string[];\n}\n// LI.FI's /quote routinely takes ~3.5s (it builds executable calldata) — 4s\n// raced it out of every round. All providers still run in parallel.\nconst QUOTE_TIMEOUT_MS = 8000;\n/** Pinned single-venue (execution) budget — see the comment at the call site. */\nconst SOLO_QUOTE_TIMEOUT_MS = 25_000;\n\nfunction parseWeights(spec?: string): ScoreWeights {\n if (!spec) return DEFAULT_WEIGHTS;\n const w = {...DEFAULT_WEIGHTS};\n for (const part of spec.split(\",\")) {\n const [k, v] = part.split(\":\");\n const n = Number(v);\n if ((k === \"price\" || k === \"speed\" || k === \"reliability\") && Number.isFinite(n)) {\n w[k] = Math.max(0, n);\n }\n }\n return w;\n}\n\nasync function withTimeout<T>(p: Promise<T>, ms: number): Promise<T | null> {\n return new Promise((resolve, reject) => {\n // Timeouts and failures must REJECT: the old `() => resolve(null)` arm\n // swallowed every provider error — including forwarded venue refusals —\n // into a null indistinguishable from \"no route\", which made execution\n // failures undiagnosable from the surface (the '(c2)' hunt of 2026-08-31).\n const timer = setTimeout(() => reject(new Error(`quote timed out after ${ms}ms`)), ms);\n p.then(resolve, reject).finally(() => clearTimeout(timer));\n });\n}\n\n/**\n * Routes a cross-chain delivery over pluggable providers: queries all that\n * support the route in parallel (with a timeout so a slow provider can't block),\n * normalizes their quotes, scores by configurable weights, and returns the best\n * tagged with `routeScore`. A failed/slow provider simply doesn't participate.\n */\nexport class CrossChainRouter {\n private readonly providers: CrossChainProvider[];\n /** Why the venues of the LAST getBestQuote call sat out — for error surfaces. */\n private _lastRejections: string[] = [];\n /** Why providers sat out the last auction, one line each. */\n get lastRejections(): readonly string[] {\n return this._lastRejections;\n }\n private readonly weights: ScoreWeights;\n private readonly valueUsd: RouterOptions[\"valueUsd\"];\n private readonly tieBand: number;\n private readonly options: RouterOptions;\n\n constructor(providers: CrossChainProvider[], options?: string | RouterOptions) {\n const opts: RouterOptions = typeof options === \"string\" ? {weights: options} : {...(options ?? {})};\n if (opts.tieBand !== undefined && !(Number.isFinite(opts.tieBand) && opts.tieBand >= 0 && opts.tieBand < 1)) {\n throw new Error(\"cross-chain router: tieBand must be a fraction in [0, 1)\");\n }\n const names = new Set<string>();\n for (const provider of providers) {\n if (typeof provider.name !== \"string\" || !/^[A-Za-z0-9_-]+$/.test(provider.name) || names.has(provider.name)) {\n throw new Error(`cross-chain router: invalid or duplicate provider name '${String(provider.name)}'`);\n }\n names.add(provider.name);\n }\n // Snapshot the dispatch surface. A caller mutating provider.name or method\n // properties after construction must not redirect quote→build/status.\n this.providers = providers.map((provider) => ({\n name: provider.name,\n enabled: provider.enabled.bind(provider),\n supportsRoute: provider.supportsRoute.bind(provider),\n getQuote: provider.getQuote.bind(provider),\n buildDeposit: provider.buildDeposit.bind(provider),\n trackIntent: provider.trackIntent.bind(provider),\n ...(provider.preflightDeposit ? {preflightDeposit: provider.preflightDeposit.bind(provider)} : {}),\n ...(provider.notifyDeposit ? {notifyDeposit: provider.notifyDeposit.bind(provider)} : {}),\n ...(provider.registerSignedOrder ? {registerSignedOrder: provider.registerSignedOrder.bind(provider)} : {}),\n // Two-phase routes (CCTP): the destination claim. Missing here, the engine\n // and the server both reported \"provider 'cctp' has no claim step\" (2026-10-13).\n ...(provider.buildClaim ? {buildClaim: provider.buildClaim.bind(provider)} : {}),\n ...(provider.claimTargets ? {claimTargets: provider.claimTargets.bind(provider)} : {}),\n // A remote stub's marker and the app's pins (scan 2026-10-27 modules, F8/F9/F16): dropped here, the engine took a\n // remote provider for a local one and checked its calldata against the backend's own addresses.\n ...(provider.remote === true ? {remote: true} : {}),\n ...(provider.verifiesBuilds === true ? {verifiesBuilds: true} : {}),\n ...(provider.depositAddressRoutes === true ? {depositAddressRoutes: true} : {}),\n ...(provider.callTargets ? {callTargets: provider.callTargets.bind(provider)} : {}),\n ...(provider.spenders ? {spenders: provider.spenders.bind(provider)} : {}),\n ...(provider.close ? {close: provider.close.bind(provider)} : {}),\n ...(provider.supportsChain ? {supportsChain: provider.supportsChain.bind(provider)} : {}),\n ...(provider.supportsChainPair ? {supportsChainPair: provider.supportsChainPair.bind(provider)} : {}),\n ...(provider.describeActivity ? {describeActivity: provider.describeActivity.bind(provider)} : {}),\n ...(provider.supportsSameChain !== undefined ? {supportsSameChain: provider.supportsSameChain} : {}),\n }));\n this.weights = parseWeights(opts.weights);\n this.valueUsd = opts.valueUsd;\n this.tieBand = opts.tieBand ?? DEFAULT_TIE_BAND;\n this.options = opts;\n }\n\n /** The same auction restricted to one provider — to execute the route a user picked. */\n only(name: string): CrossChainRouter {\n const provider = this.getProvider(name);\n if (!provider) throw new Error(`cross-chain router: provider '${name}' is not registered`);\n return new CrossChainRouter([provider], this.options);\n }\n\n /**\n * Activity recognition across the installed providers: the first one that\n * claims the transaction describes it. Null when none does (or none is held).\n */\n describeActivity(tx: ChainTx, ctx: DescribeActivityContext): ActivityItem | null {\n for (const provider of this.providers) {\n const item = provider.describeActivity?.(tx, ctx);\n if (item) return item;\n }\n return null;\n }\n\n /** A provider by name. */\n getProvider(name: string): CrossChainProvider | undefined {\n return this.providers.find((p) => p.name === name);\n }\n\n /** True when a provider of that name is installed. */\n hasProvider(name: string): boolean {\n return this.providers.some((p) => p.name === name);\n }\n\n /** True when that provider is installed and enabled. */\n hasEnabledProvider(name: string): boolean {\n return this.providers.some((p) => {\n try { return p.name === name && p.enabled(); } catch { return false; }\n });\n }\n\n /** True when any enabled provider declares the chain. */\n supportsChain(caip2: string): boolean {\n return this.providers.some((p) => {\n try { return p.enabled() && !!p.supportsChain?.(caip2); } catch { return false; }\n });\n }\n\n /** True when any enabled provider declares the chain pair. */\n supportsChainPair(fromChain: string, toChain: string): boolean {\n return this.providers.some((p) => {\n try {\n return p.enabled() && (p.supportsChainPair?.(fromChain, toChain) ?? false);\n } catch { return false; }\n });\n }\n\n /**\n * The auction's pick: the best price (net of native fees and gas when\n * `valueUsd` is set; faster, then more reliable, among equal prices), or\n * the fastest route with `prefer: \"fastest\"`.\n */\n async getBestQuote(\n params: QuoteParams,\n options?: {requireImmediateExecution?: boolean; prefer?: \"best\" | \"fastest\"},\n ): Promise<RoutedQuote | null> {\n const set = await this.getQuotes(params, options);\n if (!set) return null;\n const pick = options?.prefer === \"fastest\" ? set.fastest : set.best;\n const {netValueUsd: _n, relativeValue: _r, tags: _t, ...quote} = pick;\n return {\n ...quote,\n routeScore: {\n score: pick.relativeValue,\n weights: this.weights,\n candidates: set.quotes.map((q) => ({\n provider: q.provider,\n sourceAmount: q.sourceAmount,\n etaSeconds: q.etaSeconds,\n score: q.relativeValue,\n minDestAmount: q.minDestAmount,\n netValueUsd: q.netValueUsd,\n })),\n },\n };\n }\n\n /**\n * Every validated route, ranked — for a route picker that shows the best and\n * the fastest and lets the user choose. Providers run in parallel; with\n * `onUpdate` each one that answers re-publishes the ranked set at once (the\n * first price shows in the time of the fastest venue, not the slowest).\n */\n async getQuotes(\n params: QuoteParams,\n options?: {requireImmediateExecution?: boolean; onUpdate?: (set: RouteSet) => void},\n ): Promise<RouteSet | null> {\n // A public engine caller — or one provider running in the same auction —\n // must not be able to rewrite another provider's request while async quote\n // work is in flight. QuoteParams is intentionally flat, so a frozen copy is\n // a complete execution snapshot.\n const rejections: string[] = [];\n this._lastRejections = rejections;\n const snapshot = Object.freeze({...params});\n const from = Object.freeze({chain: snapshot.sourceChain, token: snapshot.sourceToken});\n const to = Object.freeze({chain: snapshot.destChain, token: snapshot.destToken});\n // Only enabled (validated) providers that can serve the route participate.\n let eligible = this.providers.filter((p) => {\n try { return p.enabled() && p.supportsRoute(from, to); } catch { return false; }\n });\n if (snapshot.sourceChain === snapshot.destChain) {\n eligible = eligible.filter((p) => p.supportsSameChain === true);\n }\n if (eligible.length === 0) return null;\n\n // The short timeout protects the AUCTION — one slow venue must not hold\n // the others hostage. With a single eligible provider (a pinned execution\n // re-quote) there is nobody to protect, and a live deposit-creating quote\n // legitimately takes longer than a dry one (serverless hop + upstream\n // retries) — starving it surfaced as a terminal \"no route\" on execution.\n const timeoutMs = eligible.length === 1 ? SOLO_QUOTE_TIMEOUT_MS : QUOTE_TIMEOUT_MS;\n // Each venue names its own refusal (per call, so concurrent quotes cannot race).\n const refusals: (string | undefined)[] = [];\n const accepted: Quote[] = [];\n const pending = new Set(eligible.map((p) => p.name));\n const publish = () => {\n if (!options?.onUpdate || accepted.length === 0) return;\n const set = this.rank(accepted, snapshot, [...pending], rejections);\n try { options.onUpdate(set); } catch { /* an observer must not break the auction */ }\n };\n await Promise.all(eligible.map(async (p, i) => {\n const controller = new AbortController();\n const own = Object.freeze({...snapshot, onRefusal: (reason: string) => {\n refusals[i] ??= reason.startsWith(`${p.name}:`) ? reason : `${p.name}: ${reason}`;\n try { snapshot.onRefusal?.(reason); } catch { /* diagnostics only */ }\n }});\n let q: Quote | null = null;\n try {\n q = await withTimeout(p.getQuote(own, controller.signal), timeoutMs);\n if (!q) {\n // A provider RETURNING null (vs throwing) was the one silent path\n // left — record it so the surfaced no-route error names the venue.\n rejections.push(refusals[i] ?? `${p.name}: returned no quote`);\n } else if (!validQuote(q, snapshot, p.name)) {\n const reason = `${p.name}: rejected by validation (minDest=${q.minDestAmount} vs floor=${snapshot.minAmountOut ?? \"-\"}, validUntil=${q.validUntilMs}, now=${Date.now()})`;\n rejections.push(reason);\n console.warn(`swap2-router: ${reason}`);\n q = null;\n } else {\n // A remote stub's route that calls or approves an address the app did not pin: execution would refuse it.\n const unpinned = remotePinRefusal(p, q, snapshot.sourceChain);\n if (unpinned) {\n rejections.push(unpinned);\n console.warn(`swap2-router: ${unpinned}`);\n q = null;\n } else if (options?.requireImmediateExecution && !(q.depositAddress.length > 0 || q.txRequest !== undefined)) {\n // Legacy deposit-address screens cannot execute order-based quotes that\n // require a separate build/sign/register lifecycle.\n q = null;\n }\n }\n } catch (err) {\n // A failed venue sitting out silently is indistinguishable from \"no\n // route\" — record why (surfaced through lastRejections) and say it in\n // the console (same posture as onModuleSkipped).\n const reason = `${p.name}: ${err instanceof Error ? err.message.slice(0, 160) : String(err).slice(0, 160)}`;\n rejections.push(reason);\n console.warn(`swap2-router: quote failed — ${reason}`);\n q = null;\n } finally {\n controller.abort();\n }\n pending.delete(p.name);\n // Provider identity is an execution security boundary. Never trust the\n // provider field returned by an untrusted adapter; bind it to its slot.\n if (q) accepted.push({...q, provider: p.name});\n publish();\n }));\n if (accepted.length === 0) return null;\n return this.rank(accepted, snapshot, [], rejections);\n }\n\n /** Status from the named provider; `failed` when it is not installed. */\n async trackIntent(providerName: string, ref: IntentRef): Promise<IntentStatus> {\n const provider = this.getProvider(providerName);\n if (!provider) return {state: \"failed\"};\n return provider.trackIntent(ref);\n }\n\n /** Forward a source-broadcast notification to the intent's provider. */\n async notifyDeposit(providerName: string, intentId: string, txHash: string): Promise<void> {\n await this.getProvider(providerName)?.notifyDeposit?.(intentId, txHash);\n }\n\n /** Release every provider's resources. */\n close(): void {\n for (const provider of this.providers) provider.close?.();\n }\n\n /**\n * Price first: each quote's value is its net USD (`valueUsd`) — or, when any\n * quote cannot be priced, its guaranteed output — against the best one.\n * Quotes within `tieBand` of the best are the same price; among those the\n * weights order speed and reliability. A $0.01 edge no longer beats a route\n * that lands in seconds instead of twenty minutes, and a route that charges\n * a native bridge fee on top no longer wins on its gross output.\n */\n private rank(quotes: Quote[], params: QuoteParams, pending: string[], rejections: string[]): RouteSet {\n const usd = this.valueUsd ? quotes.map((q) => {\n try {\n const v = this.valueUsd!(q, params);\n return typeof v === \"number\" && Number.isFinite(v) ? v : null;\n } catch { return null; }\n }) : quotes.map(() => null);\n const priced = usd.every((v) => v !== null);\n let relative: number[];\n if (priced) {\n const values = usd as number[];\n const max = Math.max(...values);\n relative = values.map((v) => (max > 0 ? Math.max(0, v) / max : v >= max ? 1 : 0));\n } else {\n const outs = quotes.map((q) => BigInt(q.minDestAmount));\n const max = outs.reduce((a, b) => (b > a ? b : a));\n relative = outs.map((o) => fraction(o, max));\n }\n const ranked: RankedQuote[] = quotes.map((q, i) => ({\n ...q,\n netValueUsd: priced ? usd[i]! : null,\n relativeValue: relative[i]!,\n tags: [],\n }));\n\n const tier = ranked.filter((q) => q.relativeValue >= 1 - this.tieBand - 1e-12);\n const etas = tier.map((q) => q.etaSeconds);\n const minEta = Math.min(...etas);\n const maxEta = Math.max(...etas);\n const w = this.weights;\n const tieScore = (q: RankedQuote) =>\n w.price * q.relativeValue +\n w.speed * (maxEta === minEta ? 1 : (maxEta - q.etaSeconds) / (maxEta - minEta)) +\n w.reliability * q.reliability;\n const best = tier.reduce((a, b) => (tieScore(b) > tieScore(a) ? b : a));\n const fastest = ranked.reduce((a, b) =>\n b.etaSeconds < a.etaSeconds || (b.etaSeconds === a.etaSeconds && b.relativeValue > a.relativeValue) ? b : a);\n best.tags.push(\"best\");\n fastest.tags.push(\"fastest\");\n\n // The list reads top-down by value; the pick leads its price tier.\n ranked.sort((a, b) => (a === best ? -1 : b === best ? 1 : b.relativeValue - a.relativeValue || a.etaSeconds - b.etaSeconds));\n return {quotes: ranked, best, fastest, pending, rejections: [...rejections]};\n }\n}\n\n/** Ratio of two non-negative bigints as a 0..1 number. */\nfunction fraction(num: bigint, den: bigint): number {\n if (den === 0n) return 1;\n // scale to keep precision, then to float\n return bigintToNumber((num * 10_000n) / den) / 10_000;\n}\n"],"mappings":"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","names":["set"]}
|
|
1
|
+
{"version":3,"sources":["../../src/swap2/router.ts","../../src/router.ts"],"sourcesContent":["/**\n * The optional aggregator: one swap2 protocol that quotes every provider the\n * caller installed and passed in, in parallel, and executes the best route.\n *\n * Every provider package (`@anywalletkit/protocol-swap2-lifi`, `-near-intents`,\n * `-thorchain`, `-omniston`) also works on its own through its single-provider\n * protocol class; this package is only for callers who want an auction across\n * several of them. It has no dependency on any provider: capabilities\n * (supported chains / pairs) come from the providers themselves, or — for a\n * `remoteProvider` stub — from the `supportsChain`/`supportsChainPair` options\n * the caller fills in.\n *\n * ```ts\n * const swap2 = new RouterSwap2Protocol(account, {\n * fromChain: \"eip155:1\",\n * providers: [lifiProvider({...}), nearIntentsProvider({...})],\n * })\n * ```\n */\nimport {\n BaseSwap2Protocol,\n type Swap2Account,\n type Swap2EngineConfig,\n} from \"@anywalletkit/protocol-swap2-core/swap2/base\";\nimport type {CrossChainProvider, Quote, QuoteParams} from \"@anywalletkit/protocol-swap2-core/types\";\nimport type {ActivityItem, ChainTx, DescribeActivityContext, Swap2Options, Swap2Quote} from \"@anywalletkit/core\";\nimport {CrossChainRouter, type RouteSet, type RouterOptions} from \"../router.js\";\n\n/** One route in a picker: the public quote plus its place in the auction. */\nexport interface Swap2Route {\n /** Provider name. */\n provider: string;\n /** The provider's quote. */\n quote: Swap2Quote;\n /** Net USD value when the router prices routes (`valueUsd`), else null. */\n netValueUsd: number | null;\n /** Value against the best route, 0..1. */\n relativeValue: number;\n /** `best` (most value within the tie band) and/or `fastest` (lowest ETA). */\n tags: (\"best\" | \"fastest\")[];\n}\n\n/**\n * Options for {@link RouterSwap2Protocol}: the providers (or a ready router), route preference and\n * the engine options.\n */\nexport interface RouterSwap2Config extends Swap2EngineConfig {\n /** The providers to aggregate over. Only what the caller installs is bundled. */\n providers?: CrossChainProvider[];\n /**\n * Or a ready auction engine (e.g. to share one between protocols or tune its\n * score weights). Exactly one of `providers` / `router` is required.\n */\n router?: CrossChainRouter;\n /** Order inside a price tie for a router built from `providers`, e.g. \"price:0.7,speed:0.2,reliability:0.1\". */\n weights?: string;\n /** Net USD value of a quote for a router built from `providers` — see `usdValue(prices)`. */\n valueUsd?: RouterOptions[\"valueUsd\"];\n /** Fraction of the best value inside which routes tie on price (default 0.002). */\n tieBand?: number;\n /** What `swap2()` / `quoteSwap2()` execute when several routes answer: the best (default) or the fastest. */\n prefer?: \"best\" | \"fastest\";\n}\n\n/**\n * A swap2 protocol that asks every installed provider in parallel, checks each quote the same way,\n * and executes the chosen route. Pass exactly one of `providers` or `router`.\n *\n * ```ts\n * const swap2 = new RouterSwap2Protocol(account, {\n * fromChain: 'eip155:1',\n * providers: [lifiProvider(), nearIntentsProvider(), cctpProvider()],\n * })\n * const quote = await swap2.quoteSwap2({ fromToken: 'USDC', toToken: 'USDC', toChain: 'eip155:8453', fromTokenAmount: 100_000_000n })\n * ```\n */\nexport class RouterSwap2Protocol extends BaseSwap2Protocol {\n private readonly router: CrossChainRouter;\n private readonly account: Swap2Account | undefined;\n private readonly routerConfig: RouterSwap2Config;\n\n constructor(account: Swap2Account | undefined, config: RouterSwap2Config) {\n super(account, config);\n if (!!config.router === !!config.providers) {\n throw new Error(\"swap2: RouterSwap2Protocol needs exactly one of `providers` or `router`\");\n }\n if (config.prefer !== undefined && config.prefer !== \"best\" && config.prefer !== \"fastest\") {\n throw new Error(\"swap2: prefer must be \\\"best\\\" or \\\"fastest\\\"\");\n }\n this.router = config.router ?? new CrossChainRouter(config.providers!, {\n ...(config.weights !== undefined ? {weights: config.weights} : {}),\n ...(config.valueUsd ? {valueUsd: config.valueUsd} : {}),\n ...(config.tieBand !== undefined ? {tieBand: config.tieBand} : {}),\n });\n this.account = account;\n this.routerConfig = config;\n }\n\n protected resolveQuote(params: QuoteParams): Promise<Quote | null> {\n return this.router.getBestQuote(params, this.routerConfig.prefer ? {prefer: this.routerConfig.prefer} : undefined);\n }\n\n /**\n * Every route for a picker, ranked, with the best and the fastest tagged.\n * `onUpdate` gets the ranked list each time another provider answers, so a\n * UI shows the first price as soon as the fastest venue replies. Routes the\n * caller's floor or fee caps refuse are left out. Execute the one the user\n * picks with `using(route.provider).swap2(...)`.\n */\n async quoteSwap2Routes(options: Swap2Options, opts?: {onUpdate?: (routes: Swap2Route[], pending: string[]) => void}): Promise<Swap2Route[]> {\n const snapshot = await this.prepareOptions(this.snapshotOf(options));\n const view = (set: RouteSet): Swap2Route[] =>\n set.quotes.flatMap((q) => {\n const quote = this.routeQuote(q, snapshot);\n return quote ? [{provider: q.provider, quote, netValueUsd: q.netValueUsd, relativeValue: q.relativeValue, tags: [...q.tags]}] : [];\n });\n const set = await this.router.getQuotes(this.toParams(snapshot, true), opts?.onUpdate\n ? {onUpdate: (partial) => opts.onUpdate!(view(partial), partial.pending)}\n : undefined);\n return set ? view(set) : [];\n }\n\n /** This protocol pinned to one provider — the route a user picked from `quoteSwap2Routes`. */\n using(provider: string): RouterSwap2Protocol {\n const {providers: _p, router: _r, ...rest} = this.routerConfig;\n return new RouterSwap2Protocol(this.account, {...rest, router: this.router.only(provider)});\n }\n\n protected override noRouteDetail(): string {\n return this.router.lastRejections.join(\"; \").slice(0, 400);\n }\n\n protected providerFor(name: string): CrossChainProvider | undefined {\n return this.router.getProvider(name);\n }\n\n /** Delegates to every provider the router holds (first match wins); null with no providers. */\n override describeActivity(tx: ChainTx, ctx: DescribeActivityContext): ActivityItem | null {\n return this.router.describeActivity(tx, ctx);\n }\n\n protected chainSupported(caip2: string): boolean {\n return this.router.supportsChain(caip2);\n }\n\n protected override pairSupported(fromChain: string, toChain: string): boolean {\n return this.router.supportsChainPair(fromChain, toChain);\n }\n\n /** Release the providers' resources (timers, sockets). */\n close(): void {\n this.router.close();\n }\n}\n","/**\n * The auction engine of the optional aggregator: routes a cross-chain delivery\n * over whichever providers the caller installed and passed in. Protocol\n * modules never need it — each one runs standalone on @anywalletkit/protocol-swap2-core.\n */\nimport type {\n CrossChainProvider,\n IntentRef,\n IntentStatus,\n Quote,\n QuoteParams,\n RoutedQuote,\n ScoreWeights,\n} from \"@anywalletkit/protocol-swap2-core/types\";\nimport {remotePinRefusal, validQuote} from \"@anywalletkit/protocol-swap2-core/validate\";\nimport type {ActivityItem, ChainTx, DescribeActivityContext} from \"@anywalletkit/core\";\nimport {bigintToNumber} from \"@anywalletkit/core\";\n\nconst DEFAULT_WEIGHTS: ScoreWeights = {price: 0.6, speed: 0.3, reliability: 0.1};\n/** Quotes within 0.2% of the best net value count as the same price. */\nconst DEFAULT_TIE_BAND = 0.002;\n\nexport interface RouterOptions {\n /**\n * \"price:0.6,speed:0.3,reliability:0.1\" — how quotes inside the tie band\n * (same price, within `tieBand`) are ordered. Price itself always leads.\n */\n weights?: string;\n /**\n * What a quote is worth to the user in USD: its guaranteed output minus what\n * the route charges on top (a native bridge fee, the source gas). Return null\n * when it cannot be priced — the auction then compares guaranteed outputs.\n * `usdValue(prices)` builds one from a symbol → USD price map.\n */\n valueUsd?: (quote: Quote, params: QuoteParams) => number | null;\n /** Fraction of the best net value inside which quotes tie on price (default 0.002). */\n tieBand?: number;\n}\n\n/** A validated quote with its place in the auction. */\nexport interface RankedQuote extends Quote {\n /** Net USD value (`valueUsd`), or null when the auction compared raw outputs. */\n netValueUsd: number | null;\n /** This quote's value against the best one, 0..1 (1 = the best price). */\n relativeValue: number;\n /** \"best\": the pick (best price; faster/more reliable among equal prices). \"fastest\": the lowest ETA. */\n tags: (\"best\" | \"fastest\")[];\n}\n\n/** Every validated route for one request, ranked by value. */\nexport interface RouteSet {\n /** Every validated route, best first. */\n quotes: RankedQuote[];\n /** Most delivered value (net of fees when priced) within the tie band. */\n best: RankedQuote;\n /** Lowest ETA. */\n fastest: RankedQuote;\n /** Providers still quoting (only non-empty in progressive `onUpdate` snapshots). */\n pending: string[];\n /** Why the venues that sat out did (same as `lastRejections`). */\n rejections: string[];\n}\n// LI.FI's /quote routinely takes ~3.5s (it builds executable calldata) — 4s\n// raced it out of every round. All providers still run in parallel.\nconst QUOTE_TIMEOUT_MS = 8000;\n/** Pinned single-venue (execution) budget — see the comment at the call site. */\nconst SOLO_QUOTE_TIMEOUT_MS = 25_000;\n\nfunction parseWeights(spec?: string): ScoreWeights {\n if (!spec) return DEFAULT_WEIGHTS;\n const w = {...DEFAULT_WEIGHTS};\n for (const part of spec.split(\",\")) {\n const [k, v] = part.split(\":\");\n const n = Number(v);\n if ((k === \"price\" || k === \"speed\" || k === \"reliability\") && Number.isFinite(n)) {\n w[k] = Math.max(0, n);\n }\n }\n return w;\n}\n\nasync function withTimeout<T>(p: Promise<T>, ms: number): Promise<T | null> {\n return new Promise((resolve, reject) => {\n // Timeouts and failures must REJECT: the old `() => resolve(null)` arm\n // swallowed every provider error — including forwarded venue refusals —\n // into a null indistinguishable from \"no route\", which made execution\n // failures undiagnosable from the surface (the '(c2)' hunt of 2026-08-31).\n const timer = setTimeout(() => reject(new Error(`quote timed out after ${ms}ms`)), ms);\n p.then(resolve, reject).finally(() => clearTimeout(timer));\n });\n}\n\n/**\n * Routes a cross-chain delivery over pluggable providers: queries all that\n * support the route in parallel (with a timeout so a slow provider can't block),\n * normalizes their quotes, scores by configurable weights, and returns the best\n * tagged with `routeScore`. A failed/slow provider simply doesn't participate.\n */\nexport class CrossChainRouter {\n private readonly providers: CrossChainProvider[];\n /** Why the venues of the LAST getBestQuote call sat out — for error surfaces. */\n private _lastRejections: string[] = [];\n /** Why providers sat out the last auction, one line each. */\n get lastRejections(): readonly string[] {\n return this._lastRejections;\n }\n private readonly weights: ScoreWeights;\n private readonly valueUsd: RouterOptions[\"valueUsd\"];\n private readonly tieBand: number;\n private readonly options: RouterOptions;\n\n constructor(providers: CrossChainProvider[], options?: string | RouterOptions) {\n const opts: RouterOptions = typeof options === \"string\" ? {weights: options} : {...(options ?? {})};\n if (opts.tieBand !== undefined && !(Number.isFinite(opts.tieBand) && opts.tieBand >= 0 && opts.tieBand < 1)) {\n throw new Error(\"cross-chain router: tieBand must be a fraction in [0, 1)\");\n }\n const names = new Set<string>();\n for (const provider of providers) {\n if (typeof provider.name !== \"string\" || !/^[A-Za-z0-9_-]+$/.test(provider.name) || names.has(provider.name)) {\n throw new Error(`cross-chain router: invalid or duplicate provider name '${String(provider.name)}'`);\n }\n names.add(provider.name);\n }\n // Snapshot the dispatch surface. A caller mutating provider.name or method\n // properties after construction must not redirect quote→build/status.\n this.providers = providers.map((provider) => ({\n name: provider.name,\n enabled: provider.enabled.bind(provider),\n supportsRoute: provider.supportsRoute.bind(provider),\n getQuote: provider.getQuote.bind(provider),\n buildDeposit: provider.buildDeposit.bind(provider),\n trackIntent: provider.trackIntent.bind(provider),\n ...(provider.preflightDeposit ? {preflightDeposit: provider.preflightDeposit.bind(provider)} : {}),\n ...(provider.notifyDeposit ? {notifyDeposit: provider.notifyDeposit.bind(provider)} : {}),\n ...(provider.registerSignedOrder ? {registerSignedOrder: provider.registerSignedOrder.bind(provider)} : {}),\n // Two-phase routes (CCTP): the destination claim. Missing here, the engine\n // and the server both reported \"provider 'cctp' has no claim step\" (2026-10-13).\n ...(provider.buildClaim ? {buildClaim: provider.buildClaim.bind(provider)} : {}),\n ...(provider.claimTargets ? {claimTargets: provider.claimTargets.bind(provider)} : {}),\n // A remote stub's marker and the app's pins (scan 2026-10-27 modules, F8/F9/F16): dropped here, the engine took a\n // remote provider for a local one and checked its calldata against the backend's own addresses.\n ...(provider.remote === true ? {remote: true} : {}),\n ...(provider.verifiesBuilds === true ? {verifiesBuilds: true} : {}),\n ...(provider.verifiesQuotes === true ? {verifiesQuotes: true} : {}),\n ...(provider.depositAddressRoutes === true ? {depositAddressRoutes: true} : {}),\n ...(provider.callTargets ? {callTargets: provider.callTargets.bind(provider)} : {}),\n ...(provider.spenders ? {spenders: provider.spenders.bind(provider)} : {}),\n ...(provider.close ? {close: provider.close.bind(provider)} : {}),\n ...(provider.supportsChain ? {supportsChain: provider.supportsChain.bind(provider)} : {}),\n ...(provider.supportsChainPair ? {supportsChainPair: provider.supportsChainPair.bind(provider)} : {}),\n ...(provider.describeActivity ? {describeActivity: provider.describeActivity.bind(provider)} : {}),\n ...(provider.supportsSameChain !== undefined ? {supportsSameChain: provider.supportsSameChain} : {}),\n }));\n this.weights = parseWeights(opts.weights);\n this.valueUsd = opts.valueUsd;\n this.tieBand = opts.tieBand ?? DEFAULT_TIE_BAND;\n this.options = opts;\n }\n\n /** The same auction restricted to one provider — to execute the route a user picked. */\n only(name: string): CrossChainRouter {\n const provider = this.getProvider(name);\n if (!provider) throw new Error(`cross-chain router: provider '${name}' is not registered`);\n return new CrossChainRouter([provider], this.options);\n }\n\n /**\n * Activity recognition across the installed providers: the first one that\n * claims the transaction describes it. Null when none does (or none is held).\n */\n describeActivity(tx: ChainTx, ctx: DescribeActivityContext): ActivityItem | null {\n for (const provider of this.providers) {\n const item = provider.describeActivity?.(tx, ctx);\n if (item) return item;\n }\n return null;\n }\n\n /** A provider by name. */\n getProvider(name: string): CrossChainProvider | undefined {\n return this.providers.find((p) => p.name === name);\n }\n\n /** True when a provider of that name is installed. */\n hasProvider(name: string): boolean {\n return this.providers.some((p) => p.name === name);\n }\n\n /** True when that provider is installed and enabled. */\n hasEnabledProvider(name: string): boolean {\n return this.providers.some((p) => {\n try { return p.name === name && p.enabled(); } catch { return false; }\n });\n }\n\n /** True when any enabled provider declares the chain. */\n supportsChain(caip2: string): boolean {\n return this.providers.some((p) => {\n try { return p.enabled() && !!p.supportsChain?.(caip2); } catch { return false; }\n });\n }\n\n /** True when any enabled provider declares the chain pair. */\n supportsChainPair(fromChain: string, toChain: string): boolean {\n return this.providers.some((p) => {\n try {\n return p.enabled() && (p.supportsChainPair?.(fromChain, toChain) ?? false);\n } catch { return false; }\n });\n }\n\n /**\n * The auction's pick: the best price (net of native fees and gas when\n * `valueUsd` is set; faster, then more reliable, among equal prices), or\n * the fastest route with `prefer: \"fastest\"`.\n */\n async getBestQuote(\n params: QuoteParams,\n options?: {requireImmediateExecution?: boolean; prefer?: \"best\" | \"fastest\"},\n ): Promise<RoutedQuote | null> {\n const set = await this.getQuotes(params, options);\n if (!set) return null;\n const pick = options?.prefer === \"fastest\" ? set.fastest : set.best;\n const {netValueUsd: _n, relativeValue: _r, tags: _t, ...quote} = pick;\n return {\n ...quote,\n routeScore: {\n score: pick.relativeValue,\n weights: this.weights,\n candidates: set.quotes.map((q) => ({\n provider: q.provider,\n sourceAmount: q.sourceAmount,\n etaSeconds: q.etaSeconds,\n score: q.relativeValue,\n minDestAmount: q.minDestAmount,\n netValueUsd: q.netValueUsd,\n })),\n },\n };\n }\n\n /**\n * Every validated route, ranked — for a route picker that shows the best and\n * the fastest and lets the user choose. Providers run in parallel; with\n * `onUpdate` each one that answers re-publishes the ranked set at once (the\n * first price shows in the time of the fastest venue, not the slowest).\n */\n async getQuotes(\n params: QuoteParams,\n options?: {requireImmediateExecution?: boolean; onUpdate?: (set: RouteSet) => void},\n ): Promise<RouteSet | null> {\n // A public engine caller — or one provider running in the same auction —\n // must not be able to rewrite another provider's request while async quote\n // work is in flight. QuoteParams is intentionally flat, so a frozen copy is\n // a complete execution snapshot.\n const rejections: string[] = [];\n this._lastRejections = rejections;\n const snapshot = Object.freeze({...params});\n const from = Object.freeze({chain: snapshot.sourceChain, token: snapshot.sourceToken});\n const to = Object.freeze({chain: snapshot.destChain, token: snapshot.destToken});\n // Only enabled (validated) providers that can serve the route participate.\n let eligible = this.providers.filter((p) => {\n try { return p.enabled() && p.supportsRoute(from, to); } catch { return false; }\n });\n if (snapshot.sourceChain === snapshot.destChain) {\n eligible = eligible.filter((p) => p.supportsSameChain === true);\n }\n if (eligible.length === 0) return null;\n\n // The short timeout protects the AUCTION — one slow venue must not hold\n // the others hostage. With a single eligible provider (a pinned execution\n // re-quote) there is nobody to protect, and a live deposit-creating quote\n // legitimately takes longer than a dry one (serverless hop + upstream\n // retries) — starving it surfaced as a terminal \"no route\" on execution.\n const timeoutMs = eligible.length === 1 ? SOLO_QUOTE_TIMEOUT_MS : QUOTE_TIMEOUT_MS;\n // Each venue names its own refusal (per call, so concurrent quotes cannot race).\n const refusals: (string | undefined)[] = [];\n const accepted: Quote[] = [];\n const pending = new Set(eligible.map((p) => p.name));\n const publish = () => {\n if (!options?.onUpdate || accepted.length === 0) return;\n const set = this.rank(accepted, snapshot, [...pending], rejections);\n try { options.onUpdate(set); } catch { /* an observer must not break the auction */ }\n };\n await Promise.all(eligible.map(async (p, i) => {\n const controller = new AbortController();\n const own = Object.freeze({...snapshot, onRefusal: (reason: string) => {\n refusals[i] ??= reason.startsWith(`${p.name}:`) ? reason : `${p.name}: ${reason}`;\n try { snapshot.onRefusal?.(reason); } catch { /* diagnostics only */ }\n }});\n let q: Quote | null = null;\n try {\n q = await withTimeout(p.getQuote(own, controller.signal), timeoutMs);\n if (!q) {\n // A provider RETURNING null (vs throwing) was the one silent path\n // left — record it so the surfaced no-route error names the venue.\n rejections.push(refusals[i] ?? `${p.name}: returned no quote`);\n } else if (!validQuote(q, snapshot, p.name)) {\n const reason = `${p.name}: rejected by validation (minDest=${q.minDestAmount} vs floor=${snapshot.minAmountOut ?? \"-\"}, validUntil=${q.validUntilMs}, now=${Date.now()})`;\n rejections.push(reason);\n console.warn(`swap2-router: ${reason}`);\n q = null;\n } else {\n // A remote stub's route that calls or approves an address the app did not pin: execution would refuse it.\n const unpinned = remotePinRefusal(p, q, snapshot.sourceChain);\n if (unpinned) {\n rejections.push(unpinned);\n console.warn(`swap2-router: ${unpinned}`);\n q = null;\n } else if (options?.requireImmediateExecution && !(q.depositAddress.length > 0 || q.txRequest !== undefined)) {\n // Legacy deposit-address screens cannot execute order-based quotes that\n // require a separate build/sign/register lifecycle.\n q = null;\n }\n }\n } catch (err) {\n // A failed venue sitting out silently is indistinguishable from \"no\n // route\" — record why (surfaced through lastRejections) and say it in\n // the console (same posture as onModuleSkipped).\n const reason = `${p.name}: ${err instanceof Error ? err.message.slice(0, 160) : String(err).slice(0, 160)}`;\n rejections.push(reason);\n console.warn(`swap2-router: quote failed — ${reason}`);\n q = null;\n } finally {\n controller.abort();\n }\n pending.delete(p.name);\n // Provider identity is an execution security boundary. Never trust the\n // provider field returned by an untrusted adapter; bind it to its slot.\n if (q) accepted.push({...q, provider: p.name});\n publish();\n }));\n if (accepted.length === 0) return null;\n return this.rank(accepted, snapshot, [], rejections);\n }\n\n /** Status from the named provider; `failed` when it is not installed. */\n async trackIntent(providerName: string, ref: IntentRef): Promise<IntentStatus> {\n const provider = this.getProvider(providerName);\n if (!provider) return {state: \"failed\"};\n return provider.trackIntent(ref);\n }\n\n /** Forward a source-broadcast notification to the intent's provider. */\n async notifyDeposit(providerName: string, intentId: string, txHash: string): Promise<void> {\n await this.getProvider(providerName)?.notifyDeposit?.(intentId, txHash);\n }\n\n /** Release every provider's resources. */\n close(): void {\n for (const provider of this.providers) provider.close?.();\n }\n\n /**\n * Price first: each quote's value is its net USD (`valueUsd`) — or, when any\n * quote cannot be priced, its guaranteed output — against the best one.\n * Quotes within `tieBand` of the best are the same price; among those the\n * weights order speed and reliability. A $0.01 edge no longer beats a route\n * that lands in seconds instead of twenty minutes, and a route that charges\n * a native bridge fee on top no longer wins on its gross output.\n */\n private rank(quotes: Quote[], params: QuoteParams, pending: string[], rejections: string[]): RouteSet {\n const usd = this.valueUsd ? quotes.map((q) => {\n try {\n const v = this.valueUsd!(q, params);\n return typeof v === \"number\" && Number.isFinite(v) ? v : null;\n } catch { return null; }\n }) : quotes.map(() => null);\n const priced = usd.every((v) => v !== null);\n let relative: number[];\n if (priced) {\n const values = usd as number[];\n const max = Math.max(...values);\n relative = values.map((v) => (max > 0 ? Math.max(0, v) / max : v >= max ? 1 : 0));\n } else {\n const outs = quotes.map((q) => BigInt(q.minDestAmount));\n const max = outs.reduce((a, b) => (b > a ? b : a));\n relative = outs.map((o) => fraction(o, max));\n }\n const ranked: RankedQuote[] = quotes.map((q, i) => ({\n ...q,\n netValueUsd: priced ? usd[i]! : null,\n relativeValue: relative[i]!,\n tags: [],\n }));\n\n const tier = ranked.filter((q) => q.relativeValue >= 1 - this.tieBand - 1e-12);\n const etas = tier.map((q) => q.etaSeconds);\n const minEta = Math.min(...etas);\n const maxEta = Math.max(...etas);\n const w = this.weights;\n const tieScore = (q: RankedQuote) =>\n w.price * q.relativeValue +\n w.speed * (maxEta === minEta ? 1 : (maxEta - q.etaSeconds) / (maxEta - minEta)) +\n w.reliability * q.reliability;\n const best = tier.reduce((a, b) => (tieScore(b) > tieScore(a) ? b : a));\n const fastest = ranked.reduce((a, b) =>\n b.etaSeconds < a.etaSeconds || (b.etaSeconds === a.etaSeconds && b.relativeValue > a.relativeValue) ? b : a);\n best.tags.push(\"best\");\n fastest.tags.push(\"fastest\");\n\n // The list reads top-down by value; the pick leads its price tier.\n ranked.sort((a, b) => (a === best ? -1 : b === best ? 1 : b.relativeValue - a.relativeValue || a.etaSeconds - b.etaSeconds));\n return {quotes: ranked, best, fastest, pending, rejections: [...rejections]};\n }\n}\n\n/** Ratio of two non-negative bigints as a 0..1 number. */\nfunction fraction(num: bigint, den: bigint): number {\n if (den === 0n) return 1;\n // scale to keep precision, then to float\n return bigintToNumber((num * 10_000n) / den) / 10_000;\n}\n"],"mappings":"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","names":["set"]}
|
package/dist/swap2/router.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@anywalletkit/protocol-swap2-router",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Optional swap2 aggregator for Any Wallet Kit: auctions whichever swap2 providers you install and pass in.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"homepage": "https://docs.anywallet.tech",
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
"module.json"
|
|
50
50
|
],
|
|
51
51
|
"dependencies": {
|
|
52
|
-
"@anywalletkit/protocol-swap2-core": "0.
|
|
52
|
+
"@anywalletkit/protocol-swap2-core": "0.9.0",
|
|
53
53
|
"@anywalletkit/swap2-assets": "0.2.2"
|
|
54
54
|
},
|
|
55
55
|
"peerDependencies": {
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/router.ts"],"sourcesContent":["/**\n * The auction engine of the optional aggregator: routes a cross-chain delivery\n * over whichever providers the caller installed and passed in. Protocol\n * modules never need it — each one runs standalone on @anywalletkit/protocol-swap2-core.\n */\nimport type {\n CrossChainProvider,\n IntentRef,\n IntentStatus,\n Quote,\n QuoteParams,\n RoutedQuote,\n ScoreWeights,\n} from \"@anywalletkit/protocol-swap2-core/types\";\nimport {remotePinRefusal, validQuote} from \"@anywalletkit/protocol-swap2-core/validate\";\nimport type {ActivityItem, ChainTx, DescribeActivityContext} from \"@anywalletkit/core\";\nimport {bigintToNumber} from \"@anywalletkit/core\";\n\nconst DEFAULT_WEIGHTS: ScoreWeights = {price: 0.6, speed: 0.3, reliability: 0.1};\n/** Quotes within 0.2% of the best net value count as the same price. */\nconst DEFAULT_TIE_BAND = 0.002;\n\nexport interface RouterOptions {\n /**\n * \"price:0.6,speed:0.3,reliability:0.1\" — how quotes inside the tie band\n * (same price, within `tieBand`) are ordered. Price itself always leads.\n */\n weights?: string;\n /**\n * What a quote is worth to the user in USD: its guaranteed output minus what\n * the route charges on top (a native bridge fee, the source gas). Return null\n * when it cannot be priced — the auction then compares guaranteed outputs.\n * `usdValue(prices)` builds one from a symbol → USD price map.\n */\n valueUsd?: (quote: Quote, params: QuoteParams) => number | null;\n /** Fraction of the best net value inside which quotes tie on price (default 0.002). */\n tieBand?: number;\n}\n\n/** A validated quote with its place in the auction. */\nexport interface RankedQuote extends Quote {\n /** Net USD value (`valueUsd`), or null when the auction compared raw outputs. */\n netValueUsd: number | null;\n /** This quote's value against the best one, 0..1 (1 = the best price). */\n relativeValue: number;\n /** \"best\": the pick (best price; faster/more reliable among equal prices). \"fastest\": the lowest ETA. */\n tags: (\"best\" | \"fastest\")[];\n}\n\n/** Every validated route for one request, ranked by value. */\nexport interface RouteSet {\n /** Every validated route, best first. */\n quotes: RankedQuote[];\n /** Most delivered value (net of fees when priced) within the tie band. */\n best: RankedQuote;\n /** Lowest ETA. */\n fastest: RankedQuote;\n /** Providers still quoting (only non-empty in progressive `onUpdate` snapshots). */\n pending: string[];\n /** Why the venues that sat out did (same as `lastRejections`). */\n rejections: string[];\n}\n// LI.FI's /quote routinely takes ~3.5s (it builds executable calldata) — 4s\n// raced it out of every round. All providers still run in parallel.\nconst QUOTE_TIMEOUT_MS = 8000;\n/** Pinned single-venue (execution) budget — see the comment at the call site. */\nconst SOLO_QUOTE_TIMEOUT_MS = 25_000;\n\nfunction parseWeights(spec?: string): ScoreWeights {\n if (!spec) return DEFAULT_WEIGHTS;\n const w = {...DEFAULT_WEIGHTS};\n for (const part of spec.split(\",\")) {\n const [k, v] = part.split(\":\");\n const n = Number(v);\n if ((k === \"price\" || k === \"speed\" || k === \"reliability\") && Number.isFinite(n)) {\n w[k] = Math.max(0, n);\n }\n }\n return w;\n}\n\nasync function withTimeout<T>(p: Promise<T>, ms: number): Promise<T | null> {\n return new Promise((resolve, reject) => {\n // Timeouts and failures must REJECT: the old `() => resolve(null)` arm\n // swallowed every provider error — including forwarded venue refusals —\n // into a null indistinguishable from \"no route\", which made execution\n // failures undiagnosable from the surface (the '(c2)' hunt of 2026-08-31).\n const timer = setTimeout(() => reject(new Error(`quote timed out after ${ms}ms`)), ms);\n p.then(resolve, reject).finally(() => clearTimeout(timer));\n });\n}\n\n/**\n * Routes a cross-chain delivery over pluggable providers: queries all that\n * support the route in parallel (with a timeout so a slow provider can't block),\n * normalizes their quotes, scores by configurable weights, and returns the best\n * tagged with `routeScore`. A failed/slow provider simply doesn't participate.\n */\nexport class CrossChainRouter {\n private readonly providers: CrossChainProvider[];\n /** Why the venues of the LAST getBestQuote call sat out — for error surfaces. */\n private _lastRejections: string[] = [];\n /** Why providers sat out the last auction, one line each. */\n get lastRejections(): readonly string[] {\n return this._lastRejections;\n }\n private readonly weights: ScoreWeights;\n private readonly valueUsd: RouterOptions[\"valueUsd\"];\n private readonly tieBand: number;\n private readonly options: RouterOptions;\n\n constructor(providers: CrossChainProvider[], options?: string | RouterOptions) {\n const opts: RouterOptions = typeof options === \"string\" ? {weights: options} : {...(options ?? {})};\n if (opts.tieBand !== undefined && !(Number.isFinite(opts.tieBand) && opts.tieBand >= 0 && opts.tieBand < 1)) {\n throw new Error(\"cross-chain router: tieBand must be a fraction in [0, 1)\");\n }\n const names = new Set<string>();\n for (const provider of providers) {\n if (typeof provider.name !== \"string\" || !/^[A-Za-z0-9_-]+$/.test(provider.name) || names.has(provider.name)) {\n throw new Error(`cross-chain router: invalid or duplicate provider name '${String(provider.name)}'`);\n }\n names.add(provider.name);\n }\n // Snapshot the dispatch surface. A caller mutating provider.name or method\n // properties after construction must not redirect quote→build/status.\n this.providers = providers.map((provider) => ({\n name: provider.name,\n enabled: provider.enabled.bind(provider),\n supportsRoute: provider.supportsRoute.bind(provider),\n getQuote: provider.getQuote.bind(provider),\n buildDeposit: provider.buildDeposit.bind(provider),\n trackIntent: provider.trackIntent.bind(provider),\n ...(provider.preflightDeposit ? {preflightDeposit: provider.preflightDeposit.bind(provider)} : {}),\n ...(provider.notifyDeposit ? {notifyDeposit: provider.notifyDeposit.bind(provider)} : {}),\n ...(provider.registerSignedOrder ? {registerSignedOrder: provider.registerSignedOrder.bind(provider)} : {}),\n // Two-phase routes (CCTP): the destination claim. Missing here, the engine\n // and the server both reported \"provider 'cctp' has no claim step\" (2026-10-13).\n ...(provider.buildClaim ? {buildClaim: provider.buildClaim.bind(provider)} : {}),\n ...(provider.claimTargets ? {claimTargets: provider.claimTargets.bind(provider)} : {}),\n // A remote stub's marker and the app's pins (scan 2026-10-27 modules, F8/F9/F16): dropped here, the engine took a\n // remote provider for a local one and checked its calldata against the backend's own addresses.\n ...(provider.remote === true ? {remote: true} : {}),\n ...(provider.verifiesBuilds === true ? {verifiesBuilds: true} : {}),\n ...(provider.depositAddressRoutes === true ? {depositAddressRoutes: true} : {}),\n ...(provider.callTargets ? {callTargets: provider.callTargets.bind(provider)} : {}),\n ...(provider.spenders ? {spenders: provider.spenders.bind(provider)} : {}),\n ...(provider.close ? {close: provider.close.bind(provider)} : {}),\n ...(provider.supportsChain ? {supportsChain: provider.supportsChain.bind(provider)} : {}),\n ...(provider.supportsChainPair ? {supportsChainPair: provider.supportsChainPair.bind(provider)} : {}),\n ...(provider.describeActivity ? {describeActivity: provider.describeActivity.bind(provider)} : {}),\n ...(provider.supportsSameChain !== undefined ? {supportsSameChain: provider.supportsSameChain} : {}),\n }));\n this.weights = parseWeights(opts.weights);\n this.valueUsd = opts.valueUsd;\n this.tieBand = opts.tieBand ?? DEFAULT_TIE_BAND;\n this.options = opts;\n }\n\n /** The same auction restricted to one provider — to execute the route a user picked. */\n only(name: string): CrossChainRouter {\n const provider = this.getProvider(name);\n if (!provider) throw new Error(`cross-chain router: provider '${name}' is not registered`);\n return new CrossChainRouter([provider], this.options);\n }\n\n /**\n * Activity recognition across the installed providers: the first one that\n * claims the transaction describes it. Null when none does (or none is held).\n */\n describeActivity(tx: ChainTx, ctx: DescribeActivityContext): ActivityItem | null {\n for (const provider of this.providers) {\n const item = provider.describeActivity?.(tx, ctx);\n if (item) return item;\n }\n return null;\n }\n\n /** A provider by name. */\n getProvider(name: string): CrossChainProvider | undefined {\n return this.providers.find((p) => p.name === name);\n }\n\n /** True when a provider of that name is installed. */\n hasProvider(name: string): boolean {\n return this.providers.some((p) => p.name === name);\n }\n\n /** True when that provider is installed and enabled. */\n hasEnabledProvider(name: string): boolean {\n return this.providers.some((p) => {\n try { return p.name === name && p.enabled(); } catch { return false; }\n });\n }\n\n /** True when any enabled provider declares the chain. */\n supportsChain(caip2: string): boolean {\n return this.providers.some((p) => {\n try { return p.enabled() && !!p.supportsChain?.(caip2); } catch { return false; }\n });\n }\n\n /** True when any enabled provider declares the chain pair. */\n supportsChainPair(fromChain: string, toChain: string): boolean {\n return this.providers.some((p) => {\n try {\n return p.enabled() && (p.supportsChainPair?.(fromChain, toChain) ?? false);\n } catch { return false; }\n });\n }\n\n /**\n * The auction's pick: the best price (net of native fees and gas when\n * `valueUsd` is set; faster, then more reliable, among equal prices), or\n * the fastest route with `prefer: \"fastest\"`.\n */\n async getBestQuote(\n params: QuoteParams,\n options?: {requireImmediateExecution?: boolean; prefer?: \"best\" | \"fastest\"},\n ): Promise<RoutedQuote | null> {\n const set = await this.getQuotes(params, options);\n if (!set) return null;\n const pick = options?.prefer === \"fastest\" ? set.fastest : set.best;\n const {netValueUsd: _n, relativeValue: _r, tags: _t, ...quote} = pick;\n return {\n ...quote,\n routeScore: {\n score: pick.relativeValue,\n weights: this.weights,\n candidates: set.quotes.map((q) => ({\n provider: q.provider,\n sourceAmount: q.sourceAmount,\n etaSeconds: q.etaSeconds,\n score: q.relativeValue,\n minDestAmount: q.minDestAmount,\n netValueUsd: q.netValueUsd,\n })),\n },\n };\n }\n\n /**\n * Every validated route, ranked — for a route picker that shows the best and\n * the fastest and lets the user choose. Providers run in parallel; with\n * `onUpdate` each one that answers re-publishes the ranked set at once (the\n * first price shows in the time of the fastest venue, not the slowest).\n */\n async getQuotes(\n params: QuoteParams,\n options?: {requireImmediateExecution?: boolean; onUpdate?: (set: RouteSet) => void},\n ): Promise<RouteSet | null> {\n // A public engine caller — or one provider running in the same auction —\n // must not be able to rewrite another provider's request while async quote\n // work is in flight. QuoteParams is intentionally flat, so a frozen copy is\n // a complete execution snapshot.\n const rejections: string[] = [];\n this._lastRejections = rejections;\n const snapshot = Object.freeze({...params});\n const from = Object.freeze({chain: snapshot.sourceChain, token: snapshot.sourceToken});\n const to = Object.freeze({chain: snapshot.destChain, token: snapshot.destToken});\n // Only enabled (validated) providers that can serve the route participate.\n let eligible = this.providers.filter((p) => {\n try { return p.enabled() && p.supportsRoute(from, to); } catch { return false; }\n });\n if (snapshot.sourceChain === snapshot.destChain) {\n eligible = eligible.filter((p) => p.supportsSameChain === true);\n }\n if (eligible.length === 0) return null;\n\n // The short timeout protects the AUCTION — one slow venue must not hold\n // the others hostage. With a single eligible provider (a pinned execution\n // re-quote) there is nobody to protect, and a live deposit-creating quote\n // legitimately takes longer than a dry one (serverless hop + upstream\n // retries) — starving it surfaced as a terminal \"no route\" on execution.\n const timeoutMs = eligible.length === 1 ? SOLO_QUOTE_TIMEOUT_MS : QUOTE_TIMEOUT_MS;\n // Each venue names its own refusal (per call, so concurrent quotes cannot race).\n const refusals: (string | undefined)[] = [];\n const accepted: Quote[] = [];\n const pending = new Set(eligible.map((p) => p.name));\n const publish = () => {\n if (!options?.onUpdate || accepted.length === 0) return;\n const set = this.rank(accepted, snapshot, [...pending], rejections);\n try { options.onUpdate(set); } catch { /* an observer must not break the auction */ }\n };\n await Promise.all(eligible.map(async (p, i) => {\n const controller = new AbortController();\n const own = Object.freeze({...snapshot, onRefusal: (reason: string) => {\n refusals[i] ??= reason.startsWith(`${p.name}:`) ? reason : `${p.name}: ${reason}`;\n try { snapshot.onRefusal?.(reason); } catch { /* diagnostics only */ }\n }});\n let q: Quote | null = null;\n try {\n q = await withTimeout(p.getQuote(own, controller.signal), timeoutMs);\n if (!q) {\n // A provider RETURNING null (vs throwing) was the one silent path\n // left — record it so the surfaced no-route error names the venue.\n rejections.push(refusals[i] ?? `${p.name}: returned no quote`);\n } else if (!validQuote(q, snapshot, p.name)) {\n const reason = `${p.name}: rejected by validation (minDest=${q.minDestAmount} vs floor=${snapshot.minAmountOut ?? \"-\"}, validUntil=${q.validUntilMs}, now=${Date.now()})`;\n rejections.push(reason);\n console.warn(`swap2-router: ${reason}`);\n q = null;\n } else {\n // A remote stub's route that calls or approves an address the app did not pin: execution would refuse it.\n const unpinned = remotePinRefusal(p, q, snapshot.sourceChain);\n if (unpinned) {\n rejections.push(unpinned);\n console.warn(`swap2-router: ${unpinned}`);\n q = null;\n } else if (options?.requireImmediateExecution && !(q.depositAddress.length > 0 || q.txRequest !== undefined)) {\n // Legacy deposit-address screens cannot execute order-based quotes that\n // require a separate build/sign/register lifecycle.\n q = null;\n }\n }\n } catch (err) {\n // A failed venue sitting out silently is indistinguishable from \"no\n // route\" — record why (surfaced through lastRejections) and say it in\n // the console (same posture as onModuleSkipped).\n const reason = `${p.name}: ${err instanceof Error ? err.message.slice(0, 160) : String(err).slice(0, 160)}`;\n rejections.push(reason);\n console.warn(`swap2-router: quote failed — ${reason}`);\n q = null;\n } finally {\n controller.abort();\n }\n pending.delete(p.name);\n // Provider identity is an execution security boundary. Never trust the\n // provider field returned by an untrusted adapter; bind it to its slot.\n if (q) accepted.push({...q, provider: p.name});\n publish();\n }));\n if (accepted.length === 0) return null;\n return this.rank(accepted, snapshot, [], rejections);\n }\n\n /** Status from the named provider; `failed` when it is not installed. */\n async trackIntent(providerName: string, ref: IntentRef): Promise<IntentStatus> {\n const provider = this.getProvider(providerName);\n if (!provider) return {state: \"failed\"};\n return provider.trackIntent(ref);\n }\n\n /** Forward a source-broadcast notification to the intent's provider. */\n async notifyDeposit(providerName: string, intentId: string, txHash: string): Promise<void> {\n await this.getProvider(providerName)?.notifyDeposit?.(intentId, txHash);\n }\n\n /** Release every provider's resources. */\n close(): void {\n for (const provider of this.providers) provider.close?.();\n }\n\n /**\n * Price first: each quote's value is its net USD (`valueUsd`) — or, when any\n * quote cannot be priced, its guaranteed output — against the best one.\n * Quotes within `tieBand` of the best are the same price; among those the\n * weights order speed and reliability. A $0.01 edge no longer beats a route\n * that lands in seconds instead of twenty minutes, and a route that charges\n * a native bridge fee on top no longer wins on its gross output.\n */\n private rank(quotes: Quote[], params: QuoteParams, pending: string[], rejections: string[]): RouteSet {\n const usd = this.valueUsd ? quotes.map((q) => {\n try {\n const v = this.valueUsd!(q, params);\n return typeof v === \"number\" && Number.isFinite(v) ? v : null;\n } catch { return null; }\n }) : quotes.map(() => null);\n const priced = usd.every((v) => v !== null);\n let relative: number[];\n if (priced) {\n const values = usd as number[];\n const max = Math.max(...values);\n relative = values.map((v) => (max > 0 ? Math.max(0, v) / max : v >= max ? 1 : 0));\n } else {\n const outs = quotes.map((q) => BigInt(q.minDestAmount));\n const max = outs.reduce((a, b) => (b > a ? b : a));\n relative = outs.map((o) => fraction(o, max));\n }\n const ranked: RankedQuote[] = quotes.map((q, i) => ({\n ...q,\n netValueUsd: priced ? usd[i]! : null,\n relativeValue: relative[i]!,\n tags: [],\n }));\n\n const tier = ranked.filter((q) => q.relativeValue >= 1 - this.tieBand - 1e-12);\n const etas = tier.map((q) => q.etaSeconds);\n const minEta = Math.min(...etas);\n const maxEta = Math.max(...etas);\n const w = this.weights;\n const tieScore = (q: RankedQuote) =>\n w.price * q.relativeValue +\n w.speed * (maxEta === minEta ? 1 : (maxEta - q.etaSeconds) / (maxEta - minEta)) +\n w.reliability * q.reliability;\n const best = tier.reduce((a, b) => (tieScore(b) > tieScore(a) ? b : a));\n const fastest = ranked.reduce((a, b) =>\n b.etaSeconds < a.etaSeconds || (b.etaSeconds === a.etaSeconds && b.relativeValue > a.relativeValue) ? b : a);\n best.tags.push(\"best\");\n fastest.tags.push(\"fastest\");\n\n // The list reads top-down by value; the pick leads its price tier.\n ranked.sort((a, b) => (a === best ? -1 : b === best ? 1 : b.relativeValue - a.relativeValue || a.etaSeconds - b.etaSeconds));\n return {quotes: ranked, best, fastest, pending, rejections: [...rejections]};\n }\n}\n\n/** Ratio of two non-negative bigints as a 0..1 number. */\nfunction fraction(num: bigint, den: bigint): number {\n if (den === 0n) return 1;\n // scale to keep precision, then to float\n return bigintToNumber((num * 10_000n) / den) / 10_000;\n}\n"],"mappings":"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","names":[]}
|
|
File without changes
|