@anywalletkit/protocol-swap2-core 0.5.0 → 0.6.1
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 +1 -1
- package/dist/{chunk-IC3MZIMB.js → chunk-IGTMUTNJ.js} +39 -16
- package/dist/chunk-IGTMUTNJ.js.map +1 -0
- package/dist/{chunk-OWO27YBK.js → chunk-JFGMF6FO.js} +2 -2
- package/dist/{chunk-3Y6HV2OL.js → chunk-ZMWK3RQ4.js} +3 -2
- package/dist/chunk-ZMWK3RQ4.js.map +1 -0
- package/dist/index.cjs +40 -16
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +3 -3
- package/dist/remote.cjs +2 -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 +1 -1
- package/dist/swap2/base.cjs +38 -15
- package/dist/swap2/base.cjs.map +1 -1
- package/dist/swap2/base.js +1 -1
- package/dist/swap2/single.cjs +38 -15
- package/dist/swap2/single.cjs.map +1 -1
- package/dist/swap2/single.js +2 -2
- package/dist/types.cjs.map +1 -1
- package/dist/types.d.cts +7 -0
- package/dist/types.d.ts +7 -0
- package/package.json +10 -8
- package/dist/chunk-3Y6HV2OL.js.map +0 -1
- package/dist/chunk-IC3MZIMB.js.map +0 -1
- /package/dist/{chunk-OWO27YBK.js.map → chunk-JFGMF6FO.js.map} +0 -0
package/dist/index.d.cts
CHANGED
|
@@ -3,7 +3,7 @@ export { Swap2ConfigurationError, Swap2Error, Swap2ErrorCode, Swap2ExecutionErro
|
|
|
3
3
|
export { validQuote } from './validate.cjs';
|
|
4
4
|
export { RemoteProviderOptions, remoteProvider } from './remote.cjs';
|
|
5
5
|
export { evmRef, isEvm, namespace, redactUrls, sourceAssetOf } from './util.cjs';
|
|
6
|
-
export { BaseSwap2Protocol, NATIVE_DECIMALS, SWAP2_CHAIN_ALIASES, SWAP2_ID_PREFIX, SerializedExecutionExpectation, Swap2Account, Swap2EngineConfig, Swap2ExecutionPlan, nativeDecimals, nativeUnits, swap2ChainId } from './swap2/base.cjs';
|
|
6
|
+
export { BaseSwap2Protocol, NATIVE_DECIMALS, SWAP2_CHAIN_ALIASES, SWAP2_ID_PREFIX, SerializedExecutionExpectation, Swap2Account, Swap2EngineConfig, Swap2ExecutionPhase, Swap2ExecutionPhaseDetail, Swap2ExecutionPlan, nativeDecimals, nativeUnits, swap2ChainId } from './swap2/base.cjs';
|
|
7
7
|
export { SingleProviderSwap2 } from './swap2/single.cjs';
|
|
8
8
|
export { SwapActivityOptions, assetLabel, assetMetaFor, callSelector, calledContract, callsContract, chainLabel, describeSwapLike, matchesCall, ownerAssets, shortAddress } from './activity.cjs';
|
|
9
9
|
export { SlippageClass, SlippageContext, SlippageOptions, SlippageSuggestion, slippageClassOf, suggestSlippage } from './slippage.cjs';
|
package/dist/index.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ export { Swap2ConfigurationError, Swap2Error, Swap2ErrorCode, Swap2ExecutionErro
|
|
|
3
3
|
export { validQuote } from './validate.js';
|
|
4
4
|
export { RemoteProviderOptions, remoteProvider } from './remote.js';
|
|
5
5
|
export { evmRef, isEvm, namespace, redactUrls, sourceAssetOf } from './util.js';
|
|
6
|
-
export { BaseSwap2Protocol, NATIVE_DECIMALS, SWAP2_CHAIN_ALIASES, SWAP2_ID_PREFIX, SerializedExecutionExpectation, Swap2Account, Swap2EngineConfig, Swap2ExecutionPlan, nativeDecimals, nativeUnits, swap2ChainId } from './swap2/base.js';
|
|
6
|
+
export { BaseSwap2Protocol, NATIVE_DECIMALS, SWAP2_CHAIN_ALIASES, SWAP2_ID_PREFIX, SerializedExecutionExpectation, Swap2Account, Swap2EngineConfig, Swap2ExecutionPhase, Swap2ExecutionPhaseDetail, Swap2ExecutionPlan, nativeDecimals, nativeUnits, swap2ChainId } from './swap2/base.js';
|
|
7
7
|
export { SingleProviderSwap2 } from './swap2/single.js';
|
|
8
8
|
export { SwapActivityOptions, assetLabel, assetMetaFor, callSelector, calledContract, callsContract, chainLabel, describeSwapLike, matchesCall, ownerAssets, shortAddress } from './activity.js';
|
|
9
9
|
export { SlippageClass, SlippageContext, SlippageOptions, SlippageSuggestion, slippageClassOf, suggestSlippage } from './slippage.js';
|
package/dist/index.js
CHANGED
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
} from "./chunk-J4WXUNK2.js";
|
|
13
13
|
import {
|
|
14
14
|
SingleProviderSwap2
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-JFGMF6FO.js";
|
|
16
16
|
import {
|
|
17
17
|
BaseSwap2Protocol,
|
|
18
18
|
NATIVE_DECIMALS,
|
|
@@ -21,7 +21,7 @@ import {
|
|
|
21
21
|
nativeDecimals,
|
|
22
22
|
nativeUnits,
|
|
23
23
|
swap2ChainId
|
|
24
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-IGTMUTNJ.js";
|
|
25
25
|
import "./chunk-55J6XMHW.js";
|
|
26
26
|
import {
|
|
27
27
|
Swap2ConfigurationError,
|
|
@@ -45,7 +45,7 @@ import {
|
|
|
45
45
|
} from "./chunk-VNVBGY7U.js";
|
|
46
46
|
import {
|
|
47
47
|
remoteProvider
|
|
48
|
-
} from "./chunk-
|
|
48
|
+
} from "./chunk-ZMWK3RQ4.js";
|
|
49
49
|
import {
|
|
50
50
|
evmRef,
|
|
51
51
|
isEvm,
|
package/dist/remote.cjs
CHANGED
|
@@ -116,7 +116,8 @@ function remoteProvider(opts) {
|
|
|
116
116
|
},
|
|
117
117
|
...opts.supportsChain ? { supportsChain: opts.supportsChain.bind(opts) } : {},
|
|
118
118
|
...opts.supportsChainPair ? { supportsChainPair: opts.supportsChainPair.bind(opts) } : {},
|
|
119
|
-
...opts.supportsSameChain !== void 0 ? { supportsSameChain: opts.supportsSameChain } : {}
|
|
119
|
+
...opts.supportsSameChain !== void 0 ? { supportsSameChain: opts.supportsSameChain } : {},
|
|
120
|
+
...opts.claimTargets ? { claimTargets: opts.claimTargets } : {}
|
|
120
121
|
};
|
|
121
122
|
}
|
|
122
123
|
//# sourceMappingURL=remote.cjs.map
|
package/dist/remote.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/remote.ts","../src/util.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 /** 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 };\n}\n","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;AAAA;AAAA;AAAA;AAAA;;;ACAA,0BAAyC;AAqBlC,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;;;ADUO,SAAS,eAAe,MAAiD;AAC9E,QAAM,OAAO,KAAK;AAClB,MAAI,CAAC,mBAAmB,KAAK,IAAI,EAAG,OAAM,IAAI,MAAM,qCAAqC;AACzF,QAAM,UAAU,KAAK,QAAQ,QAAQ,QAAQ,EAAE;AAC/C,MAAI,CAAC,QAAS,OAAM,IAAI,MAAM,mCAAmC;AACjE,QAAM,gBAAgB,KAAK;AAC3B,QAAM,UAAU,KAAK;AACrB,QAAM,UAAU,OAAO,OAAO,EAAC,GAAG,KAAK,QAAO,CAAC;AAC/C,QAAM,UAAU,KAAK,aAAa;AAClC,QAAM,YAAY,KAAK,aAAa;AACpC,MAAI,CAAC,OAAO,UAAU,SAAS,KAAK,aAAa,KAAK,YAAY,KAAQ;AACxE,UAAM,IAAI,MAAM,gEAAgE;AAAA,EAClF;AAEA,iBAAe,KAAQ,QAAgB,MAA+B,QAAkC;AACtG,UAAM,UAAU,cAAc,SAAS;AACvC,UAAM,gBAAgB,SAAS,UAAU,CAAC,QAAQ,OAAO,CAAC,IAAI;AAC9D,UAAM,MAAM,MAAM,QAAQ,GAAG,OAAO,IAAI,MAAM,IAAI;AAAA,MAChD,QAAQ;AAAA,MACR,SAAS,EAAC,GAAG,SAAS,gBAAgB,mBAAkB;AAAA;AAAA;AAAA;AAAA,MAIxD,MAAM,KAAK,UAAU,EAAC,UAAU,MAAM,GAAG,KAAI,GAAG,CAAC,IAAI,MAAO,OAAO,MAAM,WAAW,EAAE,SAAS,IAAI,CAAE;AAAA,MACrG,QAAQ;AAAA,IACV,CAAC;AACD,QAAI,CAAC,IAAI,IAAI;AAGX,YAAM,OAAO,MAAM,IAAI,KAAK,EAAE,MAAM,MAAM,EAAE;AAC5C,YAAM,IAAI,MAAM,gBAAgB,IAAI,IAAI,MAAM,KAAK,IAAI,MAAM,IAAI,KAAK,MAAM,GAAG,GAAG,CAAC,EAAE;AAAA,IACvF;AACA,WAAQ,MAAM,IAAI,KAAK;AAAA,EACzB;AAEA,SAAO;AAAA,IACL;AAAA;AAAA;AAAA,IAGA,SAAS,MAAM,UAAU,QAAQ,IAAI;AAAA,IACrC,cAAc,MAAa,IAAoB;AAC7C,aAAO,gBAAgB,cAAc,MAAM,EAAE,IAAI;AAAA,IACnD;AAAA,IACA,MAAM,SAAS,QAAqB,QAA6C;AAC/E,YAAM,MAAM,MAAM,KAAuC,SAAS,EAAC,OAAM,GAAG,MAAM;AAClF,UAAI,OAAO,OAAO,QAAQ,YAAY,aAAa,KAAK;AAGtD,cAAM,IAAI,MAAM,OAAQ,IAA2B,OAAO,EAAE,MAAM,GAAG,GAAG,CAAC;AAAA,MAC3E;AACA,aAAO;AAAA,IACT;AAAA,IACA,MAAM,aAAa,OAAmC;AACpD,aAAO,KAAiB,SAAS,EAAC,MAAK,CAAC;AAAA,IAC1C;AAAA,IACA,MAAM,iBAAiB,OAAc,IAA+B;AAClE,YAAM,KAA4B,aAAa,EAAC,OAAO,GAAE,CAAC;AAAA,IAC5D;AAAA,IACA,MAAM,YAAY,KAAuC;AACvD,aAAO,KAAmB,SAAS,EAAC,IAAG,CAAC;AAAA,IAC1C;AAAA,IACA,MAAM,cAAc,UAAkB,QAA+B;AACnE,YAAM,KAA4B,UAAU,EAAC,UAAU,OAAM,CAAC;AAAA,IAChE;AAAA,IACA,MAAM,oBAAoB,UAAkB,WAAkC;AAC5E,YAAM,KAA4B,YAAY,EAAC,UAAU,UAAS,CAAC;AAAA,IACrE;AAAA,IACA,MAAM,WAAW,KAA4C;AAC3D,YAAM,MAAM,MAAM,KAAgD,SAAS,EAAC,IAAG,CAAC;AAEhF,UAAI,CAAC,OAAO,OAAO,QAAQ,YAAY,EAAE,QAAQ,KAAM,QAAO;AAC9D,aAAO;AAAA,IACT;AAAA,IACA,GAAI,KAAK,gBAAgB,EAAC,eAAe,KAAK,cAAc,KAAK,IAAI,EAAC,IAAI,CAAC;AAAA,IAC3E,GAAI,KAAK,oBAAoB,EAAC,mBAAmB,KAAK,kBAAkB,KAAK,IAAI,EAAC,IAAI,CAAC;AAAA,IACvF,GAAI,KAAK,sBAAsB,SAAY,EAAC,mBAAmB,KAAK,kBAAiB,IAAI,CAAC;AAAA,EAC5F;AACF;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/remote.ts","../src/util.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","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":"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","names":[]}
|
package/dist/remote.d.cts
CHANGED
|
@@ -37,6 +37,12 @@ interface RemoteProviderOptions {
|
|
|
37
37
|
supportsChainPair?: (fromChain: string, toChain: string) => boolean;
|
|
38
38
|
/** Explicit opt-in when the backend can execute same-chain swaps. */
|
|
39
39
|
supportsSameChain?: boolean;
|
|
40
|
+
/**
|
|
41
|
+
* The contracts this provider's claims may call, per chain (e.g. `cctpClaimTargets` from
|
|
42
|
+
* `@anywalletkit/protocol-swap2-cctp`). The app's list, not the server's: without it the engine
|
|
43
|
+
* refuses claims from this stub (round 3, M24).
|
|
44
|
+
*/
|
|
45
|
+
claimTargets?: (chain: string) => readonly string[];
|
|
40
46
|
/** Defaults to globalThis.fetch — injectable for tests. */
|
|
41
47
|
fetchImpl?: typeof fetch;
|
|
42
48
|
/** Extra headers (e.g. auth) attached to every call. */
|
package/dist/remote.d.ts
CHANGED
|
@@ -37,6 +37,12 @@ interface RemoteProviderOptions {
|
|
|
37
37
|
supportsChainPair?: (fromChain: string, toChain: string) => boolean;
|
|
38
38
|
/** Explicit opt-in when the backend can execute same-chain swaps. */
|
|
39
39
|
supportsSameChain?: boolean;
|
|
40
|
+
/**
|
|
41
|
+
* The contracts this provider's claims may call, per chain (e.g. `cctpClaimTargets` from
|
|
42
|
+
* `@anywalletkit/protocol-swap2-cctp`). The app's list, not the server's: without it the engine
|
|
43
|
+
* refuses claims from this stub (round 3, M24).
|
|
44
|
+
*/
|
|
45
|
+
claimTargets?: (chain: string) => readonly string[];
|
|
40
46
|
/** Defaults to globalThis.fetch — injectable for tests. */
|
|
41
47
|
fetchImpl?: typeof fetch;
|
|
42
48
|
/** Extra headers (e.g. auth) attached to every call. */
|
package/dist/remote.js
CHANGED
package/dist/swap2/base.cjs
CHANGED
|
@@ -116,12 +116,14 @@ var inFlightKey = (fromChain, o) => JSON.stringify(
|
|
|
116
116
|
[fromChain, o.fromToken, o.toToken, o.toChain, o.recipient, o.refundAddress, o.fromTokenAmount, o.toTokenAmount, o.minAmountOut, o.slippage],
|
|
117
117
|
(_k, v) => typeof v === "bigint" ? v.toString() : v
|
|
118
118
|
);
|
|
119
|
+
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;
|
|
119
120
|
function maybeSent(error) {
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
|
|
121
|
+
const chain = [];
|
|
122
|
+
for (let e = error, i = 0; e && typeof e === "object" && i < 6; e = e.cause, i++) chain.push(e);
|
|
123
|
+
for (const e of chain) if (e.maybeSent === true) return typeof e.hash === "string" && e.hash ? { hash: e.hash } : {};
|
|
124
|
+
if (chain.some((e) => e.answered === true)) return null;
|
|
125
|
+
const texts = chain.length ? chain.map((e) => [e.message, e.code, e.name].filter((x) => typeof x === "string").join(" ")) : [String(error)];
|
|
126
|
+
return texts.some((t) => LOST_ANSWER.test(t)) ? {} : null;
|
|
125
127
|
}
|
|
126
128
|
var NATIVE_DECIMALS = Object.freeze({
|
|
127
129
|
"eip155:5042": 18
|
|
@@ -205,22 +207,24 @@ function reviewedIdentity(plan) {
|
|
|
205
207
|
return JSON.stringify(pinned, (_k, v) => typeof v === "bigint" ? v.toString() : v);
|
|
206
208
|
}
|
|
207
209
|
var SWAP2_ID_PREFIX = "awk1";
|
|
208
|
-
function encodeId(provider, intentId, sourceTxHash) {
|
|
210
|
+
function encodeId(provider, intentId, sourceTxHash, destTxHash) {
|
|
209
211
|
const enc = (v) => encodeURIComponent(v).replace(/\./g, "%2E");
|
|
210
|
-
|
|
212
|
+
const parts = [provider, intentId, ...sourceTxHash != null ? [sourceTxHash, ...destTxHash != null ? [destTxHash] : []] : []];
|
|
213
|
+
return `${SWAP2_ID_PREFIX}.${parts.map(enc).join(".")}`;
|
|
211
214
|
}
|
|
212
215
|
function decodeId(id) {
|
|
213
216
|
try {
|
|
214
217
|
if (!id.startsWith(`${SWAP2_ID_PREFIX}.`)) throw new Error("unsupported id version");
|
|
215
218
|
const parts = id.slice(SWAP2_ID_PREFIX.length + 1).split(".");
|
|
216
|
-
if (parts.length < 2 || parts.length >
|
|
219
|
+
if (parts.length < 2 || parts.length > 4 || !parts[0] || !parts[1]) throw new Error("invalid id shape");
|
|
217
220
|
const provider = decodeURIComponent(parts[0]);
|
|
218
221
|
const intentId = decodeURIComponent(parts[1]);
|
|
219
222
|
const sourceTxHash = parts[2] ? decodeURIComponent(parts[2]) : void 0;
|
|
220
|
-
|
|
223
|
+
const destTxHash = parts[3] ? decodeURIComponent(parts[3]) : void 0;
|
|
224
|
+
if (!/^[A-Za-z0-9_-]+$/.test(provider) || !intentId || parts[2] !== void 0 && !sourceTxHash || parts[3] !== void 0 && !destTxHash) {
|
|
221
225
|
throw new Error("invalid id contents");
|
|
222
226
|
}
|
|
223
|
-
return { provider, intentId, ...sourceTxHash ? { sourceTxHash } : {} };
|
|
227
|
+
return { provider, intentId, ...sourceTxHash ? { sourceTxHash } : {}, ...destTxHash ? { destTxHash } : {} };
|
|
224
228
|
} catch {
|
|
225
229
|
throw new Swap2ValidationError("swap2: malformed swap2 status id");
|
|
226
230
|
}
|
|
@@ -272,13 +276,19 @@ function toCaip2(chain, fallback) {
|
|
|
272
276
|
}
|
|
273
277
|
return swap2ChainId(chain);
|
|
274
278
|
}
|
|
279
|
+
function nonEmptyRef(ref, side) {
|
|
280
|
+
if (typeof ref !== "string" || ref.trim() === "") throw new Swap2ValidationError(`swap2: ${side} token must not be empty (pass the symbol or the contract address)`);
|
|
281
|
+
return ref;
|
|
282
|
+
}
|
|
275
283
|
function toSymbol(caip2, ref) {
|
|
284
|
+
nonEmptyRef(ref, "source");
|
|
276
285
|
const byToken = ref.startsWith("0x") || ref.length > 20 ? (0, import_swap2_assets.ccAssetByToken)(caip2, ref) : void 0;
|
|
277
286
|
if (byToken) return byToken.symbol;
|
|
278
287
|
if ((0, import_swap2_assets.ccAsset)(caip2, ref)) return ref;
|
|
279
288
|
return ref;
|
|
280
289
|
}
|
|
281
290
|
function toDestAddress(caip2, ref, allowUnlisted = false) {
|
|
291
|
+
nonEmptyRef(ref, "destination");
|
|
282
292
|
if (ref.startsWith("0x")) return ref;
|
|
283
293
|
const asset = (0, import_swap2_assets.ccAssetByToken)(caip2, ref) ?? (0, import_swap2_assets.ccAsset)(caip2, ref);
|
|
284
294
|
if (!asset) {
|
|
@@ -646,7 +656,7 @@ var BaseSwap2Protocol = class extends import_core.Swap2Protocol {
|
|
|
646
656
|
throw new Error("swap2: provider build does not match the validated quote transaction");
|
|
647
657
|
}
|
|
648
658
|
} else if (!unsigned.bodyBoc && !unsigned.typedData) {
|
|
649
|
-
if (!q.depositAddress || unsigned.to !== q.depositAddress || (unsigned.memo ?? null) !== q.depositMemo) {
|
|
659
|
+
if (!q.depositAddress || unsigned.to !== q.depositAddress || (unsigned.memo ?? null) !== q.depositMemo || unsigned.data !== void 0 || unsigned.approvalAddress !== void 0 || unsigned.serializedTx !== void 0) {
|
|
650
660
|
throw new Error("swap2: provider build does not match the validated quote deposit");
|
|
651
661
|
}
|
|
652
662
|
}
|
|
@@ -1001,10 +1011,10 @@ var BaseSwap2Protocol = class extends import_core.Swap2Protocol {
|
|
|
1001
1011
|
}
|
|
1002
1012
|
/** Status of a swap by the id `swap2()` returned, asked from the provider that executed it. */
|
|
1003
1013
|
async getSwap2Status(id, _options) {
|
|
1004
|
-
const { provider: name, intentId, sourceTxHash } = decodeId(id);
|
|
1014
|
+
const { provider: name, intentId, sourceTxHash, destTxHash } = decodeId(id);
|
|
1005
1015
|
const provider = this.providerFor(name);
|
|
1006
1016
|
if (!provider) throw new Error(`swap2: no swap2 found for id '${id}'`);
|
|
1007
|
-
return mapStatus(await provider.trackIntent(sourceTxHash
|
|
1017
|
+
return mapStatus(await provider.trackIntent({ intentId, ...sourceTxHash != null ? { sourceTxHash } : {}, ...destTxHash != null ? { destTxHash } : {} }));
|
|
1008
1018
|
}
|
|
1009
1019
|
/**
|
|
1010
1020
|
* Two-phase routes (CCTP-style burn-and-mint): once `getSwap2Status` reports
|
|
@@ -1050,6 +1060,17 @@ var BaseSwap2Protocol = class extends import_core.Swap2Protocol {
|
|
|
1050
1060
|
if (unsigned.chainId !== void 0 && String(unsigned.chainId) !== expectedId) {
|
|
1051
1061
|
throw new Error(`swap2: claim chainId ${unsigned.chainId} does not match ${unsigned.chain}`);
|
|
1052
1062
|
}
|
|
1063
|
+
if (typeof provider.claimTargets !== "function") {
|
|
1064
|
+
throw new Swap2UnsupportedOperationError(`swap2: provider '${name}' declares no claimTargets \u2014 a claim may only call contracts the provider names for its chain`);
|
|
1065
|
+
}
|
|
1066
|
+
const targets = provider.claimTargets(unsigned.chain).map((a) => a.toLowerCase());
|
|
1067
|
+
if (!targets.includes(unsigned.to.toLowerCase())) {
|
|
1068
|
+
throw new Swap2ValidationError(`swap2: claim target ${unsigned.to} is not a contract '${name}' declares for ${unsigned.chain} \u2014 refused`);
|
|
1069
|
+
}
|
|
1070
|
+
const claimCall = (0, import_tx_preview_evm.decodeCall)({ to: unsigned.to, data: unsigned.data, value: 0n });
|
|
1071
|
+
if (claimCall.transfer || claimCall.approval) {
|
|
1072
|
+
throw new Swap2ValidationError(`swap2: claim calldata (${claimCall.method}) moves tokens or grants an allowance \u2014 refused`);
|
|
1073
|
+
}
|
|
1053
1074
|
const actual = await readAccountChain(signer);
|
|
1054
1075
|
if (actual == null) throw new Error(`swap2: destination account chain identity is unavailable for ${unsigned.chain}`);
|
|
1055
1076
|
const actualText = typeof actual === "string" ? actual : String(actual);
|
|
@@ -1065,7 +1086,7 @@ var BaseSwap2Protocol = class extends import_core.Swap2Protocol {
|
|
|
1065
1086
|
});
|
|
1066
1087
|
if (!sent.hash) throw new Swap2ExecutionError("swap2: account did not return a claim transaction hash");
|
|
1067
1088
|
this.emitPhase("broadcast", { hash: sent.hash });
|
|
1068
|
-
return { hash: sent.hash, chain: unsigned.chain, id };
|
|
1089
|
+
return { hash: sent.hash, chain: unsigned.chain, id: encodeId(name, intentId, sourceTxHash, sent.hash) };
|
|
1069
1090
|
}
|
|
1070
1091
|
/** The inherited bridge() has no floor field: quote first, then bind execution
|
|
1071
1092
|
* to that quote's minimum so the inherited convenience API stays safe. */
|
|
@@ -1125,7 +1146,9 @@ var BaseSwap2Protocol = class extends import_core.Swap2Protocol {
|
|
|
1125
1146
|
if ((wantFrom || wantTo) && c.caip2 !== wantFrom && c.caip2 !== wantTo) continue;
|
|
1126
1147
|
for (const a of c.assets) {
|
|
1127
1148
|
out.push({
|
|
1128
|
-
|
|
1149
|
+
// What quoteSwap2 takes back: the contract, or the symbol of the native coin — never the
|
|
1150
|
+
// provider-specific assetId, which is "" for most catalog entries (round 3, M25).
|
|
1151
|
+
token: a.contract ?? a.symbol,
|
|
1129
1152
|
chain: c.caip2,
|
|
1130
1153
|
symbol: a.symbol,
|
|
1131
1154
|
decimals: a.decimals,
|