@anywalletkit/protocol-swap2-core 0.8.0 → 0.10.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 -2
- package/dist/{chunk-FHEU7E5A.js → chunk-AY7DVYAN.js} +3 -3
- package/dist/{chunk-5FPDKWBG.js → chunk-F5TRF52T.js} +12 -3
- package/dist/chunk-F5TRF52T.js.map +1 -0
- package/dist/{chunk-6MTZNYKM.js → chunk-KB2GX6R2.js} +2 -1
- package/dist/{chunk-6MTZNYKM.js.map → chunk-KB2GX6R2.js.map} +1 -1
- package/dist/{chunk-CRCDWV3L.js → chunk-PN76KVPT.js} +59 -12
- package/dist/chunk-PN76KVPT.js.map +1 -0
- package/dist/index.cjs +67 -13
- 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 +8 -4
- package/dist/remote.cjs +1 -0
- package/dist/remote.cjs.map +1 -1
- package/dist/remote.js +1 -1
- package/dist/server.cjs +13 -3
- package/dist/server.cjs.map +1 -1
- package/dist/server.js +8 -2
- package/dist/server.js.map +1 -1
- package/dist/swap2/base.cjs +58 -11
- package/dist/swap2/base.cjs.map +1 -1
- package/dist/swap2/base.d.cts +18 -0
- package/dist/swap2/base.d.ts +18 -0
- package/dist/swap2/base.js +2 -1
- package/dist/swap2/single.cjs +119 -68
- package/dist/swap2/single.cjs.map +1 -1
- package/dist/swap2/single.js +3 -3
- package/dist/types.cjs.map +1 -1
- package/dist/types.d.cts +18 -0
- package/dist/types.d.ts +18 -0
- package/dist/validate.cjs +11 -2
- package/dist/validate.cjs.map +1 -1
- package/dist/validate.d.cts +13 -3
- package/dist/validate.d.ts +13 -3
- package/dist/validate.js +5 -1
- package/package.json +6 -6
- package/dist/chunk-5FPDKWBG.js.map +0 -1
- package/dist/chunk-CRCDWV3L.js.map +0 -1
- /package/dist/{chunk-FHEU7E5A.js.map → chunk-AY7DVYAN.js.map} +0 -0
package/dist/swap2/single.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
SingleProviderSwap2
|
|
3
|
-
} from "../chunk-
|
|
4
|
-
import "../chunk-
|
|
3
|
+
} from "../chunk-AY7DVYAN.js";
|
|
4
|
+
import "../chunk-PN76KVPT.js";
|
|
5
5
|
import "../chunk-IVR3SREQ.js";
|
|
6
|
-
import "../chunk-
|
|
6
|
+
import "../chunk-F5TRF52T.js";
|
|
7
7
|
import "../chunk-2KC734UX.js";
|
|
8
8
|
export {
|
|
9
9
|
SingleProviderSwap2
|
package/dist/types.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/types.ts"],"sourcesContent":["/**\n * Cross-chain asset delivery types. The vault is single-chain; cross-chain is\n * delivery only, via a router over pluggable providers (NEAR Intents + others).\n * A provider can only delay/refund delivery — it can never affect vault safety.\n */\nimport type {ActivityItem, ChainTx, DescribeActivityContext} from \"@anywalletkit/core\";\n\n/** A token on a chain, as providers see it. */\nexport interface Asset {\n chain: string; // CAIP-2, e.g. \"tron:728126428\"\n token: string; // native-format token id/address on that chain\n}\n\n/** What the engine asks a provider to quote. Amounts are base-unit strings; exact input only. */\nexport interface QuoteParams {\n /** Local-only (never serialized): called with the reason when the provider\n * refuses to quote — a shared-instance \"last refusal\" field raced under\n * concurrent quotes, so the reason rides per-call. */\n onRefusal?: (reason: string) => void;\n sourceChain: string; // CAIP-2\n sourceToken: string; // token SYMBOL on source (resolved via the asset catalog), or an unlisted token's contract / mint\n /**\n * Set only for a source token the catalog does not list: `sourceToken` is then its contract\n * (EVM) or mint (Solana) and this its decimals. Providers that can trade any token resolve it with\n * `resolveAsset(chain, sourceToken, {allowUnlisted: true, decimals})`; the others refuse it.\n */\n sourceDecimals?: number;\n destChain: string; // CAIP-2 (the vault's chain)\n destToken: string; // ERC-20 address on dest (zero address = native ETH)\n amountIn: string; // what the user sends on source (base units, EXACT_INPUT)\n /** Caller-supplied output floor in destination base units. */\n minAmountOut?: string;\n /** Maximum slippage accepted by the caller, expressed in basis points. */\n slippageBps?: number;\n destAddress: string; // recipient on dest (the vault, or a payout address)\n /** Where a failed swap refunds on the source chain (the sender's address). */\n refundAddress?: string;\n /** Pricing preview only — no deposit address is created upstream. */\n dry?: boolean;\n /**\n * Amount-flexible deposit (exchange flow): `amountIn` is only a pricing\n * notional — the user may send any amount to the deposit address (1Click\n * FLEX_INPUT). Providers that can't do this return no quote.\n */\n flex?: boolean;\n}\n\n/**\n * Provider-built transaction for the CALLDATA execution model (LI.FI): the\n * user's wallet must execute this exact payload — a plain transfer to `to`\n * would LOSE funds. Either an EVM request or a pre-serialized Solana tx.\n */\nexport interface TxRequest {\n to?: string;\n data?: string; // EVM calldata\n value?: string; // wei, decimal string\n chainId?: number;\n gasLimit?: string;\n /** ERC-20 sources must approve this spender before executing. */\n approvalAddress?: string;\n /**\n * Native coin the route itself charges on top of the input (bridge\n * messaging fees — Stargate/LayerZero-style), base units. A token source\n * then sends exactly this as `value`; a native source sends input + this.\n * Declared by the provider from the quote, sealed with it, and capped by\n * the engine per chain.\n */\n nativeFee?: string;\n /** Solana: base64-serialized transaction to sign & broadcast as-is. */\n serializedTx?: string;\n}\n\n/** A normalized quote from one provider. */\nexport interface Quote {\n /** Provider name. */\n provider: string;\n /** Provider's id for this swap; tracked with `trackIntent`. */\n intentId: string;\n depositAddress: string; // where the user sends source funds (\"\" on dry quotes)\n depositMemo: string | null; // MUST accompany the deposit when present (TON)\n /** Present instead of a usable depositAddress for calldata providers. */\n txRequest?: TxRequest;\n sourceAmount: string; // what the user pays on source (base units)\n destAmount: string; // what arrives on dest (base units)\n minDestAmount: string; // worst case at the quoted slippage (base units)\n feeUsd: number; // normalized fee for scoring\n /** Honest itemized fees when the provider exposes base-unit amounts. */\n fees?: {type: \"network\" | \"protocol\" | \"affiliate\" | \"other\"; amount: string; token: string; included: boolean; description?: string}[];\n /** Estimated time to delivery. */\n etaSeconds: number; // estimated settlement time\n /** Provider's reliability hint, 0 to 1. */\n reliability: number; // 0..1 provider/route reliability hint\n /** Quote expiry, unix milliseconds. */\n validUntilMs: number;\n /** Provider-owned, JSON-safe facts required to revalidate execution. */\n providerData?: Record<string, string>;\n}\n\n/** What trackIntent gets to work with (LI.FI tracks by the source tx hash). */\nexport interface IntentRef {\n intentId: string;\n sourceTxHash?: string | null;\n /** Two-phase routes: the destination-chain claim transaction, once sent. */\n destTxHash?: string | null;\n}\n\n/** The router's chosen quote, tagged with how it scored. */\nexport interface RoutedQuote extends Quote {\n routeScore: {\n score: number;\n weights: ScoreWeights;\n /** Every validated route: `score` is its value against the best (0..1). */\n candidates: {provider: string; sourceAmount: string; etaSeconds: number; score: number; minDestAmount?: string; netValueUsd?: number | null}[];\n };\n}\n\n/** How the router weighs price, speed and reliability when it scores routes. */\nexport interface ScoreWeights {\n price: number;\n speed: number;\n reliability: number;\n}\n\n/** A swap's state as the engine reports it; maps to `Swap2Status`. */\nexport type IntentState =\n | \"pending\"\n | \"action-required\"\n | \"refund-pending\"\n | \"partial\"\n | \"completed\"\n | \"failed\"\n | \"refunded\"\n | \"cancelled\"\n | \"expired\";\n\n/** A provider's answer to `trackIntent`. */\nexport interface IntentStatus {\n state: IntentState;\n /** Still pending, but the source deposit has been observed (PROCESSING). */\n depositReceived?: boolean;\n destTxHash?: string;\n /**\n * Two-phase routes (CCTP-style burn-and-mint): the delivery needs a second,\n * user-signed transaction on the destination chain. `ready` means the\n * provider can build it now (`buildClaim`); `state` is then\n * \"action-required\". Before that the route is \"pending\" with `ready: false`.\n */\n claim?: {chain: string; ready: boolean};\n}\n\n/** A provider's source-leg transaction, before the engine checks and signs it. */\nexport interface UnsignedTx {\n chain: string;\n to: string;\n value: string;\n data?: string;\n chainId?: number;\n gasLimit?: string;\n /** ERC-20 spender that must be approved before the calldata is sent. */\n approvalAddress?: string;\n /** Provider-native serialized transaction (for accounts that expose a hook). */\n serializedTx?: string;\n /** Native-chain memo/body required by the deposit protocol. */\n memo?: string;\n /** How `memo` becomes bytes on chains whose memo is a byte field (Tron `raw_data.data`): 'utf8' text (default) or\n * 'hex' — a binary payload given as 0x-hex (a Chainflip vault-swap note). */\n memoEncoding?: \"utf8\" | \"hex\";\n /**\n * TON: serialized message-body CELL (base64 BoC) — e.g. an Omniston escrow\n * payload. NOT interchangeable with `memo`: a memo is a text comment, while\n * sending a BoC as text strands the swap. Executors must decode it to a Cell.\n */\n bodyBoc?: string;\n /** TON: contract stateInit (base64 BoC) the message must carry, when present. */\n stateInitBoc?: string;\n /**\n * GASLESS typed-order execution (Omniston EVM-source): the JSON EIP-712\n * payload the account must sign — there is NO source transaction. After\n * signing, complete via `CrossChainProvider.registerSignedOrder`. When set,\n * `approvalAddress` names the settlement contract that needs allowance.\n */\n typedData?: string;\n /**\n * Typed-order execution: the order extension (0x-hex) the order's salt commits to — a 1inch Limit Order Protocol\n * order's amount getters and post-interaction, where an HTLC order's escrow terms live. Carried so an app can open\n * a remote build on the client (`omnistonVerifyBuild`, scan 2026-10-28 F6); the signature covers it through the salt.\n */\n orderExtension?: string;\n}\n\n/**\n * The contracts a provider's EVM swaps call and approve on a chain, shipped by the provider package\n * (`lifiPins`, `fyndPins`, `uniswapPins`…) and handed to `remoteProvider({...pins})`: a backend's\n * build is checked against the app's addresses, never against its own (scan 2026-10-27 modules,\n * F8/F9/F16). An empty list means the provider has no EVM calldata route on that chain.\n */\nexport interface RemotePins {\n callTargets(chain: string): readonly string[];\n spenders(chain: string): readonly string[];\n /**\n * A client-side check of a remote quote's transaction against the user's own request — the\n * provider's local validator run again on this side (Fynd: `checkFyndTransaction`): the reason it\n * fails, or null.\n */\n verifyQuote?(params: QuoteParams, quote: Quote): string | null;\n /** A client-side check of a remote build (typed order, cell body) against its quote: the reason it fails, or null. */\n verifyBuild?(quote: Quote, tx: UnsignedTx, params?: QuoteParams): string | null | Promise<string | null>;\n /**\n * The provider's routes pay an address the backend names — a deposit address, or a plain value send — instead of\n * calling a pinned contract (`thorchainPins` for a Tron vault, NEAR Intents' per-quote deposit addresses). Without\n * it a remote stub's deposit-address and plain-value routes are refused (scan 2026-10-28, F9).\n */\n depositAddressRoutes?: boolean;\n}\n\n/**\n * Pluggable cross-chain provider. Adding a provider is \"add a module\"; the rest\n * of the app references only this interface (never a specific provider).\n */\nexport interface CrossChainProvider {\n /** Provider name, unique in a router. */\n readonly name: string;\n /** Master flag — providers ship \"dark\" (off) until validated with real funds. */\n enabled(): boolean;\n /** Cheap synchronous check: can this provider route `from` to `to`? No I/O. */\n supportsRoute(from: Asset, to: Asset): boolean;\n /** A quote, or `null` with the reason passed to `params.onRefusal`. */\n getQuote(params: QuoteParams, signal?: AbortSignal): Promise<Quote | null>;\n /** The source-leg transaction for a quote. */\n buildDeposit(quote: Quote): Promise<UnsignedTx>;\n /**\n * Last fail-closed check after any approval and immediately before the\n * wallet signs/broadcasts the source leg. Providers whose execution target\n * can rotate or halt (THORChain vaults/routers) must revalidate it here.\n */\n preflightDeposit?(quote: Quote, tx: UnsignedTx): Promise<void>;\n /** Current status of a swap. */\n trackIntent(ref: IntentRef): Promise<IntentStatus>;\n /**\n * Tell the provider the source funds were sent (tx hash / BoC). Required for\n * NEAR Intents TON deposits — the HOT-bridge oracle can't observe SIMPLE-mode\n * deposits on uninitialized addresses without it. Best-effort elsewhere.\n */\n notifyDeposit?(intentId: string, txHash: string): Promise<void>;\n /** Gasless typed-order providers: register the wallet's EIP-712 signature. */\n registerSignedOrder?(intentId: string, signature: string): Promise<void>;\n /**\n * Two-phase routes: the destination-chain transaction that completes the\n * delivery (CCTP `receiveMessage(message, attestation)`), or `null` while\n * the attestation is not available yet. The engine executes it through a\n * destination-chain account (`claimSwap2`); `tx.chain` names that chain.\n */\n buildClaim?(ref: IntentRef): Promise<UnsignedTx | null>;\n /**\n * The contracts a claim from {@link buildClaim} may call on `chain` (CAIP-2) — CCTP's\n * MessageTransmitter. `claimSwap2` refuses a claim to anything else, and a provider with a claim\n * step must declare them (round 3, M24). Kept on the client: for a remote provider this is the\n * app's list, never the server's.\n */\n claimTargets?(chain: string): readonly string[];\n /**\n * Set by `remoteProvider`: the quotes and builds come from a backend, not from code the app\n * ships. The engine then takes the addresses an EVM transaction may call or approve only from\n * {@link callTargets} / {@link spenders} — the app's pins — and refuses a calldata route or an\n * approval it has no pin for (scan 2026-10-27 modules, F8/F9/F16).\n */\n readonly remote?: boolean;\n /** Set by `remoteProvider` when the app gave it `verifyBuild`: its builds are checked on the client. */\n readonly verifiesBuilds?: boolean;\n /**\n * Set by `remoteProvider` when the app opted in (`depositAddressRoutes`): this stub may send the input to an address\n * its backend names. Without it the engine refuses a remote stub's deposit-address and plain-value builds.\n */\n readonly depositAddressRoutes?: boolean;\n /** Remote stubs: the contracts this provider's EVM swaps may call on `chain` (the app's list, e.g. `lifiPins`). */\n callTargets?(chain: string): readonly string[];\n /** Remote stubs: the spenders this provider's EVM swaps may be approved for on `chain` (the app's list). */\n spenders?(chain: string): readonly string[];\n close?(): void;\n /** Optional discovery hook for custom providers. */\n supportsChain?(caip2: string): boolean;\n /** Optional pair-level discovery for aggregators. */\n supportsChainPair?(fromChain: string, toChain: string): boolean;\n /** Explicit opt-in: provider can execute a same-chain swap. */\n supportsSameChain?: boolean;\n /**\n * Recognize one of this provider's own transactions in an address's history\n * (contract + selector on EVM, settlement counterparty elsewhere) and\n * describe it for the activity feed; null when it is not this provider's.\n * Pure and synchronous. The single-provider protocol classes and the router\n * delegate `describeActivity` here.\n */\n describeActivity?(tx: ChainTx, ctx: DescribeActivityContext): ActivityItem | null;\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAAA;AAAA;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/types.ts"],"sourcesContent":["/**\n * Cross-chain asset delivery types. The vault is single-chain; cross-chain is\n * delivery only, via a router over pluggable providers (NEAR Intents + others).\n * A provider can only delay/refund delivery — it can never affect vault safety.\n */\nimport type {ActivityItem, ChainTx, DescribeActivityContext} from \"@anywalletkit/core\";\n\n/** A token on a chain, as providers see it. */\nexport interface Asset {\n chain: string; // CAIP-2, e.g. \"tron:728126428\"\n token: string; // native-format token id/address on that chain\n}\n\n/** What the engine asks a provider to quote. Amounts are base-unit strings; exact input only. */\nexport interface QuoteParams {\n /** Local-only (never serialized): called with the reason when the provider\n * refuses to quote — a shared-instance \"last refusal\" field raced under\n * concurrent quotes, so the reason rides per-call. */\n onRefusal?: (reason: string) => void;\n sourceChain: string; // CAIP-2\n sourceToken: string; // token SYMBOL on source (resolved via the asset catalog), or an unlisted token's contract / mint\n /**\n * Set only for a source token the catalog does not list: `sourceToken` is then its contract\n * (EVM) or mint (Solana) and this its decimals. Providers that can trade any token resolve it with\n * `resolveAsset(chain, sourceToken, {allowUnlisted: true, decimals})`; the others refuse it.\n */\n sourceDecimals?: number;\n destChain: string; // CAIP-2 (the vault's chain)\n destToken: string; // ERC-20 address on dest (zero address = native ETH)\n amountIn: string; // what the user sends on source (base units, EXACT_INPUT)\n /** Caller-supplied output floor in destination base units. */\n minAmountOut?: string;\n /** Maximum slippage accepted by the caller, expressed in basis points. */\n slippageBps?: number;\n destAddress: string; // recipient on dest (the vault, or a payout address)\n /** Where a failed swap refunds on the source chain (the sender's address). */\n refundAddress?: string;\n /** Pricing preview only — no deposit address is created upstream. */\n dry?: boolean;\n /**\n * Amount-flexible deposit (exchange flow): `amountIn` is only a pricing\n * notional — the user may send any amount to the deposit address (1Click\n * FLEX_INPUT). Providers that can't do this return no quote.\n */\n flex?: boolean;\n}\n\n/**\n * Provider-built transaction for the CALLDATA execution model (LI.FI): the\n * user's wallet must execute this exact payload — a plain transfer to `to`\n * would LOSE funds. Either an EVM request or a pre-serialized Solana tx.\n */\nexport interface TxRequest {\n to?: string;\n data?: string; // EVM calldata\n value?: string; // wei, decimal string\n chainId?: number;\n gasLimit?: string;\n /** ERC-20 sources must approve this spender before executing. */\n approvalAddress?: string;\n /**\n * Native coin the route itself charges on top of the input (bridge\n * messaging fees — Stargate/LayerZero-style), base units. A token source\n * then sends exactly this as `value`; a native source sends input + this.\n * Declared by the provider from the quote, sealed with it, and capped by\n * the engine per chain.\n */\n nativeFee?: string;\n /** Solana: base64-serialized transaction to sign & broadcast as-is. */\n serializedTx?: string;\n}\n\n/** A normalized quote from one provider. */\nexport interface Quote {\n /** Provider name. */\n provider: string;\n /** Provider's id for this swap; tracked with `trackIntent`. */\n intentId: string;\n depositAddress: string; // where the user sends source funds (\"\" on dry quotes)\n depositMemo: string | null; // MUST accompany the deposit when present (TON)\n /** Present instead of a usable depositAddress for calldata providers. */\n txRequest?: TxRequest;\n sourceAmount: string; // what the user pays on source (base units)\n destAmount: string; // what arrives on dest (base units)\n minDestAmount: string; // worst case at the quoted slippage (base units)\n /**\n * Decimals of the destination token as the provider reports them (LI.FI's `action.toToken.decimals`). They are the\n * provider's word, so the engine never uses them alone for the reviewed minimum it hands an account\n * (`bridgeOut.destDecimals`): that is the catalog's value, else the caller's `toTokenDecimals`, and a quote whose value\n * disagrees with the caller's is refused.\n */\n destDecimals?: number;\n feeUsd: number; // normalized fee for scoring\n /** Honest itemized fees when the provider exposes base-unit amounts. */\n fees?: {type: \"network\" | \"protocol\" | \"affiliate\" | \"other\"; amount: string; token: string; included: boolean; description?: string}[];\n /** Estimated time to delivery. */\n etaSeconds: number; // estimated settlement time\n /** Provider's reliability hint, 0 to 1. */\n reliability: number; // 0..1 provider/route reliability hint\n /** Quote expiry, unix milliseconds. */\n validUntilMs: number;\n /** Provider-owned, JSON-safe facts required to revalidate execution. */\n providerData?: Record<string, string>;\n}\n\n/** What trackIntent gets to work with (LI.FI tracks by the source tx hash). */\nexport interface IntentRef {\n intentId: string;\n sourceTxHash?: string | null;\n /** Two-phase routes: the destination-chain claim transaction, once sent. */\n destTxHash?: string | null;\n /**\n * `true` when the account that sent `destTxHash` saw it included and succeed (`claimSwap2` after\n * the account's `waitForTransaction` resolved). A provider that cannot read the destination may\n * take it as the delivery; a bare `destTxHash` proves only that a claim was sent.\n */\n destTxConfirmed?: boolean;\n}\n\n/** The router's chosen quote, tagged with how it scored. */\nexport interface RoutedQuote extends Quote {\n routeScore: {\n score: number;\n weights: ScoreWeights;\n /** Every validated route: `score` is its value against the best (0..1). */\n candidates: {provider: string; sourceAmount: string; etaSeconds: number; score: number; minDestAmount?: string; netValueUsd?: number | null}[];\n };\n}\n\n/** How the router weighs price, speed and reliability when it scores routes. */\nexport interface ScoreWeights {\n price: number;\n speed: number;\n reliability: number;\n}\n\n/** A swap's state as the engine reports it; maps to `Swap2Status`. */\nexport type IntentState =\n | \"pending\"\n | \"action-required\"\n | \"refund-pending\"\n | \"partial\"\n | \"completed\"\n | \"failed\"\n | \"refunded\"\n | \"cancelled\"\n | \"expired\";\n\n/** A provider's answer to `trackIntent`. */\nexport interface IntentStatus {\n state: IntentState;\n /** Still pending, but the source deposit has been observed (PROCESSING). */\n depositReceived?: boolean;\n destTxHash?: string;\n /**\n * Two-phase routes (CCTP-style burn-and-mint): the delivery needs a second,\n * user-signed transaction on the destination chain. `ready` means the\n * provider can build it now (`buildClaim`); `state` is then\n * \"action-required\". Before that the route is \"pending\" with `ready: false`.\n */\n claim?: {chain: string; ready: boolean};\n}\n\n/** A provider's source-leg transaction, before the engine checks and signs it. */\nexport interface UnsignedTx {\n chain: string;\n to: string;\n value: string;\n data?: string;\n chainId?: number;\n gasLimit?: string;\n /** ERC-20 spender that must be approved before the calldata is sent. */\n approvalAddress?: string;\n /** Provider-native serialized transaction (for accounts that expose a hook). */\n serializedTx?: string;\n /** Native-chain memo/body required by the deposit protocol. */\n memo?: string;\n /** How `memo` becomes bytes on chains whose memo is a byte field (Tron `raw_data.data`): 'utf8' text (default) or\n * 'hex' — a binary payload given as 0x-hex (a Chainflip vault-swap note). */\n memoEncoding?: \"utf8\" | \"hex\";\n /**\n * TON: serialized message-body CELL (base64 BoC) — e.g. an Omniston escrow\n * payload. NOT interchangeable with `memo`: a memo is a text comment, while\n * sending a BoC as text strands the swap. Executors must decode it to a Cell.\n */\n bodyBoc?: string;\n /** TON: contract stateInit (base64 BoC) the message must carry, when present. */\n stateInitBoc?: string;\n /**\n * GASLESS typed-order execution (Omniston EVM-source): the JSON EIP-712\n * payload the account must sign — there is NO source transaction. After\n * signing, complete via `CrossChainProvider.registerSignedOrder`. When set,\n * `approvalAddress` names the settlement contract that needs allowance.\n */\n typedData?: string;\n /**\n * Typed-order execution: the order extension (0x-hex) the order's salt commits to — a 1inch Limit Order Protocol\n * order's amount getters and post-interaction, where an HTLC order's escrow terms live. Carried so an app can open\n * a remote build on the client (`omnistonVerifyBuild`, scan 2026-10-28 F6); the signature covers it through the salt.\n */\n orderExtension?: string;\n}\n\n/**\n * The contracts a provider's EVM swaps call and approve on a chain, shipped by the provider package\n * (`lifiPins`, `fyndPins`, `uniswapPins`…) and handed to `remoteProvider({...pins})`: a backend's\n * build is checked against the app's addresses, never against its own (scan 2026-10-27 modules,\n * F8/F9/F16). An empty list means the provider has no EVM calldata route on that chain.\n */\nexport interface RemotePins {\n callTargets(chain: string): readonly string[];\n spenders(chain: string): readonly string[];\n /**\n * A client-side check of a remote quote's transaction against the user's own request — the\n * provider's local validator run again on this side (Fynd: `checkFyndTransaction`): the reason it\n * fails, or null.\n */\n verifyQuote?(params: QuoteParams, quote: Quote): string | null;\n /** A client-side check of a remote build (typed order, cell body) against its quote: the reason it fails, or null. */\n verifyBuild?(quote: Quote, tx: UnsignedTx, params?: QuoteParams): string | null | Promise<string | null>;\n /**\n * The provider's routes pay an address the backend names — a deposit address, or a plain value send — instead of\n * calling a pinned contract (`thorchainPins` for a Tron vault, NEAR Intents' per-quote deposit addresses). Without\n * it a remote stub's deposit-address and plain-value routes are refused (scan 2026-10-28, F9).\n */\n depositAddressRoutes?: boolean;\n}\n\n/**\n * Pluggable cross-chain provider. Adding a provider is \"add a module\"; the rest\n * of the app references only this interface (never a specific provider).\n */\nexport interface CrossChainProvider {\n /** Provider name, unique in a router. */\n readonly name: string;\n /** Master flag — providers ship \"dark\" (off) until validated with real funds. */\n enabled(): boolean;\n /** Cheap synchronous check: can this provider route `from` to `to`? No I/O. */\n supportsRoute(from: Asset, to: Asset): boolean;\n /** A quote, or `null` with the reason passed to `params.onRefusal`. */\n getQuote(params: QuoteParams, signal?: AbortSignal): Promise<Quote | null>;\n /** The source-leg transaction for a quote. */\n buildDeposit(quote: Quote): Promise<UnsignedTx>;\n /**\n * Last fail-closed check after any approval and immediately before the\n * wallet signs/broadcasts the source leg. Providers whose execution target\n * can rotate or halt (THORChain vaults/routers) must revalidate it here.\n */\n preflightDeposit?(quote: Quote, tx: UnsignedTx): Promise<void>;\n /** Current status of a swap. */\n trackIntent(ref: IntentRef): Promise<IntentStatus>;\n /**\n * Tell the provider the source funds were sent (tx hash / BoC). Required for\n * NEAR Intents TON deposits — the HOT-bridge oracle can't observe SIMPLE-mode\n * deposits on uninitialized addresses without it. Best-effort elsewhere.\n */\n notifyDeposit?(intentId: string, txHash: string): Promise<void>;\n /** Gasless typed-order providers: register the wallet's EIP-712 signature. */\n registerSignedOrder?(intentId: string, signature: string): Promise<void>;\n /**\n * Two-phase routes: the destination-chain transaction that completes the\n * delivery (CCTP `receiveMessage(message, attestation)`), or `null` while\n * the attestation is not available yet. The engine executes it through a\n * destination-chain account (`claimSwap2`); `tx.chain` names that chain.\n */\n buildClaim?(ref: IntentRef): Promise<UnsignedTx | null>;\n /**\n * The contracts a claim from {@link buildClaim} may call on `chain` (CAIP-2) — CCTP's\n * MessageTransmitter. `claimSwap2` refuses a claim to anything else, and a provider with a claim\n * step must declare them (round 3, M24). Kept on the client: for a remote provider this is the\n * app's list, never the server's.\n */\n claimTargets?(chain: string): readonly string[];\n /**\n * Set by `remoteProvider`: the quotes and builds come from a backend, not from code the app\n * ships. The engine then takes the addresses an EVM transaction may call or approve only from\n * {@link callTargets} / {@link spenders} — the app's pins — and refuses a calldata route or an\n * approval it has no pin for (scan 2026-10-27 modules, F8/F9/F16).\n */\n readonly remote?: boolean;\n /** Set by `remoteProvider` when the app gave it `verifyBuild`: its builds are checked on the client. */\n readonly verifiesBuilds?: boolean;\n /**\n * Set by `remoteProvider` when the app gave it `verifyQuote`: its quotes' transactions are checked on the client.\n * A remote stub's EVM calldata route needs this or {@link verifiesBuilds} (scan 2026-10-30, F3).\n */\n readonly verifiesQuotes?: boolean;\n /**\n * Set by `remoteProvider` when the app opted in (`depositAddressRoutes`): this stub may send the input to an address\n * its backend names. Without it the engine refuses a remote stub's deposit-address and plain-value builds.\n */\n readonly depositAddressRoutes?: boolean;\n /** Remote stubs: the contracts this provider's EVM swaps may call on `chain` (the app's list, e.g. `lifiPins`). */\n callTargets?(chain: string): readonly string[];\n /** Remote stubs: the spenders this provider's EVM swaps may be approved for on `chain` (the app's list). */\n spenders?(chain: string): readonly string[];\n close?(): void;\n /** Optional discovery hook for custom providers. */\n supportsChain?(caip2: string): boolean;\n /** Optional pair-level discovery for aggregators. */\n supportsChainPair?(fromChain: string, toChain: string): boolean;\n /** Explicit opt-in: provider can execute a same-chain swap. */\n supportsSameChain?: boolean;\n /**\n * Recognize one of this provider's own transactions in an address's history\n * (contract + selector on EVM, settlement counterparty elsewhere) and\n * describe it for the activity feed; null when it is not this provider's.\n * Pure and synchronous. The single-provider protocol classes and the router\n * delegate `describeActivity` here.\n */\n describeActivity?(tx: ChainTx, ctx: DescribeActivityContext): ActivityItem | null;\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAAA;AAAA;","names":[]}
|
package/dist/types.d.cts
CHANGED
|
@@ -81,6 +81,13 @@ interface Quote {
|
|
|
81
81
|
sourceAmount: string;
|
|
82
82
|
destAmount: string;
|
|
83
83
|
minDestAmount: string;
|
|
84
|
+
/**
|
|
85
|
+
* Decimals of the destination token as the provider reports them (LI.FI's `action.toToken.decimals`). They are the
|
|
86
|
+
* provider's word, so the engine never uses them alone for the reviewed minimum it hands an account
|
|
87
|
+
* (`bridgeOut.destDecimals`): that is the catalog's value, else the caller's `toTokenDecimals`, and a quote whose value
|
|
88
|
+
* disagrees with the caller's is refused.
|
|
89
|
+
*/
|
|
90
|
+
destDecimals?: number;
|
|
84
91
|
feeUsd: number;
|
|
85
92
|
/** Honest itemized fees when the provider exposes base-unit amounts. */
|
|
86
93
|
fees?: {
|
|
@@ -105,6 +112,12 @@ interface IntentRef {
|
|
|
105
112
|
sourceTxHash?: string | null;
|
|
106
113
|
/** Two-phase routes: the destination-chain claim transaction, once sent. */
|
|
107
114
|
destTxHash?: string | null;
|
|
115
|
+
/**
|
|
116
|
+
* `true` when the account that sent `destTxHash` saw it included and succeed (`claimSwap2` after
|
|
117
|
+
* the account's `waitForTransaction` resolved). A provider that cannot read the destination may
|
|
118
|
+
* take it as the delivery; a bare `destTxHash` proves only that a claim was sent.
|
|
119
|
+
*/
|
|
120
|
+
destTxConfirmed?: boolean;
|
|
108
121
|
}
|
|
109
122
|
/** The router's chosen quote, tagged with how it scored. */
|
|
110
123
|
interface RoutedQuote extends Quote {
|
|
@@ -264,6 +277,11 @@ interface CrossChainProvider {
|
|
|
264
277
|
readonly remote?: boolean;
|
|
265
278
|
/** Set by `remoteProvider` when the app gave it `verifyBuild`: its builds are checked on the client. */
|
|
266
279
|
readonly verifiesBuilds?: boolean;
|
|
280
|
+
/**
|
|
281
|
+
* Set by `remoteProvider` when the app gave it `verifyQuote`: its quotes' transactions are checked on the client.
|
|
282
|
+
* A remote stub's EVM calldata route needs this or {@link verifiesBuilds} (scan 2026-10-30, F3).
|
|
283
|
+
*/
|
|
284
|
+
readonly verifiesQuotes?: boolean;
|
|
267
285
|
/**
|
|
268
286
|
* Set by `remoteProvider` when the app opted in (`depositAddressRoutes`): this stub may send the input to an address
|
|
269
287
|
* its backend names. Without it the engine refuses a remote stub's deposit-address and plain-value builds.
|
package/dist/types.d.ts
CHANGED
|
@@ -81,6 +81,13 @@ interface Quote {
|
|
|
81
81
|
sourceAmount: string;
|
|
82
82
|
destAmount: string;
|
|
83
83
|
minDestAmount: string;
|
|
84
|
+
/**
|
|
85
|
+
* Decimals of the destination token as the provider reports them (LI.FI's `action.toToken.decimals`). They are the
|
|
86
|
+
* provider's word, so the engine never uses them alone for the reviewed minimum it hands an account
|
|
87
|
+
* (`bridgeOut.destDecimals`): that is the catalog's value, else the caller's `toTokenDecimals`, and a quote whose value
|
|
88
|
+
* disagrees with the caller's is refused.
|
|
89
|
+
*/
|
|
90
|
+
destDecimals?: number;
|
|
84
91
|
feeUsd: number;
|
|
85
92
|
/** Honest itemized fees when the provider exposes base-unit amounts. */
|
|
86
93
|
fees?: {
|
|
@@ -105,6 +112,12 @@ interface IntentRef {
|
|
|
105
112
|
sourceTxHash?: string | null;
|
|
106
113
|
/** Two-phase routes: the destination-chain claim transaction, once sent. */
|
|
107
114
|
destTxHash?: string | null;
|
|
115
|
+
/**
|
|
116
|
+
* `true` when the account that sent `destTxHash` saw it included and succeed (`claimSwap2` after
|
|
117
|
+
* the account's `waitForTransaction` resolved). A provider that cannot read the destination may
|
|
118
|
+
* take it as the delivery; a bare `destTxHash` proves only that a claim was sent.
|
|
119
|
+
*/
|
|
120
|
+
destTxConfirmed?: boolean;
|
|
108
121
|
}
|
|
109
122
|
/** The router's chosen quote, tagged with how it scored. */
|
|
110
123
|
interface RoutedQuote extends Quote {
|
|
@@ -264,6 +277,11 @@ interface CrossChainProvider {
|
|
|
264
277
|
readonly remote?: boolean;
|
|
265
278
|
/** Set by `remoteProvider` when the app gave it `verifyBuild`: its builds are checked on the client. */
|
|
266
279
|
readonly verifiesBuilds?: boolean;
|
|
280
|
+
/**
|
|
281
|
+
* Set by `remoteProvider` when the app gave it `verifyQuote`: its quotes' transactions are checked on the client.
|
|
282
|
+
* A remote stub's EVM calldata route needs this or {@link verifiesBuilds} (scan 2026-10-30, F3).
|
|
283
|
+
*/
|
|
284
|
+
readonly verifiesQuotes?: boolean;
|
|
267
285
|
/**
|
|
268
286
|
* Set by `remoteProvider` when the app opted in (`depositAddressRoutes`): this stub may send the input to an address
|
|
269
287
|
* its backend names. Without it the engine refuses a remote stub's deposit-address and plain-value builds.
|
package/dist/validate.cjs
CHANGED
|
@@ -20,10 +20,17 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/validate.ts
|
|
21
21
|
var validate_exports = {};
|
|
22
22
|
__export(validate_exports, {
|
|
23
|
+
SLIPPAGE_ROUNDING_BPS: () => SLIPPAGE_ROUNDING_BPS,
|
|
23
24
|
remotePinRefusal: () => remotePinRefusal,
|
|
25
|
+
slippageFloor: () => slippageFloor,
|
|
24
26
|
validQuote: () => validQuote
|
|
25
27
|
});
|
|
26
28
|
module.exports = __toCommonJS(validate_exports);
|
|
29
|
+
var SLIPPAGE_ROUNDING_BPS = 1;
|
|
30
|
+
function slippageFloor(dest, slippageBps) {
|
|
31
|
+
const keep = 1e4 - slippageBps - SLIPPAGE_ROUNDING_BPS;
|
|
32
|
+
return keep <= 0 ? 0n : dest * BigInt(keep) / 10000n;
|
|
33
|
+
}
|
|
27
34
|
function validQuote(q, params, provider) {
|
|
28
35
|
try {
|
|
29
36
|
if (q.provider !== provider || q.sourceAmount !== params.amountIn) return false;
|
|
@@ -38,8 +45,7 @@ function validQuote(q, params, provider) {
|
|
|
38
45
|
}
|
|
39
46
|
if (params.slippageBps !== void 0) {
|
|
40
47
|
if (!Number.isInteger(params.slippageBps) || params.slippageBps < 0 || params.slippageBps >= 1e4) return false;
|
|
41
|
-
|
|
42
|
-
if (min < required) return false;
|
|
48
|
+
if (min < slippageFloor(dest, params.slippageBps)) return false;
|
|
43
49
|
}
|
|
44
50
|
if (!Number.isFinite(q.etaSeconds) || q.etaSeconds < 0) return false;
|
|
45
51
|
if (!Number.isFinite(q.reliability) || q.reliability < 0 || q.reliability > 1) return false;
|
|
@@ -77,6 +83,9 @@ function remotePinRefusal(provider, q, chain) {
|
|
|
77
83
|
if (tx.data !== void 0 && tx.to && !pinned(provider.callTargets?.(chain), tx.to)) {
|
|
78
84
|
return `${provider.name}: the route calls ${tx.to}, which the app did not pin as a call target on ${chain} (remoteProvider callTargets)`;
|
|
79
85
|
}
|
|
86
|
+
if (tx.data !== void 0 && provider.verifiesQuotes !== true && provider.verifiesBuilds !== true) {
|
|
87
|
+
return `${provider.name}: the route's calldata is not checked by the app (remoteProvider verifyQuote / verifyBuild) \u2014 a pinned target alone does not say whom it pays`;
|
|
88
|
+
}
|
|
80
89
|
return null;
|
|
81
90
|
}
|
|
82
91
|
//# sourceMappingURL=validate.cjs.map
|
package/dist/validate.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/validate.ts"],"sourcesContent":["import type {CrossChainProvider, Quote, QuoteParams} from \"./types.js\";\n\n/** Shared quote validator used by both the aggregate and single-provider paths. */\nexport function validQuote(q: Quote, params: QuoteParams, provider: string): boolean {\n try {\n if (q.provider !== provider || q.sourceAmount !== params.amountIn) return false;\n if (typeof q.intentId !== \"string\" || !q.intentId || typeof q.depositAddress !== \"string\" || (q.depositMemo !== null && typeof q.depositMemo !== \"string\")) return false;\n if (![q.sourceAmount, q.destAmount, q.minDestAmount].every((value) => /^[0-9]+$/.test(value))) return false;\n const source = BigInt(q.sourceAmount);\n const dest = BigInt(q.destAmount);\n const min = BigInt(q.minDestAmount);\n if (source <= 0n || dest <= 0n || min <= 0n || min > dest) return false;\n if (params.minAmountOut !== undefined) {\n if (!/^[0-9]+$/.test(params.minAmountOut) || BigInt(params.minAmountOut) <= 0n || min < BigInt(params.minAmountOut)) return false;\n }\n if (params.slippageBps !== undefined) {\n if (!Number.isInteger(params.slippageBps) || params.slippageBps < 0 || params.slippageBps >= 10_000) return false;\n // Providers round the floor DOWN (1Click, LI.FI: floor(dest × (1 − s)))
|
|
1
|
+
{"version":3,"sources":["../src/validate.ts"],"sourcesContent":["import type {CrossChainProvider, Quote, QuoteParams} from \"./types.js\";\n\n/**\n * How far past the requested slippage a quote's minimum may sit and still count as \"at\" it. Providers derive the\n * minimum with their own rounding: LI.FI's Mayan answers land a few base units under an exact floor on 18-decimal\n * outputs (50.0000000001 bps at a requested 50, live 2026-11-02), which refused half of them. A minimum that is more\n * than this past the request is still refused.\n */\nexport const SLIPPAGE_ROUNDING_BPS = 1;\n\n/** The lowest minimum a quote of `dest` may carry at `slippageBps`: floor(dest × (10 000 − slippageBps − {@link SLIPPAGE_ROUNDING_BPS}) / 10 000). */\nexport function slippageFloor(dest: bigint, slippageBps: number): bigint {\n const keep = 10_000 - slippageBps - SLIPPAGE_ROUNDING_BPS;\n return keep <= 0 ? 0n : (dest * BigInt(keep)) / 10_000n;\n}\n\n/** Shared quote validator used by both the aggregate and single-provider paths. */\nexport function validQuote(q: Quote, params: QuoteParams, provider: string): boolean {\n try {\n if (q.provider !== provider || q.sourceAmount !== params.amountIn) return false;\n if (typeof q.intentId !== \"string\" || !q.intentId || typeof q.depositAddress !== \"string\" || (q.depositMemo !== null && typeof q.depositMemo !== \"string\")) return false;\n if (![q.sourceAmount, q.destAmount, q.minDestAmount].every((value) => /^[0-9]+$/.test(value))) return false;\n const source = BigInt(q.sourceAmount);\n const dest = BigInt(q.destAmount);\n const min = BigInt(q.minDestAmount);\n if (source <= 0n || dest <= 0n || min <= 0n || min > dest) return false;\n if (params.minAmountOut !== undefined) {\n if (!/^[0-9]+$/.test(params.minAmountOut) || BigInt(params.minAmountOut) <= 0n || min < BigInt(params.minAmountOut)) return false;\n }\n if (params.slippageBps !== undefined) {\n if (!Number.isInteger(params.slippageBps) || params.slippageBps < 0 || params.slippageBps >= 10_000) return false;\n // Providers round the floor DOWN (1Click, LI.FI: floor(dest × (1 − s))), some through\n // floats. A ceil here refused nearly every slippage-bounded quote by one base unit.\n if (min < slippageFloor(dest, params.slippageBps)) return false;\n }\n if (!Number.isFinite(q.etaSeconds) || q.etaSeconds < 0) return false;\n if (!Number.isFinite(q.reliability) || q.reliability < 0 || q.reliability > 1) return false;\n if (!Number.isFinite(q.feeUsd) || q.feeUsd < 0) return false;\n if (q.fees && (!Array.isArray(q.fees) || !q.fees.every((fee) =>\n [\"network\", \"protocol\", \"affiliate\", \"other\"].includes(fee.type) &&\n /^[0-9]+$/.test(fee.amount) &&\n typeof fee.token === \"string\" && fee.token.length > 0 &&\n typeof fee.included === \"boolean\" &&\n (fee.description === undefined || typeof fee.description === \"string\")\n ))) return false;\n if (q.providerData && (Array.isArray(q.providerData) || typeof q.providerData !== \"object\" || !Object.values(q.providerData).every((value) => typeof value === \"string\"))) return false;\n const tx = q.txRequest;\n if (tx) {\n if (tx.value !== undefined && !/^[0-9]+$/.test(tx.value)) return false;\n if (tx.gasLimit !== undefined && !/^[0-9]+$/.test(tx.gasLimit)) return false;\n if (tx.chainId !== undefined && (!Number.isSafeInteger(tx.chainId) || tx.chainId <= 0)) return false;\n if ([tx.to, tx.data, tx.approvalAddress, tx.serializedTx].some((value) => value !== undefined && typeof value !== \"string\")) return false;\n }\n // Execution is always re-quoted. An unknown/zero expiry cannot prove that\n // the transaction is still safe to sign, so contribution packages reject it.\n if (!Number.isFinite(q.validUntilMs) || q.validUntilMs <= Date.now()) return false;\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Why a remote provider's quote cannot execute in this app, or null: its EVM transaction calls or\n * approves an address the app did not pin (`remoteProvider` `callTargets` / `spenders`), or it pays\n * an address the backend named — a deposit address or a plain value send — on a stub the app did not\n * open to such routes (`depositAddressRoutes`, scan 2026-10-28 F9), or it is EVM calldata on a stub without the\n * app's own check of what that calldata does (`verifyQuote` / `verifyBuild`, scan 2026-10-30 F3). The router and the\n * single-provider path drop such a quote with this reason, so the auction never picks a route\n * execution would refuse (scan 2026-10-27 modules, F8/F9/F16); execution checks the build again, in\n * full. Local providers are not judged here.\n */\nexport function remotePinRefusal(provider: Pick<CrossChainProvider, \"name\" | \"remote\" | \"callTargets\" | \"spenders\" | \"depositAddressRoutes\" | \"verifiesQuotes\" | \"verifiesBuilds\">, q: Quote, chain: string): string | null {\n if (provider.remote !== true) return null;\n const tx = q.txRequest;\n const plain = tx ? tx.data === undefined && tx.serializedTx === undefined : typeof q.depositAddress === \"string\" && q.depositAddress !== \"\";\n if (plain && provider.depositAddressRoutes !== true) {\n return `${provider.name}: the route pays ${tx?.to || q.depositAddress}, an address the backend named, and the app did not allow deposit-address routes for this provider (remoteProvider depositAddressRoutes)`;\n }\n if (!chain.startsWith(\"eip155:\")) return null;\n if (!tx || tx.serializedTx !== undefined) return null;\n const pinned = (list: readonly string[] | undefined, address: string) =>\n (list ?? []).some((a) => typeof a === \"string\" && a.toLowerCase() === address.toLowerCase());\n if (tx.approvalAddress && !pinned(provider.spenders?.(chain), tx.approvalAddress)) {\n return `${provider.name}: the route approves ${tx.approvalAddress}, which the app did not pin as a spender on ${chain} (remoteProvider spenders)`;\n }\n if (tx.data !== undefined && tx.to && !pinned(provider.callTargets?.(chain), tx.to)) {\n return `${provider.name}: the route calls ${tx.to}, which the app did not pin as a call target on ${chain} (remoteProvider callTargets)`;\n }\n if (tx.data !== undefined && provider.verifiesQuotes !== true && provider.verifiesBuilds !== true) {\n return `${provider.name}: the route's calldata is not checked by the app (remoteProvider verifyQuote / verifyBuild) — a pinned target alone does not say whom it pays`;\n }\n return null;\n}\n"],"mappings":"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","names":[]}
|
package/dist/validate.d.cts
CHANGED
|
@@ -1,17 +1,27 @@
|
|
|
1
1
|
import { CrossChainProvider, Quote, QuoteParams } from './types.cjs';
|
|
2
2
|
import '@anywalletkit/core';
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* How far past the requested slippage a quote's minimum may sit and still count as "at" it. Providers derive the
|
|
6
|
+
* minimum with their own rounding: LI.FI's Mayan answers land a few base units under an exact floor on 18-decimal
|
|
7
|
+
* outputs (50.0000000001 bps at a requested 50, live 2026-11-02), which refused half of them. A minimum that is more
|
|
8
|
+
* than this past the request is still refused.
|
|
9
|
+
*/
|
|
10
|
+
declare const SLIPPAGE_ROUNDING_BPS = 1;
|
|
11
|
+
/** The lowest minimum a quote of `dest` may carry at `slippageBps`: floor(dest × (10 000 − slippageBps − {@link SLIPPAGE_ROUNDING_BPS}) / 10 000). */
|
|
12
|
+
declare function slippageFloor(dest: bigint, slippageBps: number): bigint;
|
|
4
13
|
/** Shared quote validator used by both the aggregate and single-provider paths. */
|
|
5
14
|
declare function validQuote(q: Quote, params: QuoteParams, provider: string): boolean;
|
|
6
15
|
/**
|
|
7
16
|
* Why a remote provider's quote cannot execute in this app, or null: its EVM transaction calls or
|
|
8
17
|
* approves an address the app did not pin (`remoteProvider` `callTargets` / `spenders`), or it pays
|
|
9
18
|
* an address the backend named — a deposit address or a plain value send — on a stub the app did not
|
|
10
|
-
* open to such routes (`depositAddressRoutes`, scan 2026-10-28 F9)
|
|
19
|
+
* open to such routes (`depositAddressRoutes`, scan 2026-10-28 F9), or it is EVM calldata on a stub without the
|
|
20
|
+
* app's own check of what that calldata does (`verifyQuote` / `verifyBuild`, scan 2026-10-30 F3). The router and the
|
|
11
21
|
* single-provider path drop such a quote with this reason, so the auction never picks a route
|
|
12
22
|
* execution would refuse (scan 2026-10-27 modules, F8/F9/F16); execution checks the build again, in
|
|
13
23
|
* full. Local providers are not judged here.
|
|
14
24
|
*/
|
|
15
|
-
declare function remotePinRefusal(provider: Pick<CrossChainProvider, "name" | "remote" | "callTargets" | "spenders" | "depositAddressRoutes">, q: Quote, chain: string): string | null;
|
|
25
|
+
declare function remotePinRefusal(provider: Pick<CrossChainProvider, "name" | "remote" | "callTargets" | "spenders" | "depositAddressRoutes" | "verifiesQuotes" | "verifiesBuilds">, q: Quote, chain: string): string | null;
|
|
16
26
|
|
|
17
|
-
export { remotePinRefusal, validQuote };
|
|
27
|
+
export { SLIPPAGE_ROUNDING_BPS, remotePinRefusal, slippageFloor, validQuote };
|
package/dist/validate.d.ts
CHANGED
|
@@ -1,17 +1,27 @@
|
|
|
1
1
|
import { CrossChainProvider, Quote, QuoteParams } from './types.js';
|
|
2
2
|
import '@anywalletkit/core';
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* How far past the requested slippage a quote's minimum may sit and still count as "at" it. Providers derive the
|
|
6
|
+
* minimum with their own rounding: LI.FI's Mayan answers land a few base units under an exact floor on 18-decimal
|
|
7
|
+
* outputs (50.0000000001 bps at a requested 50, live 2026-11-02), which refused half of them. A minimum that is more
|
|
8
|
+
* than this past the request is still refused.
|
|
9
|
+
*/
|
|
10
|
+
declare const SLIPPAGE_ROUNDING_BPS = 1;
|
|
11
|
+
/** The lowest minimum a quote of `dest` may carry at `slippageBps`: floor(dest × (10 000 − slippageBps − {@link SLIPPAGE_ROUNDING_BPS}) / 10 000). */
|
|
12
|
+
declare function slippageFloor(dest: bigint, slippageBps: number): bigint;
|
|
4
13
|
/** Shared quote validator used by both the aggregate and single-provider paths. */
|
|
5
14
|
declare function validQuote(q: Quote, params: QuoteParams, provider: string): boolean;
|
|
6
15
|
/**
|
|
7
16
|
* Why a remote provider's quote cannot execute in this app, or null: its EVM transaction calls or
|
|
8
17
|
* approves an address the app did not pin (`remoteProvider` `callTargets` / `spenders`), or it pays
|
|
9
18
|
* an address the backend named — a deposit address or a plain value send — on a stub the app did not
|
|
10
|
-
* open to such routes (`depositAddressRoutes`, scan 2026-10-28 F9)
|
|
19
|
+
* open to such routes (`depositAddressRoutes`, scan 2026-10-28 F9), or it is EVM calldata on a stub without the
|
|
20
|
+
* app's own check of what that calldata does (`verifyQuote` / `verifyBuild`, scan 2026-10-30 F3). The router and the
|
|
11
21
|
* single-provider path drop such a quote with this reason, so the auction never picks a route
|
|
12
22
|
* execution would refuse (scan 2026-10-27 modules, F8/F9/F16); execution checks the build again, in
|
|
13
23
|
* full. Local providers are not judged here.
|
|
14
24
|
*/
|
|
15
|
-
declare function remotePinRefusal(provider: Pick<CrossChainProvider, "name" | "remote" | "callTargets" | "spenders" | "depositAddressRoutes">, q: Quote, chain: string): string | null;
|
|
25
|
+
declare function remotePinRefusal(provider: Pick<CrossChainProvider, "name" | "remote" | "callTargets" | "spenders" | "depositAddressRoutes" | "verifiesQuotes" | "verifiesBuilds">, q: Quote, chain: string): string | null;
|
|
16
26
|
|
|
17
|
-
export { remotePinRefusal, validQuote };
|
|
27
|
+
export { SLIPPAGE_ROUNDING_BPS, remotePinRefusal, slippageFloor, validQuote };
|
package/dist/validate.js
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
|
+
SLIPPAGE_ROUNDING_BPS,
|
|
2
3
|
remotePinRefusal,
|
|
4
|
+
slippageFloor,
|
|
3
5
|
validQuote
|
|
4
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-F5TRF52T.js";
|
|
5
7
|
export {
|
|
8
|
+
SLIPPAGE_ROUNDING_BPS,
|
|
6
9
|
remotePinRefusal,
|
|
10
|
+
slippageFloor,
|
|
7
11
|
validQuote
|
|
8
12
|
};
|
|
9
13
|
//# sourceMappingURL=validate.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@anywalletkit/protocol-swap2-core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"description": "The swap2 engine for Any Wallet Kit: one interface for swaps and bridges, quote binding, approvals, review gate, fee caps and status resume; providers plug in as separate packages.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"homepage": "https://docs.anywallet.tech",
|
|
@@ -84,17 +84,17 @@
|
|
|
84
84
|
],
|
|
85
85
|
"dependencies": {
|
|
86
86
|
"viem": "^2.45.0",
|
|
87
|
-
"@anywalletkit/
|
|
88
|
-
"@anywalletkit/
|
|
87
|
+
"@anywalletkit/swap2-assets": "0.2.2",
|
|
88
|
+
"@anywalletkit/tx-preview-evm": "0.5.0"
|
|
89
89
|
},
|
|
90
90
|
"peerDependencies": {
|
|
91
|
-
"@anywalletkit/core": "0.
|
|
91
|
+
"@anywalletkit/core": "0.8.0"
|
|
92
92
|
},
|
|
93
93
|
"devDependencies": {
|
|
94
94
|
"@types/node": "^22",
|
|
95
95
|
"vitest": "^5.0.3",
|
|
96
|
-
"@anywalletkit/
|
|
97
|
-
"@anywalletkit/
|
|
96
|
+
"@anywalletkit/conformance": "0.5.0",
|
|
97
|
+
"@anywalletkit/core": "0.8.0"
|
|
98
98
|
},
|
|
99
99
|
"keywords": [
|
|
100
100
|
"anywalletkit"
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/validate.ts"],"sourcesContent":["import type {CrossChainProvider, Quote, QuoteParams} from \"./types.js\";\n\n/** Shared quote validator used by both the aggregate and single-provider paths. */\nexport function validQuote(q: Quote, params: QuoteParams, provider: string): boolean {\n try {\n if (q.provider !== provider || q.sourceAmount !== params.amountIn) return false;\n if (typeof q.intentId !== \"string\" || !q.intentId || typeof q.depositAddress !== \"string\" || (q.depositMemo !== null && typeof q.depositMemo !== \"string\")) return false;\n if (![q.sourceAmount, q.destAmount, q.minDestAmount].every((value) => /^[0-9]+$/.test(value))) return false;\n const source = BigInt(q.sourceAmount);\n const dest = BigInt(q.destAmount);\n const min = BigInt(q.minDestAmount);\n if (source <= 0n || dest <= 0n || min <= 0n || min > dest) return false;\n if (params.minAmountOut !== undefined) {\n if (!/^[0-9]+$/.test(params.minAmountOut) || BigInt(params.minAmountOut) <= 0n || min < BigInt(params.minAmountOut)) return false;\n }\n if (params.slippageBps !== undefined) {\n if (!Number.isInteger(params.slippageBps) || params.slippageBps < 0 || params.slippageBps >= 10_000) return false;\n // Providers round the floor DOWN (1Click, LI.FI: floor(dest × (1 − s))).\n // A ceil here refused nearly every slippage-bounded quote by one base unit.\n const required = (dest * BigInt(10_000 - params.slippageBps)) / 10_000n;\n if (min < required) return false;\n }\n if (!Number.isFinite(q.etaSeconds) || q.etaSeconds < 0) return false;\n if (!Number.isFinite(q.reliability) || q.reliability < 0 || q.reliability > 1) return false;\n if (!Number.isFinite(q.feeUsd) || q.feeUsd < 0) return false;\n if (q.fees && (!Array.isArray(q.fees) || !q.fees.every((fee) =>\n [\"network\", \"protocol\", \"affiliate\", \"other\"].includes(fee.type) &&\n /^[0-9]+$/.test(fee.amount) &&\n typeof fee.token === \"string\" && fee.token.length > 0 &&\n typeof fee.included === \"boolean\" &&\n (fee.description === undefined || typeof fee.description === \"string\")\n ))) return false;\n if (q.providerData && (Array.isArray(q.providerData) || typeof q.providerData !== \"object\" || !Object.values(q.providerData).every((value) => typeof value === \"string\"))) return false;\n const tx = q.txRequest;\n if (tx) {\n if (tx.value !== undefined && !/^[0-9]+$/.test(tx.value)) return false;\n if (tx.gasLimit !== undefined && !/^[0-9]+$/.test(tx.gasLimit)) return false;\n if (tx.chainId !== undefined && (!Number.isSafeInteger(tx.chainId) || tx.chainId <= 0)) return false;\n if ([tx.to, tx.data, tx.approvalAddress, tx.serializedTx].some((value) => value !== undefined && typeof value !== \"string\")) return false;\n }\n // Execution is always re-quoted. An unknown/zero expiry cannot prove that\n // the transaction is still safe to sign, so contribution packages reject it.\n if (!Number.isFinite(q.validUntilMs) || q.validUntilMs <= Date.now()) return false;\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Why a remote provider's quote cannot execute in this app, or null: its EVM transaction calls or\n * approves an address the app did not pin (`remoteProvider` `callTargets` / `spenders`), or it pays\n * an address the backend named — a deposit address or a plain value send — on a stub the app did not\n * open to such routes (`depositAddressRoutes`, scan 2026-10-28 F9). The router and the\n * single-provider path drop such a quote with this reason, so the auction never picks a route\n * execution would refuse (scan 2026-10-27 modules, F8/F9/F16); execution checks the build again, in\n * full. Local providers are not judged here.\n */\nexport function remotePinRefusal(provider: Pick<CrossChainProvider, \"name\" | \"remote\" | \"callTargets\" | \"spenders\" | \"depositAddressRoutes\">, q: Quote, chain: string): string | null {\n if (provider.remote !== true) return null;\n const tx = q.txRequest;\n const plain = tx ? tx.data === undefined && tx.serializedTx === undefined : typeof q.depositAddress === \"string\" && q.depositAddress !== \"\";\n if (plain && provider.depositAddressRoutes !== true) {\n return `${provider.name}: the route pays ${tx?.to || q.depositAddress}, an address the backend named, and the app did not allow deposit-address routes for this provider (remoteProvider depositAddressRoutes)`;\n }\n if (!chain.startsWith(\"eip155:\")) return null;\n if (!tx || tx.serializedTx !== undefined) return null;\n const pinned = (list: readonly string[] | undefined, address: string) =>\n (list ?? []).some((a) => typeof a === \"string\" && a.toLowerCase() === address.toLowerCase());\n if (tx.approvalAddress && !pinned(provider.spenders?.(chain), tx.approvalAddress)) {\n return `${provider.name}: the route approves ${tx.approvalAddress}, which the app did not pin as a spender on ${chain} (remoteProvider spenders)`;\n }\n if (tx.data !== undefined && tx.to && !pinned(provider.callTargets?.(chain), tx.to)) {\n return `${provider.name}: the route calls ${tx.to}, which the app did not pin as a call target on ${chain} (remoteProvider callTargets)`;\n }\n return null;\n}\n"],"mappings":"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","names":[]}
|