@anywalletkit/protocol-swap2-core 0.4.1 → 0.6.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/README.md +2 -1
- package/dist/{chunk-Y3VUEWYI.js → chunk-IGTMUTNJ.js} +106 -28
- package/dist/chunk-IGTMUTNJ.js.map +1 -0
- package/dist/{chunk-GDRKGFLH.js → chunk-JFGMF6FO.js} +2 -2
- package/dist/{chunk-SKV5BVXK.js → chunk-MNJTMSFN.js} +8 -2
- package/dist/chunk-MNJTMSFN.js.map +1 -0
- package/dist/{chunk-4H2JVYXT.js → chunk-ZMWK3RQ4.js} +4 -3
- package/dist/chunk-ZMWK3RQ4.js.map +1 -0
- package/dist/index.cjs +119 -37
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +7 -5
- package/dist/remote.cjs +3 -1
- package/dist/remote.cjs.map +1 -1
- package/dist/remote.d.cts +6 -0
- package/dist/remote.d.ts +6 -0
- package/dist/remote.js +2 -2
- package/dist/server.cjs +8 -4
- package/dist/server.cjs.map +1 -1
- package/dist/server.d.cts +7 -0
- package/dist/server.d.ts +7 -0
- package/dist/server.js +8 -5
- package/dist/server.js.map +1 -1
- package/dist/swap2/base.cjs +101 -26
- package/dist/swap2/base.cjs.map +1 -1
- package/dist/swap2/base.d.cts +21 -1
- package/dist/swap2/base.d.ts +21 -1
- package/dist/swap2/base.js +1 -1
- package/dist/swap2/single.cjs +101 -26
- package/dist/swap2/single.cjs.map +1 -1
- package/dist/swap2/single.d.cts +1 -0
- package/dist/swap2/single.d.ts +1 -0
- package/dist/swap2/single.js +2 -2
- package/dist/types.cjs.map +1 -1
- package/dist/types.d.cts +13 -0
- package/dist/types.d.ts +13 -0
- package/dist/util.cjs +6 -0
- package/dist/util.cjs.map +1 -1
- package/dist/util.d.cts +12 -1
- package/dist/util.d.ts +12 -1
- package/dist/util.js +3 -1
- package/package.json +7 -7
- package/dist/chunk-4H2JVYXT.js.map +0 -1
- package/dist/chunk-SKV5BVXK.js.map +0 -1
- package/dist/chunk-Y3VUEWYI.js.map +0 -1
- /package/dist/{chunk-GDRKGFLH.js.map → chunk-JFGMF6FO.js.map} +0 -0
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// src/util.ts
|
|
2
|
+
import { resolveAsset } from "@anywalletkit/swap2-assets";
|
|
2
3
|
function namespace(chain) {
|
|
3
4
|
return chain.split(":")[0] ?? "";
|
|
4
5
|
}
|
|
@@ -31,6 +32,10 @@ function anySignal(signals) {
|
|
|
31
32
|
function redactUrls(text) {
|
|
32
33
|
return text.replace(/\b[a-z][a-z0-9+.-]*:\/\/[^\s"'<>]+/gi, "<url>");
|
|
33
34
|
}
|
|
35
|
+
function sourceAssetOf(params) {
|
|
36
|
+
const decimals = params.sourceDecimals;
|
|
37
|
+
return resolveAsset(params.sourceChain, params.sourceToken, decimals === void 0 ? {} : { allowUnlisted: true, decimals });
|
|
38
|
+
}
|
|
34
39
|
|
|
35
40
|
export {
|
|
36
41
|
namespace,
|
|
@@ -38,6 +43,7 @@ export {
|
|
|
38
43
|
evmRef,
|
|
39
44
|
timeoutSignal,
|
|
40
45
|
anySignal,
|
|
41
|
-
redactUrls
|
|
46
|
+
redactUrls,
|
|
47
|
+
sourceAssetOf
|
|
42
48
|
};
|
|
43
|
-
//# sourceMappingURL=chunk-
|
|
49
|
+
//# sourceMappingURL=chunk-MNJTMSFN.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/util.ts"],"sourcesContent":["import {resolveAsset, type CcAsset} from \"@anywalletkit/swap2-assets\";\nimport type {QuoteParams} from \"./types.js\";\n/** Shared CAIP-2 helpers. Contribution packages never read deployment env. */\nexport function namespace(chain: string): string {\n return chain.split(\":\")[0] ?? \"\";\n}\n/** True for an `eip155:` chain id. */\nexport function isEvm(chain: string): boolean {\n return namespace(chain) === \"eip155\";\n}\n/** Numeric chain id of an `eip155:<id>` CAIP-2 id. */\nexport function evmRef(chain: string): number {\n return Number(chain.split(\":\")[1] ?? \"0\");\n}\n\n/**\n * `AbortSignal.timeout`, portably: Hermes (React Native) ships AbortController\n * but not the static helpers, and the unguarded call threw\n * \"AbortSignal.timeout is not a function\" on every remote execution — which\n * the auction then read as \"no route\". Falls back to a manual controller.\n */\nexport function timeoutSignal(ms: number): AbortSignal {\n const native = (AbortSignal as unknown as {timeout?: (ms: number) => AbortSignal}).timeout;\n if (typeof native === \"function\") return native.call(AbortSignal, ms);\n const ctrl = new AbortController();\n setTimeout(() => ctrl.abort(), ms);\n return ctrl.signal;\n}\n\n/** `AbortSignal.any`, portably (see timeoutSignal). */\nexport function anySignal(signals: readonly AbortSignal[]): AbortSignal {\n const native = (AbortSignal as unknown as {any?: (s: readonly AbortSignal[]) => AbortSignal}).any;\n if (typeof native === \"function\") return native.call(AbortSignal, signals);\n const ctrl = new AbortController();\n for (const s of signals) {\n if (s.aborted) {\n ctrl.abort();\n break;\n }\n s.addEventListener(\"abort\", () => ctrl.abort(), {once: true});\n }\n return ctrl.signal;\n}\n\n/**\n * Remove URLs from text that may travel to a client (a refusal reason, a build error):\n * transport errors carry the endpoint — and with a keyed RPC (QuickNode, Alchemy,\n * Infura…) the key sits in its path (scan 2026-10-23 F8).\n */\nexport function redactUrls(text: string): string {\n return text.replace(/\\b[a-z][a-z0-9+.-]*:\\/\\/[^\\s\"'<>]+/gi, \"<url>\");\n}\n\n/**\n * The source asset a provider is asked to sell: the catalog's entry for `params.sourceToken`, or —\n * only when the engine sent `sourceDecimals` (an unlisted token the user added) — an unlisted asset\n * named by its contract / mint. Providers that can trade any token use this instead of the catalog\n * lookup; the others keep refusing what the catalog does not list.\n */\nexport function sourceAssetOf(params: Pick<QuoteParams, \"sourceChain\" | \"sourceToken\" | \"sourceDecimals\">): CcAsset | undefined {\n const decimals = params.sourceDecimals;\n return resolveAsset(params.sourceChain, params.sourceToken, decimals === undefined ? {} : {allowUnlisted: true, decimals});\n}\n"],"mappings":";AAAA,SAAQ,oBAAiC;AAGlC,SAAS,UAAU,OAAuB;AAC/C,SAAO,MAAM,MAAM,GAAG,EAAE,CAAC,KAAK;AAChC;AAEO,SAAS,MAAM,OAAwB;AAC5C,SAAO,UAAU,KAAK,MAAM;AAC9B;AAEO,SAAS,OAAO,OAAuB;AAC5C,SAAO,OAAO,MAAM,MAAM,GAAG,EAAE,CAAC,KAAK,GAAG;AAC1C;AAQO,SAAS,cAAc,IAAyB;AACrD,QAAM,SAAU,YAAmE;AACnF,MAAI,OAAO,WAAW,WAAY,QAAO,OAAO,KAAK,aAAa,EAAE;AACpE,QAAM,OAAO,IAAI,gBAAgB;AACjC,aAAW,MAAM,KAAK,MAAM,GAAG,EAAE;AACjC,SAAO,KAAK;AACd;AAGO,SAAS,UAAU,SAA8C;AACtE,QAAM,SAAU,YAA8E;AAC9F,MAAI,OAAO,WAAW,WAAY,QAAO,OAAO,KAAK,aAAa,OAAO;AACzE,QAAM,OAAO,IAAI,gBAAgB;AACjC,aAAW,KAAK,SAAS;AACvB,QAAI,EAAE,SAAS;AACb,WAAK,MAAM;AACX;AAAA,IACF;AACA,MAAE,iBAAiB,SAAS,MAAM,KAAK,MAAM,GAAG,EAAC,MAAM,KAAI,CAAC;AAAA,EAC9D;AACA,SAAO,KAAK;AACd;AAOO,SAAS,WAAW,MAAsB;AAC/C,SAAO,KAAK,QAAQ,wCAAwC,OAAO;AACrE;AAQO,SAAS,cAAc,QAAkG;AAC9H,QAAM,WAAW,OAAO;AACxB,SAAO,aAAa,OAAO,aAAa,OAAO,aAAa,aAAa,SAAY,CAAC,IAAI,EAAC,eAAe,MAAM,SAAQ,CAAC;AAC3H;","names":[]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
anySignal,
|
|
3
3
|
timeoutSignal
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-MNJTMSFN.js";
|
|
5
5
|
|
|
6
6
|
// src/remote.ts
|
|
7
7
|
function remoteProvider(opts) {
|
|
@@ -72,11 +72,12 @@ function remoteProvider(opts) {
|
|
|
72
72
|
},
|
|
73
73
|
...opts.supportsChain ? { supportsChain: opts.supportsChain.bind(opts) } : {},
|
|
74
74
|
...opts.supportsChainPair ? { supportsChainPair: opts.supportsChainPair.bind(opts) } : {},
|
|
75
|
-
...opts.supportsSameChain !== void 0 ? { supportsSameChain: opts.supportsSameChain } : {}
|
|
75
|
+
...opts.supportsSameChain !== void 0 ? { supportsSameChain: opts.supportsSameChain } : {},
|
|
76
|
+
...opts.claimTargets ? { claimTargets: opts.claimTargets } : {}
|
|
76
77
|
};
|
|
77
78
|
}
|
|
78
79
|
|
|
79
80
|
export {
|
|
80
81
|
remoteProvider
|
|
81
82
|
};
|
|
82
|
-
//# sourceMappingURL=chunk-
|
|
83
|
+
//# sourceMappingURL=chunk-ZMWK3RQ4.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/remote.ts"],"sourcesContent":["import type {Asset, CrossChainProvider, IntentRef, IntentStatus, Quote, QuoteParams, UnsignedTx} from \"./types.js\";\nimport {anySignal, timeoutSignal} from \"./util.js\";\n\n/**\n * HTTP-proxied `CrossChainProvider`: forwards every provider call to a backend\n * that runs the real provider. This is how a BROWSER context (e.g. a wallet's\n * signing worker) executes the full swap2 layer — account binding,\n * approvals, cell-body guards, id/status lifecycle — while provider secrets\n * (API JWTs, affiliate config) and non-CORS REST endpoints stay server-side.\n *\n * Wire protocol: POST {baseUrl}/{action} with a JSON body, one action per\n * provider method:\n * quote {provider, params: QuoteParams} → Quote | null\n * build {provider, quote: Quote} → UnsignedTx\n * preflight {provider, quote: Quote, tx: UnsignedTx} → {}\n * track {provider, ref: IntentRef} → IntentStatus\n * notify {provider, intentId, txHash} → {}\n * register {provider, intentId, signature} → {}\n * claim {provider, ref: IntentRef} → UnsignedTx | null\n * supports {provider, from, to} → {supported: boolean}\n *\n * `supportsRoute`/`enabled` need a SYNC answer, so they are config: pass the\n * routes the backend advertises via `supports`, or leave the default\n * allow-and-let-quote-decide behavior (a null quote is a clean miss).\n */\nexport interface RemoteProviderOptions {\n /** Provider name the backend multiplexes on (e.g. \"near-intents\"). */\n name: string;\n /** Endpoint prefix, e.g. \"/api/v2/swap2\" (same-origin) or absolute URL. */\n baseUrl: string;\n /** Sync capability gate; defaults to true (the backend quote decides). */\n supportsRoute?: (from: Asset, to: Asset) => boolean;\n /** Optional synchronous dark flag for accurate client-side discovery. */\n enabled?: () => boolean;\n /** Optional chain-level discovery hooks mirrored from the backend. */\n supportsChain?: (caip2: string) => boolean;\n supportsChainPair?: (fromChain: string, toChain: string) => boolean;\n /** Explicit opt-in when the backend can execute same-chain swaps. */\n supportsSameChain?: boolean;\n /**\n * The contracts this provider's claims may call, per chain (e.g. `cctpClaimTargets` from\n * `@anywalletkit/protocol-swap2-cctp`). The app's list, not the server's: without it the engine\n * refuses claims from this stub (round 3, M24).\n */\n claimTargets?: (chain: string) => readonly string[];\n /** Defaults to globalThis.fetch — injectable for tests. */\n fetchImpl?: typeof fetch;\n /** Extra headers (e.g. auth) attached to every call. */\n headers?: Record<string, string>;\n /** Per-request fail-closed timeout. Defaults to 12 seconds. */\n timeoutMs?: number;\n}\n\n/**\n * A provider that runs on your server: quotes, deposits and tracking go to `baseUrl`, so API keys\n * and affiliate settings never ship in the app. The engine still validates every quote and\n * transaction locally before signing.\n */\nexport function remoteProvider(opts: RemoteProviderOptions): CrossChainProvider {\n const name = opts.name;\n if (!/^[A-Za-z0-9_-]+$/.test(name)) throw new Error(\"swap2-remote: invalid provider name\");\n const baseUrl = opts.baseUrl.replace(/\\/+$/, \"\");\n if (!baseUrl) throw new Error(\"swap2-remote: baseUrl is required\");\n const supportsRoute = opts.supportsRoute;\n const enabled = opts.enabled;\n const headers = Object.freeze({...opts.headers});\n const doFetch = opts.fetchImpl ?? fetch;\n const timeoutMs = opts.timeoutMs ?? 12_000;\n if (!Number.isInteger(timeoutMs) || timeoutMs <= 0 || timeoutMs > 60_000) {\n throw new Error(\"swap2-remote: timeoutMs must be an integer between 1 and 60000\");\n }\n\n async function call<T>(action: string, body: Record<string, unknown>, signal?: AbortSignal): Promise<T> {\n const timeout = timeoutSignal(timeoutMs);\n const requestSignal = signal ? anySignal([signal, timeout]) : timeout;\n const res = await doFetch(`${baseUrl}/${action}`, {\n method: \"POST\",\n headers: {...headers, \"content-type\": \"application/json\"},\n // UnsignedTx carries bigint fields (value, gasLimit) — JSON.stringify\n // throws on them (\"Do not know how to serialize a BigInt\", seen\n // 2026-10-10 on a Solana → Base preflight). Wire them as decimal strings.\n body: JSON.stringify({provider: name, ...body}, (_k, v) => (typeof v === \"bigint\" ? v.toString() : v)),\n signal: requestSignal,\n });\n if (!res.ok) {\n // Surface the backend's message — provider errors are actionable\n // (\"quote expired\", \"route unsupported\"), not just status codes.\n const text = await res.text().catch(() => \"\");\n throw new Error(`swap2-remote ${name}/${action}: ${res.status} ${text.slice(0, 300)}`);\n }\n return (await res.json()) as T;\n }\n\n return {\n name,\n // The browser side has no dark-flag env; the backend enforces its own\n // flags — a disabled provider simply quotes null / rejects build.\n enabled: () => enabled ? enabled() : true,\n supportsRoute(from: Asset, to: Asset): boolean {\n return supportsRoute ? supportsRoute(from, to) : true;\n },\n async getQuote(params: QuoteParams, signal?: AbortSignal): Promise<Quote | null> {\n const out = await call<Quote | {noQuote: string} | null>(\"quote\", {params}, signal);\n if (out && typeof out === \"object\" && \"noQuote\" in out) {\n // The backend forwarded the venue's own refusal — throw it so the\n // router records a REASON instead of an anonymous null.\n throw new Error(String((out as {noQuote: unknown}).noQuote).slice(0, 300));\n }\n return out;\n },\n async buildDeposit(quote: Quote): Promise<UnsignedTx> {\n return call<UnsignedTx>(\"build\", {quote});\n },\n async preflightDeposit(quote: Quote, tx: UnsignedTx): Promise<void> {\n await call<Record<string, never>>(\"preflight\", {quote, tx});\n },\n async trackIntent(ref: IntentRef): Promise<IntentStatus> {\n return call<IntentStatus>(\"track\", {ref});\n },\n async notifyDeposit(intentId: string, txHash: string): Promise<void> {\n await call<Record<string, never>>(\"notify\", {intentId, txHash});\n },\n async registerSignedOrder(intentId: string, signature: string): Promise<void> {\n await call<Record<string, never>>(\"register\", {intentId, signature});\n },\n async buildClaim(ref: IntentRef): Promise<UnsignedTx | null> {\n const out = await call<UnsignedTx | null | Record<string, never>>(\"claim\", {ref});\n // A backend without the action (older deploy) answers {} — treat as \"not ready\".\n if (!out || typeof out !== \"object\" || !(\"to\" in out)) return null;\n return out as UnsignedTx;\n },\n ...(opts.supportsChain ? {supportsChain: opts.supportsChain.bind(opts)} : {}),\n ...(opts.supportsChainPair ? {supportsChainPair: opts.supportsChainPair.bind(opts)} : {}),\n ...(opts.supportsSameChain !== undefined ? {supportsSameChain: opts.supportsSameChain} : {}),\n ...(opts.claimTargets ? {claimTargets: opts.claimTargets} : {}),\n };\n}\n"],"mappings":"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","names":[]}
|
package/dist/index.cjs
CHANGED
|
@@ -54,6 +54,7 @@ __export(src_exports, {
|
|
|
54
54
|
remoteProvider: () => remoteProvider,
|
|
55
55
|
shortAddress: () => shortAddress,
|
|
56
56
|
slippageClassOf: () => slippageClassOf,
|
|
57
|
+
sourceAssetOf: () => sourceAssetOf,
|
|
57
58
|
suggestSlippage: () => suggestSlippage,
|
|
58
59
|
swap2ChainId: () => swap2ChainId,
|
|
59
60
|
validQuote: () => validQuote
|
|
@@ -158,6 +159,7 @@ function validQuote(q, params, provider) {
|
|
|
158
159
|
}
|
|
159
160
|
|
|
160
161
|
// src/util.ts
|
|
162
|
+
var import_swap2_assets = require("@anywalletkit/swap2-assets");
|
|
161
163
|
function namespace(chain) {
|
|
162
164
|
return chain.split(":")[0] ?? "";
|
|
163
165
|
}
|
|
@@ -190,6 +192,10 @@ function anySignal(signals) {
|
|
|
190
192
|
function redactUrls(text) {
|
|
191
193
|
return text.replace(/\b[a-z][a-z0-9+.-]*:\/\/[^\s"'<>]+/gi, "<url>");
|
|
192
194
|
}
|
|
195
|
+
function sourceAssetOf(params) {
|
|
196
|
+
const decimals = params.sourceDecimals;
|
|
197
|
+
return (0, import_swap2_assets.resolveAsset)(params.sourceChain, params.sourceToken, decimals === void 0 ? {} : { allowUnlisted: true, decimals });
|
|
198
|
+
}
|
|
193
199
|
|
|
194
200
|
// src/remote.ts
|
|
195
201
|
function remoteProvider(opts) {
|
|
@@ -260,7 +266,8 @@ function remoteProvider(opts) {
|
|
|
260
266
|
},
|
|
261
267
|
...opts.supportsChain ? { supportsChain: opts.supportsChain.bind(opts) } : {},
|
|
262
268
|
...opts.supportsChainPair ? { supportsChainPair: opts.supportsChainPair.bind(opts) } : {},
|
|
263
|
-
...opts.supportsSameChain !== void 0 ? { supportsSameChain: opts.supportsSameChain } : {}
|
|
269
|
+
...opts.supportsSameChain !== void 0 ? { supportsSameChain: opts.supportsSameChain } : {},
|
|
270
|
+
...opts.claimTargets ? { claimTargets: opts.claimTargets } : {}
|
|
264
271
|
};
|
|
265
272
|
}
|
|
266
273
|
|
|
@@ -268,7 +275,7 @@ function remoteProvider(opts) {
|
|
|
268
275
|
var import_core = require("@anywalletkit/core");
|
|
269
276
|
var import_viem = require("viem");
|
|
270
277
|
var import_tx_preview_evm = require("@anywalletkit/tx-preview-evm");
|
|
271
|
-
var
|
|
278
|
+
var import_swap2_assets2 = require("@anywalletkit/swap2-assets");
|
|
272
279
|
var ZERO = "0x0000000000000000000000000000000000000000";
|
|
273
280
|
var ERC20_TRANSFER_ABI = [
|
|
274
281
|
{
|
|
@@ -291,12 +298,14 @@ var inFlightKey = (fromChain, o) => JSON.stringify(
|
|
|
291
298
|
[fromChain, o.fromToken, o.toToken, o.toChain, o.recipient, o.refundAddress, o.fromTokenAmount, o.toTokenAmount, o.minAmountOut, o.slippage],
|
|
292
299
|
(_k, v) => typeof v === "bigint" ? v.toString() : v
|
|
293
300
|
);
|
|
301
|
+
var LOST_ANSWER = /socket hang up|ECONNRESET|ECONNABORTED|ETIMEDOUT|EPIPE|ENETUNREACH|EHOSTUNREACH|EAI_AGAIN|UND_ERR_[A-Z_]+|timed? ?out|TimeoutError|request aborted|AbortError|connection (?:closed|reset)|fetch failed|failed to fetch|network request failed|other side closed/i;
|
|
294
302
|
function maybeSent(error) {
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
|
|
303
|
+
const chain = [];
|
|
304
|
+
for (let e = error, i = 0; e && typeof e === "object" && i < 6; e = e.cause, i++) chain.push(e);
|
|
305
|
+
for (const e of chain) if (e.maybeSent === true) return typeof e.hash === "string" && e.hash ? { hash: e.hash } : {};
|
|
306
|
+
if (chain.some((e) => e.answered === true)) return null;
|
|
307
|
+
const texts = chain.length ? chain.map((e) => [e.message, e.code, e.name].filter((x) => typeof x === "string").join(" ")) : [String(error)];
|
|
308
|
+
return texts.some((t) => LOST_ANSWER.test(t)) ? {} : null;
|
|
300
309
|
}
|
|
301
310
|
var NATIVE_DECIMALS = Object.freeze({
|
|
302
311
|
"eip155:5042": 18
|
|
@@ -380,22 +389,24 @@ function reviewedIdentity(plan) {
|
|
|
380
389
|
return JSON.stringify(pinned, (_k, v) => typeof v === "bigint" ? v.toString() : v);
|
|
381
390
|
}
|
|
382
391
|
var SWAP2_ID_PREFIX = "awk1";
|
|
383
|
-
function encodeId(provider, intentId, sourceTxHash) {
|
|
392
|
+
function encodeId(provider, intentId, sourceTxHash, destTxHash) {
|
|
384
393
|
const enc = (v) => encodeURIComponent(v).replace(/\./g, "%2E");
|
|
385
|
-
|
|
394
|
+
const parts = [provider, intentId, ...sourceTxHash != null ? [sourceTxHash, ...destTxHash != null ? [destTxHash] : []] : []];
|
|
395
|
+
return `${SWAP2_ID_PREFIX}.${parts.map(enc).join(".")}`;
|
|
386
396
|
}
|
|
387
397
|
function decodeId(id) {
|
|
388
398
|
try {
|
|
389
399
|
if (!id.startsWith(`${SWAP2_ID_PREFIX}.`)) throw new Error("unsupported id version");
|
|
390
400
|
const parts = id.slice(SWAP2_ID_PREFIX.length + 1).split(".");
|
|
391
|
-
if (parts.length < 2 || parts.length >
|
|
401
|
+
if (parts.length < 2 || parts.length > 4 || !parts[0] || !parts[1]) throw new Error("invalid id shape");
|
|
392
402
|
const provider = decodeURIComponent(parts[0]);
|
|
393
403
|
const intentId = decodeURIComponent(parts[1]);
|
|
394
404
|
const sourceTxHash = parts[2] ? decodeURIComponent(parts[2]) : void 0;
|
|
395
|
-
|
|
405
|
+
const destTxHash = parts[3] ? decodeURIComponent(parts[3]) : void 0;
|
|
406
|
+
if (!/^[A-Za-z0-9_-]+$/.test(provider) || !intentId || parts[2] !== void 0 && !sourceTxHash || parts[3] !== void 0 && !destTxHash) {
|
|
396
407
|
throw new Error("invalid id contents");
|
|
397
408
|
}
|
|
398
|
-
return { provider, intentId, ...sourceTxHash ? { sourceTxHash } : {} };
|
|
409
|
+
return { provider, intentId, ...sourceTxHash ? { sourceTxHash } : {}, ...destTxHash ? { destTxHash } : {} };
|
|
399
410
|
} catch {
|
|
400
411
|
throw new Swap2ValidationError("swap2: malformed swap2 status id");
|
|
401
412
|
}
|
|
@@ -447,16 +458,23 @@ function toCaip2(chain, fallback) {
|
|
|
447
458
|
}
|
|
448
459
|
return swap2ChainId(chain);
|
|
449
460
|
}
|
|
461
|
+
function nonEmptyRef(ref, side) {
|
|
462
|
+
if (typeof ref !== "string" || ref.trim() === "") throw new Swap2ValidationError(`swap2: ${side} token must not be empty (pass the symbol or the contract address)`);
|
|
463
|
+
return ref;
|
|
464
|
+
}
|
|
450
465
|
function toSymbol(caip2, ref) {
|
|
451
|
-
|
|
466
|
+
nonEmptyRef(ref, "source");
|
|
467
|
+
const byToken = ref.startsWith("0x") || ref.length > 20 ? (0, import_swap2_assets2.ccAssetByToken)(caip2, ref) : void 0;
|
|
452
468
|
if (byToken) return byToken.symbol;
|
|
453
|
-
if ((0,
|
|
469
|
+
if ((0, import_swap2_assets2.ccAsset)(caip2, ref)) return ref;
|
|
454
470
|
return ref;
|
|
455
471
|
}
|
|
456
|
-
function toDestAddress(caip2, ref) {
|
|
472
|
+
function toDestAddress(caip2, ref, allowUnlisted = false) {
|
|
473
|
+
nonEmptyRef(ref, "destination");
|
|
457
474
|
if (ref.startsWith("0x")) return ref;
|
|
458
|
-
const asset = (0,
|
|
475
|
+
const asset = (0, import_swap2_assets2.ccAssetByToken)(caip2, ref) ?? (0, import_swap2_assets2.ccAsset)(caip2, ref);
|
|
459
476
|
if (!asset) {
|
|
477
|
+
if (allowUnlisted && (0, import_swap2_assets2.isTokenAddress)(caip2, ref)) return ref;
|
|
460
478
|
throw new Error(`swap2: unknown destination token '${ref}' on ${caip2}`);
|
|
461
479
|
}
|
|
462
480
|
return asset.contract ?? ZERO;
|
|
@@ -538,6 +556,15 @@ function mapStatus(s) {
|
|
|
538
556
|
const status = s.state === "completed" ? "completed" : s.state === "action-required" ? "action-required" : s.state === "refund-pending" ? "refund-pending" : s.state === "partial" ? "partial" : s.state === "failed" ? "failed" : s.state === "refunded" ? "refunded" : s.state === "cancelled" ? "cancelled" : s.state === "expired" ? "expired" : "pending";
|
|
539
557
|
return s.destTxHash ? { status, transactions: [{ hash: s.destTxHash, type: "destination" }] } : { status };
|
|
540
558
|
}
|
|
559
|
+
function blankToUndefined(v) {
|
|
560
|
+
return typeof v === "string" && v.trim() === "" ? void 0 : v;
|
|
561
|
+
}
|
|
562
|
+
function withoutBlankAddresses(o) {
|
|
563
|
+
const { recipient, refundAddress, ...rest } = o;
|
|
564
|
+
const r = blankToUndefined(recipient);
|
|
565
|
+
const f = blankToUndefined(refundAddress);
|
|
566
|
+
return { ...rest, ...r !== void 0 ? { recipient: r } : {}, ...f !== void 0 ? { refundAddress: f } : {} };
|
|
567
|
+
}
|
|
541
568
|
var BaseSwap2Protocol = class extends import_core.Swap2Protocol {
|
|
542
569
|
fromChain;
|
|
543
570
|
constructor(account, config) {
|
|
@@ -570,19 +597,61 @@ var BaseSwap2Protocol = class extends import_core.Swap2Protocol {
|
|
|
570
597
|
pairSupported(fromChain, toChain) {
|
|
571
598
|
return this.chainSupported(fromChain) && this.chainSupported(toChain);
|
|
572
599
|
}
|
|
600
|
+
unlistedAllowed() {
|
|
601
|
+
return this._config.allowUnlistedTokens === true;
|
|
602
|
+
}
|
|
603
|
+
/** The source asset the options name: the catalog's, or (allowUnlistedTokens) an unlisted one with its decimals. */
|
|
604
|
+
sourceAsset(options) {
|
|
605
|
+
const decimals = options.fromTokenDecimals;
|
|
606
|
+
return (0, import_swap2_assets2.resolveAsset)(this.fromChain, toSymbol(this.fromChain, options.fromToken), {
|
|
607
|
+
allowUnlisted: this.unlistedAllowed(),
|
|
608
|
+
...decimals !== void 0 ? { decimals } : {}
|
|
609
|
+
});
|
|
610
|
+
}
|
|
611
|
+
unlistedDecimals = /* @__PURE__ */ new Map();
|
|
612
|
+
/**
|
|
613
|
+
* Options ready to quote: with `allowUnlistedTokens`, an unlisted source token gets its decimals,
|
|
614
|
+
* read from the chain through the account (cached per token) — a caller's `fromTokenDecimals` that
|
|
615
|
+
* disagrees is refused. Listed tokens and every option otherwise pass through unchanged.
|
|
616
|
+
*/
|
|
617
|
+
async prepareOptions(options) {
|
|
618
|
+
if (!this.unlistedAllowed()) return options;
|
|
619
|
+
const ref = toSymbol(this.fromChain, options.fromToken);
|
|
620
|
+
if ((0, import_swap2_assets2.resolveAsset)(this.fromChain, ref) || !(0, import_swap2_assets2.isTokenAddress)(this.fromChain, ref)) return options;
|
|
621
|
+
const key = ref.startsWith("0x") ? ref.toLowerCase() : ref;
|
|
622
|
+
let decimals = this.unlistedDecimals.get(key);
|
|
623
|
+
if (decimals === void 0) {
|
|
624
|
+
const reader = this._account;
|
|
625
|
+
if (typeof reader?.getTokenInfo !== "function") {
|
|
626
|
+
if (options.fromTokenDecimals === void 0) {
|
|
627
|
+
throw new Swap2ValidationError(`swap2: '${ref}' is not in the catalog \u2014 pass fromTokenDecimals, or use an account that can read token info`);
|
|
628
|
+
}
|
|
629
|
+
return options;
|
|
630
|
+
}
|
|
631
|
+
decimals = (await reader.getTokenInfo(ref)).decimals;
|
|
632
|
+
this.unlistedDecimals.set(key, decimals);
|
|
633
|
+
}
|
|
634
|
+
if (options.fromTokenDecimals !== void 0 && options.fromTokenDecimals !== decimals) {
|
|
635
|
+
throw new Swap2ValidationError(`swap2: fromTokenDecimals ${options.fromTokenDecimals} does not match the token's ${decimals}`);
|
|
636
|
+
}
|
|
637
|
+
return snapshotOptions({ ...options, fromTokenDecimals: decimals });
|
|
638
|
+
}
|
|
573
639
|
/** Swap2Options → the engine's QuoteParams (exact-in only). */
|
|
574
|
-
toParams(
|
|
640
|
+
toParams(given, dry) {
|
|
641
|
+
const options = withoutBlankAddresses(given);
|
|
575
642
|
if (options.fromTokenAmount == null) {
|
|
576
643
|
throw new Swap2UnsupportedOperationError("swap2: exact-out swap2 is not supported by the engine");
|
|
577
644
|
}
|
|
578
645
|
const destChain = toCaip2(options.toChain, this.fromChain);
|
|
579
646
|
const constraints = callerConstraints(options);
|
|
580
647
|
const amountIn = exactPositiveAmount(options.fromTokenAmount, "fromTokenAmount");
|
|
648
|
+
const source = this.sourceAsset(options);
|
|
581
649
|
const params = {
|
|
582
650
|
sourceChain: this.fromChain,
|
|
583
|
-
sourceToken: toSymbol(this.fromChain, options.fromToken),
|
|
651
|
+
sourceToken: (0, import_swap2_assets2.isUnlisted)(source) ? source.contract : toSymbol(this.fromChain, options.fromToken),
|
|
652
|
+
...(0, import_swap2_assets2.isUnlisted)(source) ? { sourceDecimals: source.decimals } : {},
|
|
584
653
|
destChain,
|
|
585
|
-
destToken: toDestAddress(destChain, options.toToken),
|
|
654
|
+
destToken: toDestAddress(destChain, options.toToken, this.unlistedAllowed()),
|
|
586
655
|
amountIn: amountIn.toString(),
|
|
587
656
|
destAddress: options.recipient ?? "",
|
|
588
657
|
dry,
|
|
@@ -638,7 +707,7 @@ var BaseSwap2Protocol = class extends import_core.Swap2Protocol {
|
|
|
638
707
|
}
|
|
639
708
|
}
|
|
640
709
|
assertQuoteFeeCaps(q, options, config) {
|
|
641
|
-
const source =
|
|
710
|
+
const source = this.sourceAsset(options);
|
|
642
711
|
if (!source) throw new Error(`swap2: unknown source token '${options.fromToken}' on ${this.fromChain}`);
|
|
643
712
|
const token = source.contract ?? source.assetId;
|
|
644
713
|
const fees = q.fees?.map((fee) => ({ ...fee, amount: BigInt(fee.amount) }));
|
|
@@ -683,7 +752,7 @@ var BaseSwap2Protocol = class extends import_core.Swap2Protocol {
|
|
|
683
752
|
* gave one.
|
|
684
753
|
*/
|
|
685
754
|
async quoteSwap2(options) {
|
|
686
|
-
const snapshot = snapshotOptions(options);
|
|
755
|
+
const snapshot = await this.prepareOptions(snapshotOptions(options));
|
|
687
756
|
const q = await this.resolveQuote(this.toParams(snapshot, true));
|
|
688
757
|
if (!q) {
|
|
689
758
|
const detail = this.noRouteDetail();
|
|
@@ -725,9 +794,9 @@ var BaseSwap2Protocol = class extends import_core.Swap2Protocol {
|
|
|
725
794
|
this.assertFeeConfig(configSnapshot);
|
|
726
795
|
await this.assertAccountChain(signer);
|
|
727
796
|
const selfAddress = await signer.getAddress();
|
|
728
|
-
const recipient = snapshot.recipient ?? selfAddress;
|
|
729
|
-
const refundAddress = snapshot.refundAddress ?? selfAddress;
|
|
730
|
-
const executionOptions = snapshotOptions({ ...snapshot, recipient, refundAddress });
|
|
797
|
+
const recipient = blankToUndefined(snapshot.recipient) ?? selfAddress;
|
|
798
|
+
const refundAddress = blankToUndefined(snapshot.refundAddress) ?? selfAddress;
|
|
799
|
+
const executionOptions = await this.prepareOptions(snapshotOptions({ ...snapshot, recipient, refundAddress }));
|
|
731
800
|
const params = this.toParams(executionOptions, false);
|
|
732
801
|
const resolved = await this.resolveQuote(params);
|
|
733
802
|
if (!resolved) {
|
|
@@ -769,7 +838,7 @@ var BaseSwap2Protocol = class extends import_core.Swap2Protocol {
|
|
|
769
838
|
throw new Error("swap2: provider build does not match the validated quote transaction");
|
|
770
839
|
}
|
|
771
840
|
} else if (!unsigned.bodyBoc && !unsigned.typedData) {
|
|
772
|
-
if (!q.depositAddress || unsigned.to !== q.depositAddress || (unsigned.memo ?? null) !== q.depositMemo) {
|
|
841
|
+
if (!q.depositAddress || unsigned.to !== q.depositAddress || (unsigned.memo ?? null) !== q.depositMemo || unsigned.data !== void 0 || unsigned.approvalAddress !== void 0 || unsigned.serializedTx !== void 0) {
|
|
773
842
|
throw new Error("swap2: provider build does not match the validated quote deposit");
|
|
774
843
|
}
|
|
775
844
|
}
|
|
@@ -808,7 +877,7 @@ var BaseSwap2Protocol = class extends import_core.Swap2Protocol {
|
|
|
808
877
|
}
|
|
809
878
|
let tokenId;
|
|
810
879
|
if (!unsigned.data && !unsigned.bodyBoc && !unsigned.typedData && !serialized) {
|
|
811
|
-
const src =
|
|
880
|
+
const src = this.sourceAsset(executionOptions);
|
|
812
881
|
if (src?.contract) {
|
|
813
882
|
if (this.fromChain.startsWith("eip155:")) {
|
|
814
883
|
unsigned = {
|
|
@@ -834,7 +903,7 @@ var BaseSwap2Protocol = class extends import_core.Swap2Protocol {
|
|
|
834
903
|
if (tokenId && (cellBody !== void 0 || unsigned.memo !== void 0 && !tronSource && !nearSource && !tonSource)) {
|
|
835
904
|
throw new Error("swap2: token deposit with memo/cell payload is not implemented");
|
|
836
905
|
}
|
|
837
|
-
const source =
|
|
906
|
+
const source = this.sourceAsset(executionOptions);
|
|
838
907
|
if (!source) throw new Error(`swap2: unknown source token '${executionOptions.fromToken}' on ${this.fromChain}`);
|
|
839
908
|
const executionValue = BigInt(unsigned.value);
|
|
840
909
|
if (serialized) {
|
|
@@ -1124,10 +1193,10 @@ var BaseSwap2Protocol = class extends import_core.Swap2Protocol {
|
|
|
1124
1193
|
}
|
|
1125
1194
|
/** Status of a swap by the id `swap2()` returned, asked from the provider that executed it. */
|
|
1126
1195
|
async getSwap2Status(id, _options) {
|
|
1127
|
-
const { provider: name, intentId, sourceTxHash } = decodeId(id);
|
|
1196
|
+
const { provider: name, intentId, sourceTxHash, destTxHash } = decodeId(id);
|
|
1128
1197
|
const provider = this.providerFor(name);
|
|
1129
1198
|
if (!provider) throw new Error(`swap2: no swap2 found for id '${id}'`);
|
|
1130
|
-
return mapStatus(await provider.trackIntent(sourceTxHash
|
|
1199
|
+
return mapStatus(await provider.trackIntent({ intentId, ...sourceTxHash != null ? { sourceTxHash } : {}, ...destTxHash != null ? { destTxHash } : {} }));
|
|
1131
1200
|
}
|
|
1132
1201
|
/**
|
|
1133
1202
|
* Two-phase routes (CCTP-style burn-and-mint): once `getSwap2Status` reports
|
|
@@ -1173,6 +1242,17 @@ var BaseSwap2Protocol = class extends import_core.Swap2Protocol {
|
|
|
1173
1242
|
if (unsigned.chainId !== void 0 && String(unsigned.chainId) !== expectedId) {
|
|
1174
1243
|
throw new Error(`swap2: claim chainId ${unsigned.chainId} does not match ${unsigned.chain}`);
|
|
1175
1244
|
}
|
|
1245
|
+
if (typeof provider.claimTargets !== "function") {
|
|
1246
|
+
throw new Swap2UnsupportedOperationError(`swap2: provider '${name}' declares no claimTargets \u2014 a claim may only call contracts the provider names for its chain`);
|
|
1247
|
+
}
|
|
1248
|
+
const targets = provider.claimTargets(unsigned.chain).map((a) => a.toLowerCase());
|
|
1249
|
+
if (!targets.includes(unsigned.to.toLowerCase())) {
|
|
1250
|
+
throw new Swap2ValidationError(`swap2: claim target ${unsigned.to} is not a contract '${name}' declares for ${unsigned.chain} \u2014 refused`);
|
|
1251
|
+
}
|
|
1252
|
+
const claimCall = (0, import_tx_preview_evm.decodeCall)({ to: unsigned.to, data: unsigned.data, value: 0n });
|
|
1253
|
+
if (claimCall.transfer || claimCall.approval) {
|
|
1254
|
+
throw new Swap2ValidationError(`swap2: claim calldata (${claimCall.method}) moves tokens or grants an allowance \u2014 refused`);
|
|
1255
|
+
}
|
|
1176
1256
|
const actual = await readAccountChain(signer);
|
|
1177
1257
|
if (actual == null) throw new Error(`swap2: destination account chain identity is unavailable for ${unsigned.chain}`);
|
|
1178
1258
|
const actualText = typeof actual === "string" ? actual : String(actual);
|
|
@@ -1188,7 +1268,7 @@ var BaseSwap2Protocol = class extends import_core.Swap2Protocol {
|
|
|
1188
1268
|
});
|
|
1189
1269
|
if (!sent.hash) throw new Swap2ExecutionError("swap2: account did not return a claim transaction hash");
|
|
1190
1270
|
this.emitPhase("broadcast", { hash: sent.hash });
|
|
1191
|
-
return { hash: sent.hash, chain: unsigned.chain, id };
|
|
1271
|
+
return { hash: sent.hash, chain: unsigned.chain, id: encodeId(name, intentId, sourceTxHash, sent.hash) };
|
|
1192
1272
|
}
|
|
1193
1273
|
/** The inherited bridge() has no floor field: quote first, then bind execution
|
|
1194
1274
|
* to that quote's minimum so the inherited convenience API stays safe. */
|
|
@@ -1230,7 +1310,7 @@ var BaseSwap2Protocol = class extends import_core.Swap2Protocol {
|
|
|
1230
1310
|
/** Source chains this protocol can swap from. */
|
|
1231
1311
|
async getSupportedChains() {
|
|
1232
1312
|
if (!this.protocolEnabled()) return [];
|
|
1233
|
-
return
|
|
1313
|
+
return import_swap2_assets2.CC_SOURCE_CHAINS.filter((c) => this.chainSupported(c.caip2)).map((c) => ({
|
|
1234
1314
|
id: c.caip2,
|
|
1235
1315
|
name: c.label,
|
|
1236
1316
|
type: chainType(c.caip2),
|
|
@@ -1243,12 +1323,14 @@ var BaseSwap2Protocol = class extends import_core.Swap2Protocol {
|
|
|
1243
1323
|
const wantTo = options?.toChain != null ? toCaip2(options.toChain, "") : void 0;
|
|
1244
1324
|
if (!this.protocolEnabled() || wantFrom && wantTo && !this.pairSupported(wantFrom, wantTo)) return [];
|
|
1245
1325
|
const out = [];
|
|
1246
|
-
for (const c of
|
|
1326
|
+
for (const c of import_swap2_assets2.CC_SOURCE_CHAINS) {
|
|
1247
1327
|
if (!this.chainSupported(c.caip2)) continue;
|
|
1248
1328
|
if ((wantFrom || wantTo) && c.caip2 !== wantFrom && c.caip2 !== wantTo) continue;
|
|
1249
1329
|
for (const a of c.assets) {
|
|
1250
1330
|
out.push({
|
|
1251
|
-
|
|
1331
|
+
// What quoteSwap2 takes back: the contract, or the symbol of the native coin — never the
|
|
1332
|
+
// provider-specific assetId, which is "" for most catalog entries (round 3, M25).
|
|
1333
|
+
token: a.contract ?? a.symbol,
|
|
1252
1334
|
chain: c.caip2,
|
|
1253
1335
|
symbol: a.symbol,
|
|
1254
1336
|
decimals: a.decimals,
|
|
@@ -1330,7 +1412,7 @@ var SingleProviderSwap2 = class extends BaseSwap2Protocol {
|
|
|
1330
1412
|
|
|
1331
1413
|
// src/activity.ts
|
|
1332
1414
|
var import_core2 = require("@anywalletkit/core");
|
|
1333
|
-
var
|
|
1415
|
+
var import_swap2_assets3 = require("@anywalletkit/swap2-assets");
|
|
1334
1416
|
function calledContract(tx) {
|
|
1335
1417
|
const to = tx.call?.to ?? tx.to;
|
|
1336
1418
|
if (!to) return null;
|
|
@@ -1367,7 +1449,7 @@ function matchesCall(tx, contracts, selectors) {
|
|
|
1367
1449
|
return sel !== void 0 && want.has(sel);
|
|
1368
1450
|
}
|
|
1369
1451
|
function chainLabel(caip2) {
|
|
1370
|
-
return (0,
|
|
1452
|
+
return (0, import_swap2_assets3.ccChain)(caip2)?.label ?? caip2;
|
|
1371
1453
|
}
|
|
1372
1454
|
function shortAddress(a) {
|
|
1373
1455
|
return a.length > 14 ? `${a.slice(0, 6)}\u2026${a.slice(-4)}` : a;
|
|
@@ -1386,7 +1468,7 @@ function assetMetaFor(tx) {
|
|
|
1386
1468
|
const key = token === null ? null : token.startsWith("0x") ? token.toLowerCase() : token;
|
|
1387
1469
|
const known = fromTransfers.get(key);
|
|
1388
1470
|
if (known?.symbol !== void 0 && known.decimals !== void 0) return known;
|
|
1389
|
-
const cat = (0,
|
|
1471
|
+
const cat = (0, import_swap2_assets3.ccAssetByToken)(tx.chain, token ?? "");
|
|
1390
1472
|
if (!cat) return known;
|
|
1391
1473
|
const meta = { symbol: known?.symbol ?? cat.symbol, decimals: known?.decimals ?? cat.decimals };
|
|
1392
1474
|
return meta;
|
|
@@ -1394,7 +1476,7 @@ function assetMetaFor(tx) {
|
|
|
1394
1476
|
}
|
|
1395
1477
|
function assetLabel(tx, a) {
|
|
1396
1478
|
if (a.symbol) return a.symbol;
|
|
1397
|
-
if (a.token === null) return (0,
|
|
1479
|
+
if (a.token === null) return (0, import_swap2_assets3.ccAssetByToken)(tx.chain, "")?.symbol ?? "native";
|
|
1398
1480
|
return shortAddress(a.token);
|
|
1399
1481
|
}
|
|
1400
1482
|
function ownerAssets(tx, ctx) {
|