@anywalletkit/protocol-swap2-router 0.0.0-stage → 0.2.2
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/LICENSE +202 -0
- package/README.md +70 -2
- package/dist/chunk-6WXEWTIF.js +296 -0
- package/dist/chunk-6WXEWTIF.js.map +1 -0
- package/dist/chunk-ATQMEXTG.js +98 -0
- package/dist/chunk-ATQMEXTG.js.map +1 -0
- package/dist/chunk-VRUHVDAX.js +78 -0
- package/dist/chunk-VRUHVDAX.js.map +1 -0
- package/dist/index.cjs +487 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +7 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +22 -0
- package/dist/index.js.map +1 -0
- package/dist/router.cjs +316 -0
- package/dist/router.cjs.map +1 -0
- package/dist/router.d.cts +118 -0
- package/dist/router.d.ts +118 -0
- package/dist/router.js +7 -0
- package/dist/router.js.map +1 -0
- package/dist/swap2/router.cjs +386 -0
- package/dist/swap2/router.cjs.map +1 -0
- package/dist/swap2/router.d.cts +100 -0
- package/dist/swap2/router.d.ts +100 -0
- package/dist/swap2/router.js +8 -0
- package/dist/swap2/router.js.map +1 -0
- package/dist/value.cjs +118 -0
- package/dist/value.cjs.map +1 -0
- package/dist/value.d.cts +51 -0
- package/dist/value.d.ts +51 -0
- package/dist/value.js +9 -0
- package/dist/value.js.map +1 -0
- package/module.json +20 -0
- package/package.json +69 -3
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
// src/value.ts
|
|
2
|
+
import { bigintToNumber, bigintToUnits } from "@anywalletkit/core";
|
|
3
|
+
import { ccAssetByToken, ccChain } from "@anywalletkit/swap2-assets";
|
|
4
|
+
var PAR = /^(USDC|USDT|USDT0|USD₮0|DAI|USDC\.E)$/i;
|
|
5
|
+
function priceOf(prices, symbol) {
|
|
6
|
+
const tries = [symbol, symbol.toUpperCase()];
|
|
7
|
+
if (/^w/i.test(symbol) && symbol.length > 2) tries.push(symbol.slice(1), symbol.slice(1).toUpperCase());
|
|
8
|
+
for (const t of tries) {
|
|
9
|
+
const p = prices[t];
|
|
10
|
+
if (typeof p === "number" && Number.isFinite(p) && p > 0) return p;
|
|
11
|
+
}
|
|
12
|
+
return PAR.test(symbol) ? 1 : null;
|
|
13
|
+
}
|
|
14
|
+
var units = (amount, decimals) => bigintToUnits(BigInt(amount), decimals);
|
|
15
|
+
function usdValue(prices, options) {
|
|
16
|
+
return (quote, params) => {
|
|
17
|
+
const dest = ccAssetByToken(params.destChain, params.destToken);
|
|
18
|
+
if (!dest) return null;
|
|
19
|
+
const destPrice = priceOf(prices, dest.symbol);
|
|
20
|
+
if (destPrice === null) return null;
|
|
21
|
+
let value = units(quote.minDestAmount, dest.decimals) * destPrice;
|
|
22
|
+
const nativeFee = quote.txRequest?.nativeFee;
|
|
23
|
+
if (nativeFee && BigInt(nativeFee) > 0n) {
|
|
24
|
+
const native = ccAssetByToken(params.sourceChain, "");
|
|
25
|
+
const nativePrice = native ? priceOf(prices, native.symbol) : null;
|
|
26
|
+
if (!native || nativePrice === null) return null;
|
|
27
|
+
value -= units(nativeFee, native.decimals) * nativePrice;
|
|
28
|
+
}
|
|
29
|
+
if (options?.gasUsd) {
|
|
30
|
+
const gas = options.gasUsd(quote, params);
|
|
31
|
+
if (gas === null || !Number.isFinite(gas)) return null;
|
|
32
|
+
value -= gas;
|
|
33
|
+
}
|
|
34
|
+
return value;
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
function assetFor(chain, token) {
|
|
38
|
+
const byToken = ccAssetByToken(chain, token);
|
|
39
|
+
if (byToken) return byToken;
|
|
40
|
+
const want = token.toLowerCase();
|
|
41
|
+
return ccChain(chain)?.assets.find((a) => a.symbol.toLowerCase() === want);
|
|
42
|
+
}
|
|
43
|
+
function quoteValues(prices, params, quotes, options = {}) {
|
|
44
|
+
const betterBy = options.betterByPct ?? 2;
|
|
45
|
+
const src = assetFor(params.sourceChain, params.sourceToken);
|
|
46
|
+
const dest = assetFor(params.destChain, params.destToken);
|
|
47
|
+
const srcPrice = src ? priceOf(prices, src.symbol) : null;
|
|
48
|
+
const destPrice = dest ? priceOf(prices, dest.symbol) : null;
|
|
49
|
+
let valueUsdIn = null;
|
|
50
|
+
if (src && srcPrice !== null) {
|
|
51
|
+
try {
|
|
52
|
+
valueUsdIn = units(params.amountIn, src.decimals) * srcPrice;
|
|
53
|
+
} catch {
|
|
54
|
+
valueUsdIn = null;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
const out = quotes.map((q) => {
|
|
58
|
+
let valueUsdOut = null;
|
|
59
|
+
if (dest && destPrice !== null) {
|
|
60
|
+
try {
|
|
61
|
+
valueUsdOut = units(q.destAmount, dest.decimals) * destPrice;
|
|
62
|
+
const nativeFee = q.txRequest?.nativeFee;
|
|
63
|
+
if (nativeFee && BigInt(nativeFee) > 0n) {
|
|
64
|
+
const native = ccAssetByToken(params.sourceChain, "");
|
|
65
|
+
const nativePrice = native ? priceOf(prices, native.symbol) : null;
|
|
66
|
+
if (native && nativePrice !== null) valueUsdOut -= units(nativeFee, native.decimals) * nativePrice;
|
|
67
|
+
}
|
|
68
|
+
} catch {
|
|
69
|
+
valueUsdOut = null;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
const lossPct = valueUsdIn !== null && valueUsdIn > 0 && valueUsdOut !== null ? (valueUsdIn - valueUsdOut) / valueUsdIn * 100 : null;
|
|
73
|
+
const impact = q.providerData?.priceImpactBps;
|
|
74
|
+
const priceImpactBps = typeof impact === "string" && /^\d+$/.test(impact) ? Number(impact) : void 0;
|
|
75
|
+
const v = { provider: q.provider, valueUsdIn, valueUsdOut, lossPct };
|
|
76
|
+
if (priceImpactBps !== void 0) v.priceImpactBps = priceImpactBps;
|
|
77
|
+
return v;
|
|
78
|
+
});
|
|
79
|
+
const allPriced = out.length > 1 && out.every((v) => v.valueUsdOut !== null);
|
|
80
|
+
if (out.length > 1) {
|
|
81
|
+
const measure = (v) => allPriced ? v.valueUsdOut : bigintToNumber(BigInt(quotes.find((q) => q.provider === v.provider).destAmount));
|
|
82
|
+
const top = out.reduce((a, b) => measure(b) > measure(a) ? b : a);
|
|
83
|
+
const topQuote = quotes.find((q) => q.provider === top.provider);
|
|
84
|
+
for (const v of out) {
|
|
85
|
+
if (v === top) continue;
|
|
86
|
+
const mine = measure(v);
|
|
87
|
+
const byPct = mine > 0 ? (measure(top) - mine) / mine * 100 : Infinity;
|
|
88
|
+
if (byPct > betterBy) v.betterAlternative = { provider: top.provider, valueUsdOut: top.valueUsdOut, destAmount: topQuote.destAmount, byPct };
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return out;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export {
|
|
95
|
+
usdValue,
|
|
96
|
+
quoteValues
|
|
97
|
+
};
|
|
98
|
+
//# sourceMappingURL=chunk-ATQMEXTG.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/value.ts"],"sourcesContent":["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\ntype ValueParams = Pick<QuoteParams, \"sourceChain\" | \"sourceToken\" | \"destChain\" | \"destToken\" | \"amountIn\">;\ntype 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"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CrossChainRouter
|
|
3
|
+
} from "./chunk-6WXEWTIF.js";
|
|
4
|
+
|
|
5
|
+
// src/swap2/router.ts
|
|
6
|
+
import {
|
|
7
|
+
BaseSwap2Protocol
|
|
8
|
+
} from "@anywalletkit/protocol-swap2-core/swap2/base";
|
|
9
|
+
var RouterSwap2Protocol = class _RouterSwap2Protocol extends BaseSwap2Protocol {
|
|
10
|
+
router;
|
|
11
|
+
account;
|
|
12
|
+
routerConfig;
|
|
13
|
+
constructor(account, config) {
|
|
14
|
+
super(account, config);
|
|
15
|
+
if (!!config.router === !!config.providers) {
|
|
16
|
+
throw new Error("swap2: RouterSwap2Protocol needs exactly one of `providers` or `router`");
|
|
17
|
+
}
|
|
18
|
+
if (config.prefer !== void 0 && config.prefer !== "best" && config.prefer !== "fastest") {
|
|
19
|
+
throw new Error('swap2: prefer must be "best" or "fastest"');
|
|
20
|
+
}
|
|
21
|
+
this.router = config.router ?? new CrossChainRouter(config.providers, {
|
|
22
|
+
...config.weights !== void 0 ? { weights: config.weights } : {},
|
|
23
|
+
...config.valueUsd ? { valueUsd: config.valueUsd } : {},
|
|
24
|
+
...config.tieBand !== void 0 ? { tieBand: config.tieBand } : {}
|
|
25
|
+
});
|
|
26
|
+
this.account = account;
|
|
27
|
+
this.routerConfig = config;
|
|
28
|
+
}
|
|
29
|
+
resolveQuote(params) {
|
|
30
|
+
return this.router.getBestQuote(params, this.routerConfig.prefer ? { prefer: this.routerConfig.prefer } : void 0);
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Every route for a picker, ranked, with the best and the fastest tagged.
|
|
34
|
+
* `onUpdate` gets the ranked list each time another provider answers, so a
|
|
35
|
+
* UI shows the first price as soon as the fastest venue replies. Routes the
|
|
36
|
+
* caller's floor or fee caps refuse are left out. Execute the one the user
|
|
37
|
+
* picks with `using(route.provider).swap2(...)`.
|
|
38
|
+
*/
|
|
39
|
+
async quoteSwap2Routes(options, opts) {
|
|
40
|
+
const snapshot = this.snapshotOf(options);
|
|
41
|
+
const view = (set2) => set2.quotes.flatMap((q) => {
|
|
42
|
+
const quote = this.routeQuote(q, snapshot);
|
|
43
|
+
return quote ? [{ provider: q.provider, quote, netValueUsd: q.netValueUsd, relativeValue: q.relativeValue, tags: [...q.tags] }] : [];
|
|
44
|
+
});
|
|
45
|
+
const set = await this.router.getQuotes(this.toParams(snapshot, true), opts?.onUpdate ? { onUpdate: (partial) => opts.onUpdate(view(partial), partial.pending) } : void 0);
|
|
46
|
+
return set ? view(set) : [];
|
|
47
|
+
}
|
|
48
|
+
/** This protocol pinned to one provider — the route a user picked from `quoteSwap2Routes`. */
|
|
49
|
+
using(provider) {
|
|
50
|
+
const { providers: _p, router: _r, ...rest } = this.routerConfig;
|
|
51
|
+
return new _RouterSwap2Protocol(this.account, { ...rest, router: this.router.only(provider) });
|
|
52
|
+
}
|
|
53
|
+
noRouteDetail() {
|
|
54
|
+
return this.router.lastRejections.join("; ").slice(0, 400);
|
|
55
|
+
}
|
|
56
|
+
providerFor(name) {
|
|
57
|
+
return this.router.getProvider(name);
|
|
58
|
+
}
|
|
59
|
+
/** Delegates to every provider the router holds (first match wins); null with no providers. */
|
|
60
|
+
describeActivity(tx, ctx) {
|
|
61
|
+
return this.router.describeActivity(tx, ctx);
|
|
62
|
+
}
|
|
63
|
+
chainSupported(caip2) {
|
|
64
|
+
return this.router.supportsChain(caip2);
|
|
65
|
+
}
|
|
66
|
+
pairSupported(fromChain, toChain) {
|
|
67
|
+
return this.router.supportsChainPair(fromChain, toChain);
|
|
68
|
+
}
|
|
69
|
+
/** Release the providers' resources (timers, sockets). */
|
|
70
|
+
close() {
|
|
71
|
+
this.router.close();
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
export {
|
|
76
|
+
RouterSwap2Protocol
|
|
77
|
+
};
|
|
78
|
+
//# sourceMappingURL=chunk-VRUHVDAX.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/swap2/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 = 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":";;;;;AAmBA;AAAA,EACE;AAAA,OAGK;AAqDA,IAAM,sBAAN,MAAM,6BAA4B,kBAAkB;AAAA,EACxC;AAAA,EACA;AAAA,EACA;AAAA,EAEjB,YAAY,SAAmC,QAA2B;AACxE,UAAM,SAAS,MAAM;AACrB,QAAI,CAAC,CAAC,OAAO,WAAW,CAAC,CAAC,OAAO,WAAW;AAC1C,YAAM,IAAI,MAAM,yEAAyE;AAAA,IAC3F;AACA,QAAI,OAAO,WAAW,UAAa,OAAO,WAAW,UAAU,OAAO,WAAW,WAAW;AAC1F,YAAM,IAAI,MAAM,2CAA+C;AAAA,IACjE;AACA,SAAK,SAAS,OAAO,UAAU,IAAI,iBAAiB,OAAO,WAAY;AAAA,MACrE,GAAI,OAAO,YAAY,SAAY,EAAC,SAAS,OAAO,QAAO,IAAI,CAAC;AAAA,MAChE,GAAI,OAAO,WAAW,EAAC,UAAU,OAAO,SAAQ,IAAI,CAAC;AAAA,MACrD,GAAI,OAAO,YAAY,SAAY,EAAC,SAAS,OAAO,QAAO,IAAI,CAAC;AAAA,IAClE,CAAC;AACD,SAAK,UAAU;AACf,SAAK,eAAe;AAAA,EACtB;AAAA,EAEU,aAAa,QAA4C;AACjE,WAAO,KAAK,OAAO,aAAa,QAAQ,KAAK,aAAa,SAAS,EAAC,QAAQ,KAAK,aAAa,OAAM,IAAI,MAAS;AAAA,EACnH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,iBAAiB,SAAuB,MAA8F;AAC1I,UAAM,WAAW,KAAK,WAAW,OAAO;AACxC,UAAM,OAAO,CAACA,SACZA,KAAI,OAAO,QAAQ,CAAC,MAAM;AACxB,YAAM,QAAQ,KAAK,WAAW,GAAG,QAAQ;AACzC,aAAO,QAAQ,CAAC,EAAC,UAAU,EAAE,UAAU,OAAO,aAAa,EAAE,aAAa,eAAe,EAAE,eAAe,MAAM,CAAC,GAAG,EAAE,IAAI,EAAC,CAAC,IAAI,CAAC;AAAA,IACnI,CAAC;AACH,UAAM,MAAM,MAAM,KAAK,OAAO,UAAU,KAAK,SAAS,UAAU,IAAI,GAAG,MAAM,WACzE,EAAC,UAAU,CAAC,YAAY,KAAK,SAAU,KAAK,OAAO,GAAG,QAAQ,OAAO,EAAC,IACtE,MAAS;AACb,WAAO,MAAM,KAAK,GAAG,IAAI,CAAC;AAAA,EAC5B;AAAA;AAAA,EAGA,MAAM,UAAuC;AAC3C,UAAM,EAAC,WAAW,IAAI,QAAQ,IAAI,GAAG,KAAI,IAAI,KAAK;AAClD,WAAO,IAAI,qBAAoB,KAAK,SAAS,EAAC,GAAG,MAAM,QAAQ,KAAK,OAAO,KAAK,QAAQ,EAAC,CAAC;AAAA,EAC5F;AAAA,EAEmB,gBAAwB;AACzC,WAAO,KAAK,OAAO,eAAe,KAAK,IAAI,EAAE,MAAM,GAAG,GAAG;AAAA,EAC3D;AAAA,EAEU,YAAY,MAA8C;AAClE,WAAO,KAAK,OAAO,YAAY,IAAI;AAAA,EACrC;AAAA;AAAA,EAGS,iBAAiB,IAAa,KAAmD;AACxF,WAAO,KAAK,OAAO,iBAAiB,IAAI,GAAG;AAAA,EAC7C;AAAA,EAEU,eAAe,OAAwB;AAC/C,WAAO,KAAK,OAAO,cAAc,KAAK;AAAA,EACxC;AAAA,EAEmB,cAAc,WAAmB,SAA0B;AAC5E,WAAO,KAAK,OAAO,kBAAkB,WAAW,OAAO;AAAA,EACzD;AAAA;AAAA,EAGA,QAAc;AACZ,SAAK,OAAO,MAAM;AAAA,EACpB;AACF;","names":["set"]}
|