@anywalletkit/protocol-swap2-thorchain 0.3.5 → 0.4.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 +84 -0
- package/dist/{chunk-LYJOENYE.js → chunk-EIAXGWNG.js} +521 -106
- package/dist/chunk-EIAXGWNG.js.map +1 -0
- package/dist/{chunk-QLDZS2KO.js → chunk-YKA6IYKX.js} +2 -2
- package/dist/index.cjs +520 -105
- 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 +4 -2
- package/dist/protocol.cjs +448 -79
- package/dist/protocol.cjs.map +1 -1
- package/dist/protocol.js +2 -2
- package/dist/provider.cjs +520 -105
- package/dist/provider.cjs.map +1 -1
- package/dist/provider.d.cts +59 -2
- package/dist/provider.d.ts +59 -2
- package/dist/provider.js +3 -1
- package/package.json +6 -6
- package/dist/chunk-LYJOENYE.js.map +0 -1
- /package/dist/{chunk-QLDZS2KO.js.map → chunk-YKA6IYKX.js.map} +0 -0
package/dist/provider.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/provider.ts","../src/config.ts","../src/activity.ts"],"sourcesContent":["import {thorchain as thorCfg} from \"./config.js\";\nimport {describeThorchainActivity} from \"./activity.js\";\nimport {decodeFunctionData, encodeFunctionData} from \"viem\";\nimport {timeoutSignal} from \"@anywalletkit/protocol-swap2-core/util\";\nimport {ccAsset, ccAssetByToken} from \"@anywalletkit/swap2-assets\";\nimport type {Asset, CrossChainProvider, IntentRef, IntentStatus, Quote, QuoteParams, RemotePins, UnsignedTx} from \"@anywalletkit/protocol-swap2-core/types\";\nimport {bigintToNumber} from \"@anywalletkit/core\";\n\n/**\n * THORChain — native L1 swaps via asgard vaults (no wrapping). Scope here is\n * **EVM sources first**: the user\n * deposits on an EVM chain (Ethereum/Base/BSC/Avalanche) into the THORChain router with\n * `depositWithExpiry(vault, asset, amount, memo, expiry)`; THORChain settles the\n * swap and delivers ETH/stables to our mainnet vault. **Tron** (opt-in,\n * `tronSource`) executes as a native TRX send / TRC-20 transfer to the inbound\n * vault with the memo in `raw_data.data` — bifrost reads that field for both\n * TransferContract and TriggerSmartContract. BTC/Cosmos/Solana sources are not\n * routed yet (no memo-capable send surface).\n *\n * Safety: the MEMO and inbound vault come verbatim from the quote — we never\n * hand-build them (a wrong memo makes funds unrecoverable). The quote\n * embeds an on-chain LIM, so a bad-price swap refunds instead of filling:\n * `liquidity_tolerance_bps` when the caller passes a slippage (LIM = expected\n * output after fees × (1 − slippage)), `tolerance_bps` otherwise.\n *\n * Hosts (re-verified 2026-10-28): two public THORNodes of different operators —\n * Liquify's public GATEWAY (50k req/day per IP; x-client-id identifies us for a\n * bump) and the IBS team's node. Nine Realms retired its hosts, the Liquify\n * vanity hostname serves an expired certificate and thornode.thorchain.network\n * no longer resolves. Hosts are tried in order for the quote, and a quote is\n * bound to an inbound snapshot from the SAME host; the source vault and router\n * must then be confirmed by a SECOND host (scan 2026-10-27 modules, F15): one\n * node's answer is not an authority over where the funds go. The list is an\n * explicit constructor option (`nodeUrl`, one or many, plus `confirmNodeUrl`);\n * this package never reads deployment environment values.\n */\n\nconst HOSTS = [\n \"https://gateway.liquify.com/chain/thorchain_api\",\n \"https://thorchain.ibs.team/api\",\n];\n\n/**\n * THORChain's EVM routers (`depositWithExpiry`), the only contracts an EVM-source swap may call and approve (scan\n * 2026-10-27 modules, F15). Reported identically on 2026-10-28 by both default nodes (two operators) and by every\n * October quote-matrix build. A router migration needs a release or `trustedRouters`; until then a quote naming\n * another router is refused, never followed.\n */\nexport const THORCHAIN_ROUTERS: Readonly<Record<string, readonly string[]>> = Object.freeze({\n \"eip155:1\": Object.freeze([\"0xD37BbE5744D730a1d98d8DC97c42F0Ca46aD7146\"]),\n \"eip155:56\": Object.freeze([\"0xb30eC53F98ff5947EDe720D32aC2da7e52A5f56b\"]),\n \"eip155:43114\": Object.freeze([\"0x00dc6100103BC402d490aEE3F9a5560cBd91f1d4\"]),\n \"eip155:8453\": Object.freeze([\"0x00dc6100103BC402d490aEE3F9a5560cBd91f1d4\"]),\n});\n\nconst DEFAULT_CLIENT_ID = \"anywalletkit\";\n\nconst NATIVE = \"0x0000000000000000000000000000000000000000\";\nconst TOLERANCE_BPS = \"300\"; // 3% max slippage, embedded as an on-chain LIM\n// Two ways to ask THORNode for the LIM:\n// - `liquidity_tolerance_bps` — measured from the expected output AFTER\n// THORChain's fees (liquidity, outbound, affiliate): LIM = expected × (1 −\n// slippage), the floor every other provider quotes and validQuote enforces.\n// Used whenever the caller passes a slippage, in one request.\n// - `tolerance_bps` — measured from the FEELESS spot: LIM = spot × (1 −\n// tolerance), so the room left is (tolerance − fees) and the node rejects\n// the quote outright when fees exceed it (\"emit asset X less than price\n// limit Y\"; 500 USDC Base → BTC at 1% paid ≈1.7%). Kept only for legacy\n// quotes without a slippage, which widen it to what the pool needs.\n// Both are hard-capped: a route whose THORChain fees alone exceed the cap\n// stays hidden, with a named reason.\nconst MAX_TOLERANCE_BPS = 500n;\n/** How long a quote stays executable (bounded by the memo's own expiry). */\nconst QUOTE_VALIDITY_MS = 5 * 60_000;\n\n// CAIP-2 → THORChain chain prefix. EVM chains execute via the router; TRON\n// executes via a native send to the inbound vault + memo (no router).\nconst THOR_CHAIN: Record<string, string> = {\n \"eip155:1\": \"ETH\",\n \"eip155:8453\": \"BASE\",\n \"eip155:56\": \"BSC\",\n // 2026-09-16: AVAX.AVAX/USDC/USDT pools Available (≈$2.5M/$0.3M/$0.2M),\n // router 0x00dc61…f1d4 live in inbound_addresses; same depositWithExpiry ABI.\n // Polygon has no THORChain pool any more — deliberately absent.\n \"eip155:43114\": \"AVAX\",\n \"tron:728126428\": \"TRON\",\n \"bitcoin:mainnet\": \"BTC\",\n // 2026-08 (pools verified live via the Liquify gateway): THORChain added\n // SOL/XRP, and our catalog now carries LTC/DOGE/BCH/ATOM — destination legs\n // for the step-2 off-ramp (source stays EVM/Tron, see supportsRoute).\n \"solana:mainnet\": \"SOL\",\n \"xrp:mainnet\": \"XRP\",\n \"litecoin:mainnet\": \"LTC\",\n \"doge:mainnet\": \"DOGE\",\n \"bch:mainnet\": \"BCH\",\n \"cosmos:cosmoshub-4\": \"GAIA\",\n};\nconst CHAIN_ID: Record<string, number> = {\"eip155:1\": 1, \"eip155:8453\": 8453, \"eip155:56\": 56, \"eip155:43114\": 43114};\nconst TRON_CAIP2 = \"tron:728126428\";\n// Sources executed as a plain send to the inbound vault + memo (no router).\n// Only chains whose account can attach the memo ON-CHAIN belong here; an\n// unsent memo strands the deposit in the vault.\nconst DEPOSIT_SOURCES = new Set([TRON_CAIP2]);\nconst NATIVE_ASSET: Record<string, string> = {\n ETH: \"ETH.ETH\",\n BASE: \"BASE.ETH\",\n BSC: \"BSC.BNB\",\n AVAX: \"AVAX.AVAX\",\n TRON: \"TRON.TRX\",\n BTC: \"BTC.BTC\",\n SOL: \"SOL.SOL\",\n XRP: \"XRP.XRP\",\n LTC: \"LTC.LTC\",\n DOGE: \"DOGE.DOGE\",\n BCH: \"BCH.BCH\",\n GAIA: \"GAIA.ATOM\",\n};\n\n// Curated token asset notation (UPPERCASE contract, as THORChain expects).\n// Pools come and go (all eight verified Available via the Liquify gateway,\n// 2026-09-16); a retired pool's quote just 404s to null, so entries stay harmless.\nconst TOKEN_ASSET: Record<string, string> = {\n \"ETH:USDC\": \"ETH.USDC-0XA0B86991C6218B36C1D19D4A2E9EB0CE3606EB48\",\n \"ETH:USDT\": \"ETH.USDT-0XDAC17F958D2EE523A2206206994597C13D831EC7\",\n \"BASE:USDC\": \"BASE.USDC-0X833589FCD6EDB6E08F4C7C32D4F71B54BDA02913\",\n \"BSC:USDC\": \"BSC.USDC-0X8AC76A51CC950D9822D68B83FE1AD97B32CD580D\",\n \"BSC:USDT\": \"BSC.USDT-0X55D398326F99059FF775485246999027B3197955\",\n \"AVAX:USDC\": \"AVAX.USDC-0XB97EF9EF8734C71904D8002F8B6BC66DD9C48A6E\",\n \"AVAX:USDT\": \"AVAX.USDT-0X9702230A8EA53601F5CD2DC00FDBC13D4DF4A8C7\",\n \"TRON:USDT\": \"TRON.USDT-TR7NHQJEKQXGTCI8Q8ZY4PL8OTSZGJLJ6T\",\n};\n\nconst ROUTER_ABI = [\n {\n type: \"function\",\n name: \"depositWithExpiry\",\n stateMutability: \"payable\",\n inputs: [\n {name: \"vault\", type: \"address\"},\n {name: \"asset\", type: \"address\"},\n {name: \"amount\", type: \"uint256\"},\n {name: \"memo\", type: \"string\"},\n {name: \"expiration\", type: \"uint256\"},\n ],\n outputs: [],\n },\n] as const;\n\nfunction isEvm(caip2: string): boolean {\n return caip2.startsWith(\"eip155:\");\n}\n\n/** THOR asset notation for a (chain, symbol) on either leg, or undefined. */\nfunction thorAsset(caip2: string, symbol: string): string | undefined {\n const chain = THOR_CHAIN[caip2];\n if (!chain) return undefined;\n const sym = symbol.toUpperCase();\n const token = TOKEN_ASSET[`${chain}:${sym}`];\n if (token) return token;\n const native = NATIVE_ASSET[chain];\n return native && native.split(\".\")[1] === sym ? native : undefined;\n}\n\n/**\n * Destination asset for either direction: inbound → the vault on Ethereum, or\n * the step-2 off-ramp → any THOR-supported chain (BTC/BASE/BSC/TRON). Resolved\n * from the catalog so we get the right symbol + decimals for the target chain.\n */\nfunction destAsset(destChain: string, destToken: string): {asset: string; decimals: number} | undefined {\n const a = ccAssetByToken(destChain, destToken);\n if (!a) return undefined;\n const asset = thorAsset(destChain, a.symbol);\n return asset ? {asset, decimals: a.decimals} : undefined;\n}\n\ninterface ThorQuoteResponse {\n expected_amount_out?: string;\n inbound_address?: string;\n router?: string;\n memo?: string;\n expiry?: number;\n total_swap_seconds?: number;\n /** 1e8 source units; below this the swap is refunded minus fees. */\n recommended_min_amount_in?: string;\n error?: string;\n /** thornode simulation rejections arrive as {code, message}. */\n message?: string;\n /** THORChain's fees on this quote; `total_bps` includes liquidity, outbound and affiliate. */\n fees?: {total_bps?: number};\n}\n\n/**\n * A host-level failure (unreachable, gateway error, rate-limited, blocked):\n * the next host may answer. Anything else the node says — including a 4xx\n * business rejection such as \"no pool\" — is an answer, not a reason to shop\n * the same question to another node.\n */\nclass HostUnavailable extends Error {\n constructor(host: string, reason: string) {\n super(`thorchain: ${host} unavailable (${reason})`);\n }\n}\n\ninterface HostResponse {\n ok: boolean;\n status: number;\n body: Record<string, unknown> | unknown[] | null;\n}\n\nasync function hostGet(host: string, path: string, clientId: string, signal?: AbortSignal): Promise<HostResponse> {\n let res: Response;\n try {\n res = await fetch(`${host}${path}`, {\n headers: {accept: \"application/json\", \"x-client-id\": clientId},\n cache: \"no-store\",\n signal: signal ?? timeoutSignal(8000),\n });\n } catch (error) {\n if (signal?.aborted) throw error; // the caller gave up — not the host's fault\n throw new HostUnavailable(host, error instanceof Error ? error.message : \"fetch failed\");\n }\n if (res.status >= 500 || res.status === 429 || res.status === 403) {\n throw new HostUnavailable(host, `HTTP ${res.status}`);\n }\n const body = (await res.json().catch(() => null)) as HostResponse[\"body\"];\n return {ok: res.ok, status: res.status, body};\n}\n\n/** Per-request failover for reads whose answer is host-independent (tx status). */\nasync function thornodeGet(\n path: string,\n signal: AbortSignal | undefined,\n hosts: string[],\n clientId: string,\n): Promise<Record<string, unknown> | null> {\n for (const host of hosts) {\n try {\n const res = await hostGet(host, path, clientId, signal);\n if (!res.ok) continue;\n return Array.isArray(res.body) ? null : res.body;\n } catch (error) {\n if (error instanceof HostUnavailable) continue;\n throw error;\n }\n }\n return null;\n}\n\ninterface InboundAddress {\n chain?: string;\n address?: string;\n router?: string;\n halted?: boolean;\n global_trading_paused?: boolean;\n chain_trading_paused?: boolean;\n /** 1e8 source units; inbounds at or below it are IGNORED by THORChain. */\n dust_threshold?: string;\n}\n\n/** Fail closed on amounts THORChain would ignore (dust) or refund (below the\n * recommended minimum). Both are quoted in 1e8 source units. */\nfunction belowThorMinimums(amount1e8: bigint, inbound: InboundAddress | undefined, quote: ThorQuoteResponse | null): string | null {\n const dust = inbound?.dust_threshold;\n if (dust !== undefined && (!/^\\d+$/.test(String(dust)) || amount1e8 <= BigInt(dust))) return \"amount at or below THORChain dust threshold\";\n const min = quote?.recommended_min_amount_in;\n if (min !== undefined && (!/^\\d+$/.test(String(min)) || amount1e8 < BigInt(min))) return \"amount below THORChain recommended minimum\";\n return null;\n}\n\n/** Inbound snapshot from ONE host. Throws HostUnavailable so the caller can\n * re-run the whole quote on the next host rather than mixing nodes. */\nasync function inboundAddressesOn(host: string, clientId: string): Promise<InboundAddress[]> {\n const res = await hostGet(host, \"/thorchain/inbound_addresses\", clientId);\n if (!res.ok || !Array.isArray(res.body)) throw new HostUnavailable(host, `inbound_addresses HTTP ${res.status}`);\n return res.body as InboundAddress[];\n}\n\nfunction paused(entry: InboundAddress | undefined): boolean {\n return !entry || entry.halted === true || entry.global_trading_paused === true || entry.chain_trading_paused === true;\n}\n\nfunction sameTarget(a: string | undefined, b: string | undefined): boolean {\n if (!a || !b) return false;\n return a.startsWith(\"0x\") || b.startsWith(\"0x\") ? a.toLowerCase() === b.toLowerCase() : a === b;\n}\n\nfunction verifiedMemo(\n memo: string,\n expectedAsset: string,\n expectedDestination: string,\n expectedRefund: string,\n expectedAffiliate: string,\n expectedAffiliateBps: string,\n): {limit: bigint; canonical: string} | null {\n if (memo.includes(\"|\")) return null; // DEX-aggregator tail is a separate, unbound execution program.\n const parts = memo.split(\":\");\n if (parts.length !== 4 && parts.length !== 6) return null;\n const [op, asset, destination, limit, affiliate, bps] = parts;\n // Quote responses legitimately use THORChain fuzzy asset notation (`b` for\n // BTC.BTC). We never execute that untrusted spelling: after checking the\n // shape, destination/refund, limit and affiliate we rebuild a canonical memo\n // from our own route facts below.\n if (op !== \"=\" || !asset || !/^[A-Za-z0-9._~\\-]+$/.test(asset)) return null;\n const expectedTarget = expectedRefund ? `${expectedDestination}/${expectedRefund}` : expectedDestination;\n if (!sameTarget(destination, expectedTarget)) return null;\n if (parts.length === 6) {\n if (!expectedAffiliate || affiliate !== expectedAffiliate || bps !== expectedAffiliateBps) return null;\n } else if (expectedAffiliate || expectedAffiliateBps) {\n return null;\n }\n const stream = (limit ?? \"\").split(\"/\");\n // We never request streaming swaps. A provider-supplied LIM/INTERVAL/QTY\n // memo changes the floor to a per-sub-swap condition, so reject it instead\n // of presenting LIM as an atomic total guarantee.\n if (stream.length !== 1 || stream.some((v) => !/^\\d+$/.test(v))) return null;\n const floor = BigInt(stream[0] ?? \"0\");\n if (floor <= 0n) return null;\n const canonical = `=:${expectedAsset}:${expectedTarget}:${stream.join(\"/\")}${\n expectedAffiliate ? `:${expectedAffiliate}:${expectedAffiliateBps}` : \"\"\n }`;\n return {limit: floor, canonical};\n}\n\nfunction toThorUnitsCeil(amount: bigint, decimals: number): bigint {\n const scale = 10n ** BigInt(decimals);\n return (amount * 100_000_000n + scale - 1n) / scale;\n}\n\n/** Explicit constructor configuration; no deployment environment is read. */\nexport interface ThorchainProviderConfig {\n enabled?: boolean;\n affiliate?: string;\n affiliateBps?: string;\n /**\n * THORNode base URL(s), tried in order; a comma-separated string is\n * accepted for env-style configuration. Defaults to the documented public\n * hosts. Quote + inbound snapshot always come from the same host.\n */\n nodeUrl?: string | string[];\n /**\n * Nodes that confirm the source vault and router a quote names (scan 2026-10-27 modules, F15): another host must\n * report the same before a quote is used and again right before broadcast; a disagreeing or silent second source\n * refuses. Default: the other `nodeUrl` hosts, else the default public nodes. Name a node of another operator.\n */\n confirmNodeUrl?: string | string[];\n /** Routers to trust besides {@link THORCHAIN_ROUTERS}, per CAIP-2 chain (a router migration before a release). */\n trustedRouters?: Readonly<Record<string, readonly string[]>>;\n /** Allow `http:` node URLs (local development only): the vault and router a swap pays come from them. */\n allowInsecureNodeUrl?: boolean;\n /** Optional gateway identification; defaults to a neutral module name. */\n clientId?: string;\n /**\n * Opt-in Tron SOURCE execution: a native TRX send / TRC-20 transfer to the\n * inbound vault carrying the swap memo in `raw_data.data`. Ships dark: the\n * bound account MUST attach the memo on-chain (`raw_data.data`); a\n * memo-less send is unsettleable.\n */\n tronSource?: boolean;\n}\n\n/**\n * The app's side of a remote THORChain stub (scan 2026-10-27 modules, F15): `remoteProvider({name: \"thorchain\",\n * baseUrl, ...thorchainPins()})`. The pinned routers are the only call targets and spenders, and `verifyBuild` checks\n * the build on the client: the vault in the router call (or the Tron deposit's recipient) confirmed by two THORNodes\n * of different operators, the source asset and exact input, and the memo's asset, destination, refund and limit\n * against the app's own request. Pass the affiliate your backend's provider uses (the memo must carry exactly it).\n * The Tron deposit route is open (`depositAddressRoutes`): its vault is the one `verifyBuild` confirms.\n */\nexport function thorchainPins(opts: {\n nodeUrl?: string | string[];\n affiliate?: string;\n affiliateBps?: string;\n trustedRouters?: Readonly<Record<string, readonly string[]>>;\n clientId?: string;\n} = {}): RemotePins & {verifyBuild(quote: Quote, tx: UnsignedTx, params?: QuoteParams): Promise<string | null>} {\n const nodes = [...new Set((Array.isArray(opts.nodeUrl) ? opts.nodeUrl : opts.nodeUrl ? opts.nodeUrl.split(\",\") : HOSTS).map((h) => h.trim().replace(/\\/$/, \"\")).filter(Boolean))];\n for (const n of nodes) if (!/^https:\\/\\//i.test(n)) throw new Error(\"thorchain: thorchainPins nodeUrl must use https\");\n const clientId = opts.clientId?.trim() || DEFAULT_CLIENT_ID;\n const routersFor = (chain: string): readonly string[] => [...(THORCHAIN_ROUTERS[chain] ?? []), ...(opts.trustedRouters?.[chain] ?? [])];\n return Object.freeze({\n callTargets: routersFor,\n spenders: routersFor,\n // A Tron source is a send to the inbound vault; verifyBuild confirms that vault with two THORNodes (scan 2026-10-28 F9).\n depositAddressRoutes: true,\n async verifyBuild(quote: Quote, tx: UnsignedTx, params?: QuoteParams): Promise<string | null> {\n if (!params) return \"the request this quote answered is unknown\";\n const src = ccAsset(params.sourceChain, params.sourceToken);\n const dst = destAsset(params.destChain, params.destToken);\n if (!src || !dst) return \"unknown source or destination asset\";\n const chainId = CHAIN_ID[params.sourceChain];\n let vault: string, memo: string, router: string | undefined;\n if (chainId) {\n if (!tx.data) return \"no router calldata\";\n let args: readonly unknown[] | undefined;\n try {\n const d = decodeFunctionData({abi: ROUTER_ABI, data: tx.data as `0x${string}`});\n if (d.functionName !== \"depositWithExpiry\") return `${d.functionName} is not depositWithExpiry`;\n args = d.args;\n } catch { return \"the router calldata does not decode\"; }\n if (!args || args.length !== 5) return \"the router calldata does not decode\";\n router = tx.to;\n if (!routersFor(params.sourceChain).some((r) => sameTarget(r, router))) return `router ${tx.to} is not pinned`;\n vault = String(args[0]);\n const asset = String(args[1]);\n if (!sameTarget(asset, src.contract ?? NATIVE)) return `the router call moves ${asset}, not the source asset`;\n if (BigInt(args[2] as bigint) !== BigInt(quote.sourceAmount)) return `the router call moves ${String(args[2])}, not the ${quote.sourceAmount} input`;\n memo = String(args[3]);\n } else {\n // A deposit source (Tron): a plain send of the input to the vault with the memo.\n if (!tx.memo || tx.value !== quote.sourceAmount) return \"the deposit is not a send of the input with a memo\";\n vault = tx.to;\n memo = tx.memo;\n }\n const checked = verifiedMemo(memo, dst.asset, params.destAddress, params.refundAddress ?? \"\", opts.affiliate ?? \"\", opts.affiliateBps ?? \"\");\n if (!checked) return `the memo does not pay ${params.destAddress} in ${dst.asset} with this app's refund and affiliate`;\n // The server's provider signs only the canonical memo it rebuilds from route facts, so the build must be that\n // memo byte for byte: a fuzzy or swapped output asset (scan 2026-10-30 F2) is refused here.\n if (memo !== checked.canonical) return `the memo is not the canonical ${checked.canonical}`;\n if ((checked.limit * 10n ** BigInt(dst.decimals)) / 100_000_000n < BigInt(quote.minDestAmount)) return `the memo's limit ${checked.limit} is below the quoted minimum`;\n // Two nodes of different operators must report this vault (and router), trading open.\n let agreeing = 0;\n for (const host of nodes) {\n let entries: InboundAddress[];\n try { entries = await inboundAddressesOn(host, clientId); } catch (error) { if (error instanceof HostUnavailable) continue; throw error; }\n const entry = entries.find((e) => e.chain === THOR_CHAIN[params.sourceChain]);\n if (paused(entry)) return `${THOR_CHAIN[params.sourceChain]} is halted / paused`;\n if (!sameTarget(entry?.address, vault)) return `a THORNode reports another inbound vault than ${vault}`;\n if (router !== undefined && !sameTarget(entry?.router, router)) return \"a THORNode reports another router\";\n if (++agreeing >= 2) return null;\n }\n return \"two THORNodes could not confirm the inbound vault\";\n },\n });\n}\n\nexport function thorchainProvider(config: ThorchainProviderConfig = {}): CrossChainProvider {\n config = Object.freeze({...config});\n const configuredHosts = (Array.isArray(config.nodeUrl) ? config.nodeUrl : (config.nodeUrl ?? \"\").split(\",\"))\n .map((h) => h.trim())\n .filter(Boolean);\n const hosts = [...new Set((configuredHosts.length ? configuredHosts : HOSTS).map((h) => {\n let url: URL;\n try {\n url = new URL(h);\n } catch {\n throw new Error(\"thorchain: nodeUrl must be an absolute http(s) URL\");\n }\n if (url.protocol !== \"https:\" && !(url.protocol === \"http:\" && config.allowInsecureNodeUrl === true)) {\n throw new Error(\"thorchain: nodeUrl must use https (allowInsecureNodeUrl for local development)\");\n }\n return url.toString().replace(/\\/$/, \"\");\n }))];\n const parseHosts = (input: string | string[] | undefined): string[] => (Array.isArray(input) ? input : (input ?? \"\").split(\",\"))\n .map((h) => h.trim()).filter(Boolean).map((h) => {\n let url: URL;\n try { url = new URL(h); } catch { throw new Error(\"thorchain: confirmNodeUrl must be an absolute https URL\"); }\n if (url.protocol !== \"https:\" && !(url.protocol === \"http:\" && config.allowInsecureNodeUrl === true)) throw new Error(\"thorchain: confirmNodeUrl must use https\");\n return url.toString().replace(/\\/$/, \"\");\n });\n const confirmHosts = [...new Set([...parseHosts(config.confirmNodeUrl), ...hosts, ...HOSTS])];\n const routers = new Map<string, Set<string>>();\n for (const [chain, list] of [...Object.entries(THORCHAIN_ROUTERS), ...Object.entries(config.trustedRouters ?? {})]) {\n const set = routers.get(chain) ?? new Set<string>();\n for (const r of list) {\n if (!/^0x[0-9a-fA-F]{40}$/.test(r)) throw new Error(`thorchain: trusted router for ${chain} is not an EVM address`);\n set.add(r.toLowerCase());\n }\n routers.set(chain, set);\n }\n const pinnedRouter = (chain: string, router: string | undefined) => !!router && routers.get(chain)?.has(router.toLowerCase()) === true;\n /**\n * A second node's view of the source chain, from a host other than `quoteHost`: the vault (and router) it reports\n * must be the quote's, and trading open. The reason it fails, or null.\n */\n const confirmedElsewhere = async (quoteHost: string, chain: string, vault: string, router: string | undefined): Promise<string | null> => {\n for (const host of confirmHosts) {\n if (host === quoteHost) continue;\n let entries: InboundAddress[];\n try { entries = await inboundAddressesOn(host, clientId); } catch (error) { if (error instanceof HostUnavailable) continue; throw error; }\n const entry = entries.find((e) => e.chain === THOR_CHAIN[chain]);\n if (paused(entry)) return `${THOR_CHAIN[chain]} is halted / paused on the confirming node`;\n if (!sameTarget(entry?.address, vault)) return \"a second node reports another inbound vault — refused until they agree\";\n if (router !== undefined && !sameTarget(entry?.router, router)) return \"a second node reports another router — refused until they agree\";\n return null;\n }\n return \"no second node answered to confirm the inbound vault (configure confirmNodeUrl)\";\n };\n const configuredAffiliate = config.affiliate ?? \"\";\n const configuredAffiliateBps = config.affiliateBps ?? \"\";\n if (!!configuredAffiliate !== !!configuredAffiliateBps) {\n throw new Error(\"thorchain: affiliate and affiliateBps must be configured together\");\n }\n if (configuredAffiliate && !/^[A-Za-z0-9._~-]+$/.test(configuredAffiliate)) {\n throw new Error(\"thorchain: affiliate contains unsupported memo characters\");\n }\n if (configuredAffiliateBps && (!/^\\d+$/.test(configuredAffiliateBps) || BigInt(configuredAffiliateBps) > 10_000n)) {\n throw new Error(\"thorchain: affiliateBps must be an integer between 0 and 10000\");\n }\n const clientId = config.clientId?.trim() || DEFAULT_CLIENT_ID;\n if (!/^[\\x21-\\x7e]{1,128}$/.test(clientId)) throw new Error(\"thorchain: clientId must contain 1-128 visible ASCII characters\");\n const tronSource = config.tronSource === true;\n const isDepositSource = (caip2: string): boolean => tronSource && DEPOSIT_SOURCES.has(caip2);\n return {\n name: \"thorchain\",\n describeActivity: describeThorchainActivity,\n enabled: () => config.enabled ?? true,\n\n // Capability discovery comes from the provider itself, so it can run alone\n // or inside the optional aggregator without a central capability table.\n supportsChain: (chain: string) => thorCfg.supportsChain(chain),\n supportsChainPair: (fromChain: string, toChain: string) => thorCfg.supports(fromChain, toChain),\n // Inbound: EVM/Tron source → the mainnet vault. Outbound (step-2 off-ramp):\n // EVM source (Ethereum) → any THOR-supported chain. The SOURCE must be EVM\n // (router calldata) or, when opted in, Tron (send + memo); both legs must\n // be THOR chains and differ.\n supportsRoute(from: Asset, to: Asset): boolean {\n const srcExec = isEvm(from.chain) || isDepositSource(from.chain);\n if (!(srcExec && !!THOR_CHAIN[from.chain] && !!THOR_CHAIN[to.chain] && from.chain !== to.chain)) return false;\n // Asset level too: claiming a chain pair whose assets THORChain has no\n // pool for (e.g. USDC on Solana) put the provider in every route list\n // and then answered a silent null.\n const fromAsset = thorAsset(from.chain, from.token) ?? thorAsset(from.chain, ccAssetByToken(from.chain, from.token)?.symbol ?? \"\");\n const toAsset = destAsset(to.chain, to.token) ?? (thorAsset(to.chain, to.token) ? {asset: thorAsset(to.chain, to.token)!} : undefined);\n return !!fromAsset && !!toAsset && fromAsset !== toAsset.asset;\n },\n\n async getQuote(params: QuoteParams, signal?: AbortSignal): Promise<Quote | null> {\n if (!(config.enabled ?? true)) return null;\n if (params.flex) return null; // memo/LIM embed the exact amount\n const chainId = CHAIN_ID[params.sourceChain];\n // EVM sources execute via the router; opted-in deposit sources (Tron)\n // via send + memo. Anything else has no safe executor.\n if (!chainId && !isDepositSource(params.sourceChain)) return null;\n if (params.sourceChain === params.destChain) return null; // same-chain: not a swap\n\n const src = ccAsset(params.sourceChain, params.sourceToken);\n const fromAsset = thorAsset(params.sourceChain, params.sourceToken);\n const dst = destAsset(params.destChain, params.destToken);\n if (!src || !fromAsset || !dst || fromAsset === dst.asset) {\n params.onRefusal?.(`thorchain: no pool for ${params.sourceToken} on ${params.sourceChain} → ${params.destToken} on ${params.destChain}`);\n return null;\n }\n\n // THORChain amounts are universally 1e8-scaled.\n const amountIn = BigInt(params.amountIn);\n const amount1e8 = (amountIn * 100000000n) / 10n ** BigInt(src.decimals);\n if (amount1e8 <= 0n) return null;\n // THOR quotes only 1e8 units. Never send a larger high-precision source\n // amount than the amount priced by the quote (the remainder is dust the\n // memo cannot account for and may be donated to the vault).\n if (amount1e8 * 10n ** BigInt(src.decimals) !== amountIn * 100_000_000n) {\n params.onRefusal?.(`thorchain: amount has more precision than THORChain's 8 decimals — round it to 8 decimals`);\n return null;\n }\n\n const requestedTolerance = params.slippageBps ?? Number(TOLERANCE_BPS);\n if (!Number.isInteger(requestedTolerance) || requestedTolerance < 0 || requestedTolerance > bigintToNumber(MAX_TOLERANCE_BPS)) {\n params.onRefusal?.(`thorchain: slippage ${String(params.slippageBps)} bps is outside 0–${MAX_TOLERANCE_BPS} bps`);\n return null;\n }\n // An explicit slippage → `liquidity_tolerance_bps`. The node floors LIM in\n // 1e8 units; for a destination with more than 8 decimals that floor lands\n // a hair below expected × (1 − slippage) in base units, so ask 1 bp\n // tighter there (never looser). 0 bp cannot carry a LIM that way: such a\n // request goes out as `tolerance_bps` and the node's answer stands.\n const explicitSlippage = params.slippageBps !== undefined;\n const liquidityBps = explicitSlippage ? (dst.decimals > 8 ? requestedTolerance - 1 : requestedTolerance) : 0;\n const limitMode = liquidityBps > 0 ? \"liquidity_tolerance_bps\" : \"tolerance_bps\";\n // `tolerance_bps` → LIM from the feeless spot output; `liquidity_tolerance_bps`\n // → LIM from the expected output after fees (the node accepts only one).\n const quoteOn = async (\n host: string,\n bps: string,\n limitMode: \"tolerance_bps\" | \"liquidity_tolerance_bps\" = \"tolerance_bps\",\n ): Promise<ThorQuoteResponse | null> => {\n const qs = new URLSearchParams({\n from_asset: fromAsset,\n to_asset: dst.asset,\n amount: amount1e8.toString(),\n destination: params.destAddress,\n [limitMode]: bps,\n // Pin a single (non-streaming) swap. Left to itself the node picks\n // streaming for thin pools (max_streaming_quantity > 1) and then\n // simulates the LIM per sub-swap — the adaptive retry could never\n // pass on BASE.ETH / BSC stables (verified 2026-09-16). We reject\n // streaming memos anyway, so the quote must be simulated atomically.\n streaming_quantity: \"1\",\n });\n if (configuredAffiliate && configuredAffiliateBps) {\n qs.set(\"affiliate\", configuredAffiliate);\n qs.set(\"affiliate_bps\", configuredAffiliateBps);\n }\n if (params.refundAddress) qs.set(\"refund_address\", params.refundAddress);\n const res = await hostGet(host, `/thorchain/quote/swap?${qs.toString()}`, clientId, signal);\n if (Array.isArray(res.body)) return null;\n // A 4xx carries the node's rejection body (used by the adaptive retry).\n return (res.body ?? (res.ok ? null : {error: `HTTP ${res.status}`})) as ThorQuoteResponse | null;\n };\n\n // Host failover: the quote AND the inbound snapshot it is bound to must\n // come from one node. If either call fails at the host level, the whole\n // pair is re-run on the next host; a node's business rejection is final.\n let q: ThorQuoteResponse | null = null;\n let checkedMemo: ReturnType<typeof verifiedMemo> = null;\n let inbounds: InboundAddress[] | null = null;\n let quoteHost = \"\";\n for (const host of hosts) {\n try {\n if (limitMode === \"liquidity_tolerance_bps\") {\n q = await quoteOn(host, String(liquidityBps), \"liquidity_tolerance_bps\");\n const feeBps = Number(q?.fees?.total_bps);\n if (Number.isFinite(feeBps) && feeBps > bigintToNumber(MAX_TOLERANCE_BPS)) {\n // Dust amounts: a fixed outbound fee eats the swap.\n params.onRefusal?.(`thorchain: THORChain fees ${(feeBps / 100).toFixed(2)}% — too expensive at this amount (cap ${bigintToNumber(MAX_TOLERANCE_BPS) / 100}%)`);\n return null;\n }\n } else {\n q = await quoteOn(host, String(requestedTolerance));\n // Legacy quotes without a slippage: fees > tolerance makes the node\n // reject the quote; the rejection carries the actual emit vs the\n // limit the tolerance implied. ONE retry, on the same host, widens\n // the tolerance to what the pool needs (+buffer), capped. An\n // explicit 0 bp slippage is never widened — the rejection stands.\n const rejected = (q?.error ?? q?.message)?.match(/emit asset (\\d+) less than price limit (\\d+)/);\n if (rejected && !explicitSlippage) {\n const emit = BigInt(rejected[1] ?? \"0\");\n const limit = BigInt(rejected[2] ?? \"0\");\n if (emit > 0n && limit > emit) {\n // limit = spot × (1 − tolerance/10000) → spot; needed = 1 − emit/spot.\n const spot = (limit * 10000n) / (10000n - BigInt(requestedTolerance));\n const needed = 10000n - (emit * 10000n) / spot + 50n; // +0.5% buffer\n if (needed <= MAX_TOLERANCE_BPS) q = await quoteOn(host, needed.toString());\n }\n }\n }\n // Validate the node's answer BEFORE touching the network again: a\n // rejection, a malformed quote or an unbound memo is final.\n if (q?.error || q?.message) {\n // The node's own rejection (no pool, price limit, halted…) is the\n // caller's answer — surface it instead of an anonymous null.\n params.onRefusal?.(`thorchain: ${String(q.error ?? q.message).slice(0, 200)}`);\n return null;\n }\n if (!q || !q.expected_amount_out || !q.inbound_address || !q.memo || !q.expiry) {\n params.onRefusal?.(`thorchain: incomplete quote from ${host} (expected_amount_out / inbound_address / memo / expiry missing)`);\n return null;\n }\n // A router is required for EVM and must be ABSENT for a deposit\n // source: a router on a Tron quote means the venue changed its\n // execution model and a plain send would no longer settle.\n if (chainId ? !q.router : !!q.router) {\n params.onRefusal?.(chainId ? \"thorchain: quote has no router for an EVM source\" : \"thorchain: quote names a router for a deposit source — execution model changed\");\n return null;\n }\n checkedMemo = verifiedMemo(q.memo, dst.asset, params.destAddress, params.refundAddress ?? \"\", configuredAffiliate, configuredAffiliateBps);\n if (!checkedMemo) {\n params.onRefusal?.(`thorchain: memo failed verification (${String(q.memo).slice(0, 80)})`);\n return null;\n }\n const floor1e8 = params.minAmountOut !== undefined ? toThorUnitsCeil(BigInt(params.minAmountOut), dst.decimals) : undefined;\n if (floor1e8 !== undefined && checkedMemo.limit < floor1e8) {\n params.onRefusal?.(`thorchain: floor breach (limit=${checkedMemo.limit} < floor=${floor1e8}, 1e8 units)`);\n return null;\n }\n // A quote gateway is not an authority for rotating vault/router\n // state. Bind it against a separately fetched no-store inbound\n // snapshot from the SAME host now, then repeat the check before broadcast.\n inbounds = await inboundAddressesOn(host, clientId);\n quoteHost = host;\n break;\n } catch (error) {\n if (error instanceof HostUnavailable) {\n q = null;\n checkedMemo = null;\n inbounds = null;\n continue;\n }\n throw error;\n }\n }\n if (!q?.expected_amount_out || !q.inbound_address || !q.expiry || !checkedMemo || !inbounds) {\n params.onRefusal?.(!inbounds ? \"thorchain: inbound addresses unavailable from every node\" : \"thorchain: no quote from any node\");\n return null;\n }\n const limit1e8 = checkedMemo.limit;\n const srcInbound = inbounds.find((entry) => entry.chain === THOR_CHAIN[params.sourceChain]);\n const dstInbound = inbounds.find((entry) => entry.chain === THOR_CHAIN[params.destChain]);\n if (paused(srcInbound) || paused(dstInbound)) {\n params.onRefusal?.(`thorchain: ${paused(srcInbound) ? THOR_CHAIN[params.sourceChain] : THOR_CHAIN[params.destChain]} chain is halted / paused on THORChain`);\n return null;\n }\n if (!sameTarget(srcInbound?.address, q.inbound_address)) {\n params.onRefusal?.(\"thorchain: quote inbound address differs from the node's current inbound (vault rotated) — retry\");\n return null;\n }\n if (chainId && !sameTarget(srcInbound?.router, q.router)) {\n params.onRefusal?.(\"thorchain: quote router differs from the node's current router — retry\");\n return null;\n }\n if (chainId && !pinnedRouter(params.sourceChain, q.router)) {\n params.onRefusal?.(`thorchain: router ${String(q.router)} is not a THORChain router this module trusts on ${params.sourceChain} (THORCHAIN_ROUTERS / trustedRouters)`);\n return null;\n }\n const unconfirmed = await confirmedElsewhere(quoteHost, params.sourceChain, q.inbound_address, chainId ? q.router : undefined);\n if (unconfirmed) {\n params.onRefusal?.(`thorchain: ${unconfirmed}`);\n return null;\n }\n const tooSmall = belowThorMinimums(amount1e8, srcInbound, q);\n if (tooSmall) {\n params.onRefusal?.(`thorchain: ${tooSmall}`);\n return null;\n }\n\n // expected_amount_out is 1e8 of the DEST asset → base units.\n const outUnits = (BigInt(q.expected_amount_out) * 10n ** BigInt(dst.decimals)) / 100000000n;\n if (outUnits <= 0n) {\n params.onRefusal?.(\"thorchain: expected output rounds to zero\");\n return null;\n }\n const memoMinUnits = (limit1e8 * 10n ** BigInt(dst.decimals)) / 100_000_000n;\n const minUnits = memoMinUnits;\n if (minUnits <= 0n || minUnits > outUnits) {\n params.onRefusal?.(`thorchain: memo limit ${limit1e8} inconsistent with expected output ${q.expected_amount_out}`);\n return null;\n }\n // The caller's slippage is measured from the quoted output, as validQuote\n // does for every provider. A memo LIM below that floor would only be\n // dropped later as an anonymous validation failure — name it here.\n if (params.slippageBps !== undefined) {\n const slippageFloor = (outUnits * BigInt(10_000 - params.slippageBps)) / 10_000n;\n if (minUnits < slippageFloor) {\n params.onRefusal?.(`thorchain: memo limit ${limit1e8} is below expected ${q.expected_amount_out} minus ${params.slippageBps} bps slippage (1e8 units)`);\n return null;\n }\n }\n\n const nowSeconds = Math.floor(Date.now() / 1000);\n const executionExpiry = Math.min(q.expiry, nowSeconds + 15 * 60);\n if (!Number.isInteger(executionExpiry) || executionExpiry <= nowSeconds + 30) {\n params.onRefusal?.(`thorchain: quote expires in ${Number.isInteger(executionExpiry) ? executionExpiry - nowSeconds : \"?\"} s — too soon to execute`);\n return null;\n }\n const assetAddr = (src.contract ? src.contract : NATIVE) as `0x${string}`;\n const common = {\n provider: \"thorchain\",\n intentId: `thorchain:${chainId ?? THOR_CHAIN[params.sourceChain]}`,\n sourceAmount: params.amountIn,\n destAmount: outUnits.toString(),\n minDestAmount: minUnits.toString(),\n feeUsd: 0, // destAmount is already net of THORChain fees\n etaSeconds: q.total_swap_seconds ?? 120,\n reliability: 0.9,\n // Validity must outlive the ERC-20 approval leg: for USDT that is\n // approve(0) + approve(n), each awaited to inclusion (≈2 blocks), so a\n // 60 s window expired before the deposit and only the revoke went out\n // (2026-09-16). The on-chain LIM bounds price movement and preflight\n // re-checks vault/router/halts right before broadcast, so a longer\n // window costs nothing in safety.\n validUntilMs: Math.min(Date.now() + QUOTE_VALIDITY_MS, executionExpiry * 1000),\n providerData: {\n sourceChain: params.sourceChain,\n destChain: params.destChain,\n inboundAddress: q.inbound_address,\n router: q.router ?? \"\",\n assetAddress: assetAddr,\n expiry: String(executionExpiry),\n memo: checkedMemo.canonical,\n },\n };\n\n // Deposit source (Tron): the engine sends `sourceAmount` of the source\n // asset to the inbound vault with the canonical memo attached on-chain.\n if (!chainId) {\n return {...common, depositAddress: q.inbound_address, depositMemo: checkedMemo.canonical};\n }\n\n // EVM: router calldata depositWithExpiry(asgardVault, asset, amount, memo, expiry).\n const data = encodeFunctionData({\n abi: ROUTER_ABI,\n functionName: \"depositWithExpiry\",\n args: [q.inbound_address as `0x${string}`, assetAddr, amountIn, checkedMemo.canonical, BigInt(executionExpiry)],\n });\n return {\n ...common,\n depositAddress: \"\",\n depositMemo: null,\n txRequest: {\n to: q.router!,\n data,\n value: src.contract ? \"0\" : params.amountIn,\n chainId: chainId!,\n ...(src.contract ? {approvalAddress: q.router!} : {}),\n },\n };\n },\n\n async buildDeposit(quote: Quote): Promise<UnsignedTx> {\n if (!quote.txRequest) {\n const sourceChain = quote.providerData?.sourceChain ?? \"\";\n if (!isDepositSource(sourceChain) || !quote.depositAddress || !quote.depositMemo) {\n throw new Error(\"thorchain: deposit-address execution is only supported for an opted-in Tron source\");\n }\n // Plain send to the inbound vault (the engine turns a TRC-20 source\n // into transfer()); the memo MUST ride on-chain in raw_data.data.\n return {chain: sourceChain, to: quote.depositAddress, value: quote.sourceAmount, memo: quote.depositMemo};\n }\n return {\n chain: \"\",\n to: quote.txRequest?.to ?? \"\",\n value: quote.txRequest?.value ?? \"0\",\n ...(quote.txRequest?.data ? {data: quote.txRequest.data} : {}),\n ...(quote.txRequest?.chainId !== undefined ? {chainId: quote.txRequest.chainId} : {}),\n ...(quote.txRequest?.gasLimit ? {gasLimit: quote.txRequest.gasLimit} : {}),\n ...(quote.txRequest?.approvalAddress ? {approvalAddress: quote.txRequest.approvalAddress} : {}),\n };\n },\n\n async preflightDeposit(quote: Quote, tx: UnsignedTx): Promise<void> {\n const data = quote.providerData;\n if (!data?.sourceChain || !data.destChain || !data.inboundAddress || !data.assetAddress || !data.expiry || !data.memo) {\n throw new Error(\"thorchain: quote is missing execution-bound metadata\");\n }\n const evmSource = CHAIN_ID[data.sourceChain] !== undefined;\n if (evmSource && !data.router) throw new Error(\"thorchain: quote is missing execution-bound metadata\");\n if (!evmSource && !isDepositSource(data.sourceChain)) throw new Error(\"thorchain: source chain has no executor\");\n if (!/^\\d+$/.test(data.expiry) || BigInt(data.expiry) <= BigInt(Math.floor(Date.now() / 1000))) {\n throw new Error(\"thorchain: quote expired before broadcast\");\n }\n if (evmSource && !pinnedRouter(data.sourceChain, data.router)) throw new Error(\"thorchain: the quote's router is not one this module trusts\");\n let inbounds: InboundAddress[] | null = null;\n let snapshotHost = \"\";\n for (const host of hosts) {\n try { inbounds = await inboundAddressesOn(host, clientId); snapshotHost = host; break; } catch (error) { if (!(error instanceof HostUnavailable)) throw error; }\n }\n if (!inbounds) throw new Error(\"thorchain: cannot refresh inbound addresses before broadcast\");\n // The vault the funds go to is confirmed by a second node right before broadcast too (after this node's own checks).\n const confirm = async () => {\n const unconfirmed = await confirmedElsewhere(snapshotHost, data.sourceChain!, data.inboundAddress!, evmSource ? data.router : undefined);\n if (unconfirmed) throw new Error(`thorchain: ${unconfirmed}`);\n };\n const src = inbounds.find((entry) => entry.chain === THOR_CHAIN[data.sourceChain!]);\n const dst = inbounds.find((entry) => entry.chain === THOR_CHAIN[data.destChain!]);\n if (paused(src) || paused(dst)) throw new Error(\"thorchain: source or destination chain trading is paused\");\n if (!sameTarget(src?.address, data.inboundAddress)) throw new Error(\"thorchain: inbound vault rotated after quote\");\n if (!evmSource) {\n // Deposit source: exactly a plain send of the validated amount to the\n // validated vault carrying the validated memo — nothing else.\n if (tx.data !== undefined || tx.approvalAddress !== undefined || tx.bodyBoc !== undefined || tx.typedData !== undefined || tx.serializedTx !== undefined || tx.stateInitBoc !== undefined) {\n throw new Error(\"thorchain: deposit-address execution must be a plain send with memo\");\n }\n if (!sameTarget(tx.to, data.inboundAddress) || tx.memo !== data.memo || tx.value !== quote.sourceAmount || (tx.chain && tx.chain !== data.sourceChain)) {\n throw new Error(\"thorchain: deposit does not match the validated quote\");\n }\n const srcAsset = ccAssetByToken(data.sourceChain, sameTarget(data.assetAddress, NATIVE) ? \"\" : data.assetAddress);\n if (!srcAsset) throw new Error(\"thorchain: unknown source asset\");\n const amount1e8 = (BigInt(quote.sourceAmount) * 100_000_000n) / 10n ** BigInt(srcAsset.decimals);\n const tooSmall = belowThorMinimums(amount1e8, src, null);\n if (tooSmall) throw new Error(`thorchain: ${tooSmall}`);\n await confirm();\n return;\n }\n if (!sameTarget(src?.router, data.router) || !sameTarget(tx.to, data.router)) {\n throw new Error(\"thorchain: router rotated after quote\");\n }\n if (!tx.data) throw new Error(\"thorchain: missing depositWithExpiry calldata\");\n let decoded: {functionName: string; args?: readonly unknown[]};\n try {\n decoded = decodeFunctionData({abi: ROUTER_ABI, data: tx.data as `0x${string}`});\n } catch {\n throw new Error(\"thorchain: malformed depositWithExpiry calldata\");\n }\n const args = decoded.args;\n if (\n decoded.functionName !== \"depositWithExpiry\" || !args || args.length !== 5 ||\n !sameTarget(String(args[0]), data.inboundAddress) ||\n !sameTarget(String(args[1]), data.assetAddress) ||\n BigInt(args[2] as bigint) !== BigInt(quote.sourceAmount) ||\n String(args[3]) !== data.memo || BigInt(args[4] as bigint) !== BigInt(data.expiry) ||\n tx.chainId !== CHAIN_ID[data.sourceChain]\n ) {\n throw new Error(\"thorchain: calldata does not match the validated quote\");\n }\n const tokenSource = !sameTarget(data.assetAddress, NATIVE);\n if (\n tx.value !== (tokenSource ? \"0\" : quote.sourceAmount) ||\n (tokenSource ? !sameTarget(tx.approvalAddress, data.router) : tx.approvalAddress !== undefined)\n ) {\n throw new Error(\"thorchain: value/approval does not match the validated source asset\");\n }\n await confirm();\n },\n\n async trackIntent(ref: IntentRef): Promise<IntentStatus> {\n if (!ref.sourceTxHash) return {state: \"pending\"}; // not broadcast yet\n // THORNode keys EVM inbounds by the tx hash without 0x, uppercase.\n if (!/^(?:0x)?[0-9a-fA-F]{64}$/.test(ref.sourceTxHash)) {\n throw new Error(\"thorchain: source transaction hash must be 32-byte hex\");\n }\n const hash = ref.sourceTxHash.replace(/^0x/i, \"\").toUpperCase();\n const j = await thornodeGet(`/thorchain/tx/status/${hash}`, undefined, hosts, clientId) ??\n await thornodeGet(`/thorchain/tx/${hash}`, undefined, hosts, clientId);\n if (!j) return {state: \"pending\"};\n const stages = j.stages as {\n inbound_observed?: {started?: boolean; completed?: boolean};\n inbound_finalised?: {completed?: boolean};\n outbound_signed?: {completed?: boolean};\n } | undefined;\n if (stages) {\n const planned = (j.planned_out_txs ?? []) as {refund?: boolean}[];\n const refunded = planned.some((out) => out.refund === true);\n const delivered = planned.some((out) => out.refund === false);\n const outTxs = (j.out_txs ?? []) as {id?: string; memo?: string}[];\n const outHash = outTxs.find((out) => typeof out.id === \"string\" && out.id.length > 0 && !/^0+$/.test(out.id))?.id;\n const deliveredHash = outTxs.find((out) =>\n typeof out.id === \"string\" && out.id.length > 0 && !/^0+$/.test(out.id) && typeof out.memo === \"string\" && !/^REFUND/i.test(out.memo)\n )?.id;\n if (stages.outbound_signed?.completed) {\n // `completed` describes the signing stage, not the economic outcome.\n // A truncated/malformed status response with no classified plan or\n // observed outbound must not be promoted to successful delivery.\n if ((!refunded && !delivered) || !outHash) {\n return {state: \"pending\", depositReceived: true};\n }\n return refunded && delivered\n // A refund hash is not a destination transaction. For mixed plans,\n // expose a hash only when the observed outbound is classifiable.\n ? {state: \"partial\", depositReceived: true, ...(deliveredHash ? {destTxHash: deliveredHash} : {})}\n : refunded\n ? {state: \"refunded\", depositReceived: true}\n : {state: \"completed\", depositReceived: true, ...(outHash ? {destTxHash: outHash} : {})};\n }\n return {\n state: \"pending\",\n depositReceived: !!(stages.inbound_observed?.started || stages.inbound_observed?.completed || stages.inbound_finalised?.completed),\n };\n }\n const obs = j.observed_tx as {status?: string; out_hashes?: string[]} | undefined;\n const outHash = obs?.out_hashes?.find((h) => typeof h === \"string\" && h.length > 0 && !/^0+$/.test(h));\n if (obs?.status === \"done\") {\n // A slipped-past-LIM (or halted) swap ALSO finalizes \"done\", but its\n // outbound is a REFUND to the source chain — never report that as a\n // completed swap (audit M1). Planned outbounds carry the memo.\n const planned = (j.planned_out_txs ?? j.out_txs ?? []) as {memo?: string; refund?: boolean}[];\n const refunded = planned.some(\n (o) => o?.refund === true || /^REFUND/i.test(o?.memo ?? \"\"),\n );\n const delivered = planned.some(\n (o) => o?.refund === false && !/^REFUND/i.test(o?.memo ?? \"\"),\n );\n if ((!refunded && !delivered) || !outHash) return {state: \"pending\", depositReceived: true};\n if (refunded && delivered) return {state: \"partial\", depositReceived: true};\n if (refunded) return {state: \"refunded\", depositReceived: true};\n return {state: \"completed\", ...(outHash ? {destTxHash: outHash} : {})};\n }\n return {state: \"pending\", depositReceived: !!obs};\n },\n };\n}\n","import {evmRef, isEvm, namespace} from \"@anywalletkit/protocol-swap2-core/util\";\n\n// ── THORChain — native L1 assets: BTC/ETH/BSC/BASE/Cosmos/Tron/Solana, and\n// (2026-08, pools live) XRP/LTC/DOGE/BCH + GAIA.ATOM ──────────────────────\n// Only EVM source executors actually implemented by provider.ts.\nconst THOR_EVM = new Set([1, 8453, 56, 43114]); // ETH, BASE, BSC, AVAX (2026-09-16)\nconst THOR_NS = new Set([\"bitcoin\", \"cosmos\", \"solana\", \"tron\", \"xrp\", \"litecoin\", \"doge\", \"bch\"]);\nexport const thorchain = {\n enabled: () => true,\n affiliate: () => \"\",\n affiliateBps: () => \"\",\n supportsChain(chain: string): boolean {\n if (THOR_NS.has(namespace(chain))) return true;\n return isEvm(chain) && THOR_EVM.has(evmRef(chain));\n },\n supports(from: string, to: string): boolean {\n return this.supportsChain(from) && this.supportsChain(to);\n },\n};\n","/**\n * Activity recognition for THORChain on its EVM source chains.\n *\n * Routers and Asgard vaults rotate, so nothing is matched by address: the\n * THORChain router ABI is unique enough. `depositWithExpiry` is our source leg\n * (`bridge`, \"Bridged A\"; `swap` when the swap settled back on the same chain\n * and both legs netted). `transferOut` / `transferOutAndCall` are the router\n * paying a destination leg — recognized only when the owner actually received\n * something (\"Received A via THORChain\"). Native sends to an inbound vault with\n * a memo (Tron, BTC) carry no router call and are not recognizable offline.\n */\nimport type {ActivityItem, ChainTx, DescribeActivityContext} from \"@anywalletkit/core\";\nimport {callSelector, describeSwapLike, ownerAssets} from \"@anywalletkit/protocol-swap2-core/activity\";\nimport {thorchain as thorchainCfg} from \"./config.js\";\n\nexport const THORCHAIN_MODULE = \"@anywalletkit/protocol-swap2-thorchain\";\n\n/** depositWithExpiry(address,address,uint256,string,uint256) */\nexport const THORCHAIN_DEPOSIT_WITH_EXPIRY = \"0x44bc937b\";\n/** transferOut(address,address,uint256,string) */\nexport const THORCHAIN_TRANSFER_OUT = \"0x574da717\";\n/** transferOutAndCall(address,address,uint256,address,address,string) */\nexport const THORCHAIN_TRANSFER_OUT_AND_CALL = \"0xec341444\";\n\nexport function describeThorchainActivity(tx: ChainTx, ctx: DescribeActivityContext): ActivityItem | null {\n if (!tx.chain.startsWith(\"eip155:\") || !thorchainCfg.supportsChain(tx.chain)) return null;\n const selector = callSelector(tx);\n if (selector === THORCHAIN_DEPOSIT_WITH_EXPIRY) {\n // The owner must be the depositor: a stranger's deposit that paid us is a transferOut, not ours.\n const isOwn = (a: string) => ctx.own.has(a) || ctx.own.has(a.toLowerCase());\n if (!isOwn(tx.from)) return null;\n return describeSwapLike(tx, ctx, {protocol: THORCHAIN_MODULE, subtitle: \"THORChain\", kind: \"auto\"});\n }\n if (selector === THORCHAIN_TRANSFER_OUT || selector === THORCHAIN_TRANSFER_OUT_AND_CALL) {\n const {assetsIn} = ownerAssets(tx, ctx);\n if (assetsIn.length === 0) return null;\n return describeSwapLike(tx, ctx, {protocol: THORCHAIN_MODULE, subtitle: \"THORChain\", kind: \"bridge\", inSuffix: \"via THORChain\"});\n }\n return null;\n}\n"],"mappings":"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","names":["import_util","isEvm","limitMode","outHash"]}
|
|
1
|
+
{"version":3,"sources":["../src/provider.ts","../src/config.ts","../src/activity.ts","../src/confirm.ts"],"sourcesContent":["import {thorchain as thorCfg} from \"./config.js\";\nimport {describeThorchainActivity} from \"./activity.js\";\nimport {decodeFunctionData, encodeFunctionData} from \"viem\";\nimport {timeoutSignal} from \"@anywalletkit/protocol-swap2-core/util\";\nimport {combinedRefusal, httpRefusal, refusal, refusalNotes, refusalOf, withReason, type Swap2RefusalInfo, type Swap2RefusalReason} from \"@anywalletkit/protocol-swap2-core/errors\";\nimport {ccAsset, ccAssetByToken} from \"@anywalletkit/swap2-assets\";\nimport type {Asset, CrossChainProvider, IntentRef, IntentStatus, Quote, QuoteParams, RemotePins, UnsignedTx} from \"@anywalletkit/protocol-swap2-core/types\";\nimport {bigintToNumber} from \"@anywalletkit/core\";\nimport {\n HostUnavailable,\n MIN_CONFIRM_TIMEOUT_MS,\n THORNODE_CONFIRM_PATHS,\n confirmOptions,\n inboundAddresses,\n lastblockHeight,\n nodeDeadline,\n nodeHead,\n nodeRead,\n paused,\n sameTarget,\n statusRefusal,\n vaultVerdict,\n type InboundAddress,\n type VaultClaim,\n type VaultVerdict,\n} from \"./confirm.js\";\n\nexport {THORNODE_CONFIRM_PATHS} from \"./confirm.js\";\n\n/**\n * THORChain — native L1 swaps via asgard vaults (no wrapping). Scope here is\n * **EVM sources first**: the user\n * deposits on an EVM chain (Ethereum/Base/BSC/Avalanche) into the THORChain router with\n * `depositWithExpiry(vault, asset, amount, memo, expiry)`; THORChain settles the\n * swap and delivers ETH/stables to our mainnet vault. **Tron** (opt-in,\n * `tronSource`) executes as a native TRX send / TRC-20 transfer to the inbound\n * vault with the memo in `raw_data.data` — bifrost reads that field for both\n * TransferContract and TriggerSmartContract. BTC/Cosmos/Solana sources are not\n * routed yet (no memo-capable send surface).\n *\n * Safety: the MEMO and inbound vault come verbatim from the quote — we never\n * hand-build them (a wrong memo makes funds unrecoverable). The quote\n * embeds an on-chain LIM, so a bad-price swap refunds instead of filling:\n * `liquidity_tolerance_bps` when the caller passes a slippage (LIM = expected\n * output after fees × (1 − slippage)), `tolerance_bps` otherwise.\n *\n * Hosts (re-verified 2026-10-28): two public THORNodes of different operators —\n * Liquify's public GATEWAY (50k req/day per IP; x-client-id identifies us for a\n * bump) and the IBS team's node. Nine Realms retired its hosts, the Liquify\n * vanity hostname serves an expired certificate and thornode.thorchain.network\n * no longer resolves. Hosts are tried in order for the quote, and a quote is\n * bound to an inbound snapshot from the SAME host; the source vault and router\n * must then be confirmed by a SECOND host (scan 2026-10-27 modules, F15): one\n * node's answer is not an authority over where the funds go. The list is an\n * explicit constructor option (`nodeUrl`, one or many, plus `confirmNodeUrl`);\n * this package never reads deployment environment values.\n */\n\nconst HOSTS = [\n \"https://gateway.liquify.com/chain/thorchain_api\",\n \"https://thorchain.ibs.team/api\",\n];\n\n/**\n * THORChain's EVM routers (`depositWithExpiry`), the only contracts an EVM-source swap may call and approve (scan\n * 2026-10-27 modules, F15). Reported identically on 2026-10-28 by both default nodes (two operators) and by every\n * October quote-matrix build. A router migration needs a release or `trustedRouters`; until then a quote naming\n * another router is refused, never followed.\n */\nexport const THORCHAIN_ROUTERS: Readonly<Record<string, readonly string[]>> = Object.freeze({\n \"eip155:1\": Object.freeze([\"0xD37BbE5744D730a1d98d8DC97c42F0Ca46aD7146\"]),\n \"eip155:56\": Object.freeze([\"0xb30eC53F98ff5947EDe720D32aC2da7e52A5f56b\"]),\n \"eip155:43114\": Object.freeze([\"0x00dc6100103BC402d490aEE3F9a5560cBd91f1d4\"]),\n \"eip155:8453\": Object.freeze([\"0x00dc6100103BC402d490aEE3F9a5560cBd91f1d4\"]),\n});\n\nconst DEFAULT_CLIENT_ID = \"anywalletkit\";\n\nconst NATIVE = \"0x0000000000000000000000000000000000000000\";\nconst TOLERANCE_BPS = \"300\"; // 3% max slippage, embedded as an on-chain LIM\n// Two ways to ask THORNode for the LIM:\n// - `liquidity_tolerance_bps` — measured from the expected output AFTER\n// THORChain's fees (liquidity, outbound, affiliate): LIM = expected × (1 −\n// slippage), the floor every other provider quotes and validQuote enforces.\n// Used whenever the caller passes a slippage, in one request.\n// - `tolerance_bps` — measured from the FEELESS spot: LIM = spot × (1 −\n// tolerance), so the room left is (tolerance − fees) and the node rejects\n// the quote outright when fees exceed it (\"emit asset X less than price\n// limit Y\"; 500 USDC Base → BTC at 1% paid ≈1.7%). Kept only for legacy\n// quotes without a slippage, which widen it to what the pool needs.\n// Both are hard-capped: a route whose THORChain fees alone exceed the cap\n// stays hidden, with a named reason.\nconst MAX_TOLERANCE_BPS = 500n;\n/** How long a quote stays executable (bounded by the memo's own expiry). */\nconst QUOTE_VALIDITY_MS = 5 * 60_000;\n/** Each read of a quoting (or snapshot-refreshing) node — the quote, `inbound_addresses`, `lastblock` — gets this long. */\nconst NODE_READ_TIMEOUT_MS = 8_000;\n/**\n * The vault check's own budget. It starts when the quoting node's quote is in hand (before broadcast: when a node is\n * asked to refresh the inbound snapshot) and covers that node's `inbound_addresses` and `lastblock` reads and every\n * confirming node; time a failed host took before it does not count. No confirming node is asked with less than\n * MIN_CONFIRM_TIMEOUT_MS of it left.\n */\nconst CONFIRM_BUDGET_MS = 8_000;\n/** A confirming node behind the quoting node by more than the allowed lag: ask the next one. */\nconst LAGGING = Symbol(\"lagging\");\n/** Why the second-node check refused: its text and, next to it, its reason. */\ninterface Unconfirmed {\n text: string;\n info: Swap2RefusalInfo;\n}\n\n// CAIP-2 → THORChain chain prefix. EVM chains execute via the router; TRON\n// executes via a native send to the inbound vault + memo (no router).\nconst THOR_CHAIN: Record<string, string> = {\n \"eip155:1\": \"ETH\",\n \"eip155:8453\": \"BASE\",\n \"eip155:56\": \"BSC\",\n // 2026-09-16: AVAX.AVAX/USDC/USDT pools Available (≈$2.5M/$0.3M/$0.2M),\n // router 0x00dc61…f1d4 live in inbound_addresses; same depositWithExpiry ABI.\n // Polygon has no THORChain pool any more — deliberately absent.\n \"eip155:43114\": \"AVAX\",\n \"tron:728126428\": \"TRON\",\n \"bitcoin:mainnet\": \"BTC\",\n // 2026-08 (pools verified live via the Liquify gateway): THORChain added\n // SOL/XRP, and our catalog now carries LTC/DOGE/BCH/ATOM — destination legs\n // for the step-2 off-ramp (source stays EVM/Tron, see supportsRoute).\n \"solana:mainnet\": \"SOL\",\n \"xrp:mainnet\": \"XRP\",\n \"litecoin:mainnet\": \"LTC\",\n \"doge:mainnet\": \"DOGE\",\n \"bch:mainnet\": \"BCH\",\n \"cosmos:cosmoshub-4\": \"GAIA\",\n};\nconst CHAIN_ID: Record<string, number> = {\"eip155:1\": 1, \"eip155:8453\": 8453, \"eip155:56\": 56, \"eip155:43114\": 43114};\nconst TRON_CAIP2 = \"tron:728126428\";\n// Sources executed as a plain send to the inbound vault + memo (no router).\n// Only chains whose account can attach the memo ON-CHAIN belong here; an\n// unsent memo strands the deposit in the vault.\nconst DEPOSIT_SOURCES = new Set([TRON_CAIP2]);\nconst NATIVE_ASSET: Record<string, string> = {\n ETH: \"ETH.ETH\",\n BASE: \"BASE.ETH\",\n BSC: \"BSC.BNB\",\n AVAX: \"AVAX.AVAX\",\n TRON: \"TRON.TRX\",\n BTC: \"BTC.BTC\",\n SOL: \"SOL.SOL\",\n XRP: \"XRP.XRP\",\n LTC: \"LTC.LTC\",\n DOGE: \"DOGE.DOGE\",\n BCH: \"BCH.BCH\",\n GAIA: \"GAIA.ATOM\",\n};\n\n// Curated token asset notation (UPPERCASE contract, as THORChain expects).\n// Pools come and go (all eight verified Available via the Liquify gateway,\n// 2026-09-16); a retired pool's quote just 404s to null, so entries stay harmless.\nconst TOKEN_ASSET: Record<string, string> = {\n \"ETH:USDC\": \"ETH.USDC-0XA0B86991C6218B36C1D19D4A2E9EB0CE3606EB48\",\n \"ETH:USDT\": \"ETH.USDT-0XDAC17F958D2EE523A2206206994597C13D831EC7\",\n \"BASE:USDC\": \"BASE.USDC-0X833589FCD6EDB6E08F4C7C32D4F71B54BDA02913\",\n \"BSC:USDC\": \"BSC.USDC-0X8AC76A51CC950D9822D68B83FE1AD97B32CD580D\",\n \"BSC:USDT\": \"BSC.USDT-0X55D398326F99059FF775485246999027B3197955\",\n \"AVAX:USDC\": \"AVAX.USDC-0XB97EF9EF8734C71904D8002F8B6BC66DD9C48A6E\",\n \"AVAX:USDT\": \"AVAX.USDT-0X9702230A8EA53601F5CD2DC00FDBC13D4DF4A8C7\",\n \"TRON:USDT\": \"TRON.USDT-TR7NHQJEKQXGTCI8Q8ZY4PL8OTSZGJLJ6T\",\n};\n\nconst ROUTER_ABI = [\n {\n type: \"function\",\n name: \"depositWithExpiry\",\n stateMutability: \"payable\",\n inputs: [\n {name: \"vault\", type: \"address\"},\n {name: \"asset\", type: \"address\"},\n {name: \"amount\", type: \"uint256\"},\n {name: \"memo\", type: \"string\"},\n {name: \"expiration\", type: \"uint256\"},\n ],\n outputs: [],\n },\n] as const;\n\nfunction isEvm(caip2: string): boolean {\n return caip2.startsWith(\"eip155:\");\n}\n\n/** THOR asset notation for a (chain, symbol) on either leg, or undefined. */\nfunction thorAsset(caip2: string, symbol: string): string | undefined {\n const chain = THOR_CHAIN[caip2];\n if (!chain) return undefined;\n const sym = symbol.toUpperCase();\n const token = TOKEN_ASSET[`${chain}:${sym}`];\n if (token) return token;\n const native = NATIVE_ASSET[chain];\n return native && native.split(\".\")[1] === sym ? native : undefined;\n}\n\n/**\n * Destination asset for either direction: inbound → the vault on Ethereum, or\n * the step-2 off-ramp → any THOR-supported chain (BTC/BASE/BSC/TRON). Resolved\n * from the catalog so we get the right symbol + decimals for the target chain.\n */\nfunction destAsset(destChain: string, destToken: string): {asset: string; decimals: number} | undefined {\n const a = ccAssetByToken(destChain, destToken);\n if (!a) return undefined;\n const asset = thorAsset(destChain, a.symbol);\n return asset ? {asset, decimals: a.decimals} : undefined;\n}\n\ninterface ThorQuoteResponse {\n expected_amount_out?: string;\n inbound_address?: string;\n router?: string;\n memo?: string;\n expiry?: number;\n total_swap_seconds?: number;\n /** 1e8 source units; below this the swap is refunded minus fees. */\n recommended_min_amount_in?: string;\n error?: string;\n /** thornode simulation rejections arrive as {code, message}. */\n message?: string;\n /** THORChain's fees on this quote; `total_bps` includes liquidity, outbound and affiliate. */\n fees?: {total_bps?: number};\n}\n\ninterface HostResponse {\n ok: boolean;\n status: number;\n body: Record<string, unknown> | unknown[] | null;\n}\n\nasync function hostGet(host: string, path: string, clientId: string, signal?: AbortSignal): Promise<HostResponse> {\n let res: Response;\n try {\n res = await fetch(`${host}${path}`, {\n headers: {accept: \"application/json\", \"x-client-id\": clientId},\n cache: \"no-store\",\n signal: signal ?? timeoutSignal(NODE_READ_TIMEOUT_MS),\n });\n } catch (error) {\n if (signal?.aborted) throw error; // the caller gave up — not the host's fault\n throw new HostUnavailable(host, error instanceof Error ? error.message : \"fetch failed\");\n }\n if (res.status >= 500 || res.status === 429 || res.status === 403) {\n throw new HostUnavailable(host, `HTTP ${res.status}`, statusRefusal(res.status, res.headers?.get?.(\"retry-after\")));\n }\n const body = (await res.json().catch(() => null)) as HostResponse[\"body\"];\n return {ok: res.ok, status: res.status, body};\n}\n\n/** Per-request failover for reads whose answer is host-independent (tx status). */\nasync function thornodeGet(\n path: string,\n signal: AbortSignal | undefined,\n hosts: string[],\n clientId: string,\n): Promise<Record<string, unknown> | null> {\n for (const host of hosts) {\n try {\n const res = await hostGet(host, path, clientId, signal);\n if (!res.ok) continue;\n return Array.isArray(res.body) ? null : res.body;\n } catch (error) {\n if (error instanceof HostUnavailable) continue;\n throw error;\n }\n }\n return null;\n}\n\n/** Fail closed on amounts THORChain would ignore (dust) or refund (below the\n * recommended minimum). Both are quoted in 1e8 source units. */\nfunction belowThorMinimums(amount1e8: bigint, inbound: InboundAddress | undefined, quote: ThorQuoteResponse | null): string | null {\n const dust = inbound?.dust_threshold;\n if (dust !== undefined && (!/^\\d+$/.test(String(dust)) || amount1e8 <= BigInt(dust))) return \"amount at or below THORChain dust threshold\";\n const min = quote?.recommended_min_amount_in;\n if (min !== undefined && (!/^\\d+$/.test(String(min)) || amount1e8 < BigInt(min))) return \"amount below THORChain recommended minimum\";\n return null;\n}\n\n/**\n * The reason every node failing adds up to (each failure's own classification, see HostUnavailable): theirs when they\n * all agree (the shortest wait when every node throttled), else `upstream_unavailable`.\n */\nfunction nodesFailed(failures: readonly (Swap2RefusalInfo | undefined)[]): Swap2RefusalInfo {\n const known = failures.filter((f): f is Swap2RefusalInfo => f !== undefined);\n if (!known.length || known.length !== failures.length) return {reason: \"upstream_unavailable\"};\n const combined = combinedRefusal(known.map((f) => ({message: \"\", ...f})));\n return combined.reason === \"no_route\" ? {reason: \"upstream_unavailable\"} : combined;\n}\n\n/**\n * The reason a node's quote rejection gives: its text first (THORNode's simulation errors: price limit, halt, dust,\n * missing pool), else its HTTP status, else `no_route`. `bodyless`: the node answered a non-2xx status without a JSON\n * body (the `HTTP <status>` text), another shape than THORNode's `{code, message}`.\n */\nfunction quoteRejection(text: string, status: number, bodyless: boolean): Swap2RefusalInfo {\n // Fees ate the whole output: nothing is left to emit at this amount.\n if (/emit asset 0 less than price limit/.test(text)) return {reason: \"amount_too_small\"};\n if (/emit asset \\d+ less than price limit/.test(text)) return {reason: \"price_check_failed\"};\n if (/halt|paused/i.test(text)) return {reason: \"chain_halted\"};\n if (/dust|too small|not enough [a-z ]*(?:to pay|for) (?:the )?fee/i.test(text)) return {reason: \"amount_too_small\"};\n if (/insufficient liquidity|not enough liquidity/i.test(text)) return {reason: \"insufficient_liquidity\"};\n if (/pool [^ ]* ?(?:does not exist|doesn't exist|not exist|not found|not available|is not available)|no pool/i.test(text)) return {reason: \"unsupported_pair\"};\n if (/rate limit|too many requests/i.test(text)) return {reason: \"rate_limited\"};\n if (/api key|unauthori[sz]ed/i.test(text)) return {reason: \"key_rejected\"};\n const byStatus = status >= 400 ? httpRefusal(status) : undefined;\n if (byStatus) return byStatus;\n return bodyless ? {reason: \"upstream_unavailable\", httpStatus: status} : {reason: \"no_route\"};\n}\n\n/** Inbound snapshot from ONE host. Throws HostUnavailable so the caller can\n * re-run the whole quote on the next host rather than mixing nodes — also when\n * a field this module reads has another type (`inboundAddresses`). */\nasync function inboundAddressesOn(host: string, clientId: string): Promise<InboundAddress[]> {\n const res = await hostGet(host, \"/thorchain/inbound_addresses\", clientId);\n if (!res.ok || !Array.isArray(res.body)) throw new HostUnavailable(host, `inbound_addresses HTTP ${res.status}`, res.ok ? undefined : statusRefusal(res.status));\n const entries = inboundAddresses(res.body);\n if (!entries) throw new HostUnavailable(host, \"inbound_addresses is not a THORNode inbound address list\");\n return entries;\n}\n\nfunction verifiedMemo(\n memo: string,\n expectedAsset: string,\n expectedDestination: string,\n expectedRefund: string,\n expectedAffiliate: string,\n expectedAffiliateBps: string,\n why?: (reason: Swap2RefusalReason) => void,\n): {limit: bigint; canonical: string} | null {\n /** Null, after telling `why` the reason the memo is refused. */\n const refused = (reason: Swap2RefusalReason): null => {\n why?.(reason);\n return null;\n };\n if (memo.includes(\"|\")) return refused(\"recipient_unverifiable\"); // DEX-aggregator tail is a separate, unbound execution program.\n const parts = memo.split(\":\");\n if (parts.length !== 4 && parts.length !== 6) return refused(\"policy_refused\");\n const [op, asset, destination, limit, affiliate, bps] = parts;\n // Quote responses legitimately use THORChain fuzzy asset notation (`b` for\n // BTC.BTC). We never execute that untrusted spelling: after checking the\n // shape, destination/refund, limit and affiliate we rebuild a canonical memo\n // from our own route facts below.\n if (op !== \"=\" || !asset || !/^[A-Za-z0-9._~\\-]+$/.test(asset)) return refused(\"policy_refused\");\n const expectedTarget = expectedRefund ? `${expectedDestination}/${expectedRefund}` : expectedDestination;\n if (!sameTarget(destination, expectedTarget)) return refused(\"recipient_mismatch\");\n if (parts.length === 6) {\n if (!expectedAffiliate || affiliate !== expectedAffiliate || bps !== expectedAffiliateBps) return refused(\"policy_refused\");\n } else if (expectedAffiliate || expectedAffiliateBps) {\n return refused(\"policy_refused\");\n }\n const stream = (limit ?? \"\").split(\"/\");\n // We never request streaming swaps. A provider-supplied LIM/INTERVAL/QTY\n // memo changes the floor to a per-sub-swap condition, so reject it instead\n // of presenting LIM as an atomic total guarantee.\n if (stream.length !== 1 || stream.some((v) => !/^\\d+$/.test(v))) return refused(\"price_check_failed\");\n const floor = BigInt(stream[0] ?? \"0\");\n if (floor <= 0n) return refused(\"price_check_failed\");\n const canonical = `=:${expectedAsset}:${expectedTarget}:${stream.join(\"/\")}${\n expectedAffiliate ? `:${expectedAffiliate}:${expectedAffiliateBps}` : \"\"\n }`;\n return {limit: floor, canonical};\n}\n\nfunction toThorUnitsCeil(amount: bigint, decimals: number): bigint {\n const scale = 10n ** BigInt(decimals);\n return (amount * 100_000_000n + scale - 1n) / scale;\n}\n\n/** Explicit constructor configuration; no deployment environment is read. */\nexport interface ThorchainProviderConfig {\n enabled?: boolean;\n affiliate?: string;\n affiliateBps?: string;\n /**\n * THORNode base URL(s), tried in order; a comma-separated string is\n * accepted for env-style configuration. Defaults to the documented public\n * hosts. Quote + inbound snapshot always come from the same host. A host whose\n * `inbound_addresses` or `lastblock` answer has another shape (a field of\n * another type included) is unavailable: the next one is asked.\n */\n nodeUrl?: string | string[];\n /**\n * Nodes that confirm the source vault and router a quote names (scan 2026-10-27 modules, F15): another host must\n * report the same before a quote is used and again right before broadcast; a disagreeing or silent second source\n * refuses. Default: the other `nodeUrl` hosts, else the default public nodes. Name a node of another operator.\n */\n confirmNodeUrl?: string | string[];\n /**\n * Blocks a confirming node may trail the quoting node's THORChain height (`/thorchain/lastblock`) before it is\n * skipped for the next confirming node. Default 50 (~5 minutes). Integer 0–100000.\n */\n confirmMaxLagBlocks?: number;\n /**\n * Time one confirming node gets for all of its reads, in ms; a node that has not answered by then is skipped for\n * the next one. Default 2500. Integer 100–8000. It bounds confirming nodes only: the quoting node's own reads (the\n * quote, `inbound_addresses`, `/thorchain/lastblock`) get 8 s each whatever this is. The confirming nodes share the\n * vault check's 8 s budget, which starts when the quote is in hand (before broadcast: when a node is asked to\n * refresh the inbound snapshot) and also covers that node's `inbound_addresses` and `lastblock` reads; a node is\n * asked only while at least 100 ms of it is left.\n *\n * Worst case without a caller signal: each `nodeUrl` host takes at most 8 s for the quote (16 s when a quote\n * without a slippage is retried with a wider tolerance) plus 8 s for its snapshot, and the check of the host that\n * quotes ends within the 8 s that started when its quote was in hand — hosts × 16 s, or hosts × 24 s with the\n * retry (32 s / 48 s with the two default hosts). `preflightDeposit`: hosts × 8 s. A caller's AbortSignal (the\n * router passes one) replaces the 8 s bound of the quote request; when it aborts, the quote request, the quoting\n * node's `lastblock` read and the confirming reads stop at once, and its `inbound_addresses` read keeps its own 8 s.\n */\n confirmTimeoutMs?: number;\n /** Routers to trust besides {@link THORCHAIN_ROUTERS}, per CAIP-2 chain (a router migration before a release). */\n trustedRouters?: Readonly<Record<string, readonly string[]>>;\n /** Allow `http:` node URLs (local development only): the vault and router a swap pays come from them. */\n allowInsecureNodeUrl?: boolean;\n /** Optional gateway identification; defaults to a neutral module name. */\n clientId?: string;\n /**\n * Opt-in Tron SOURCE execution: a native TRX send / TRC-20 transfer to the\n * inbound vault carrying the swap memo in `raw_data.data`. Ships dark: the\n * bound account MUST attach the memo on-chain (`raw_data.data`); a\n * memo-less send is unsettleable.\n */\n tronSource?: boolean;\n}\n\n/**\n * The app's side of a remote THORChain stub (scan 2026-10-27 modules, F15): `remoteProvider({name: \"thorchain\",\n * baseUrl, ...thorchainPins()})`. The pinned routers are the only call targets and spenders, and `verifyBuild` checks\n * the build on the client: the vault in the router call (or the Tron deposit's recipient) confirmed by two THORNodes\n * of different operators, the source asset and exact input, and the memo's asset, destination, refund and limit\n * against the app's own request. Pass the affiliate your backend's provider uses (the memo must carry exactly it).\n * The Tron deposit route is open (`depositAddressRoutes`): its vault is the one `verifyBuild` confirms.\n *\n * A node confirms by the provider's rule: the vault is its current inbound for the source chain or that chain's\n * address of an ActiveVault its mimir does not flag compromised or insolvent (never RetiringVault or another status),\n * both chains open, on EVM its router the call's. All `nodeUrl` nodes are asked in parallel on the fixed GET paths of\n * {@link THORNODE_CONFIRM_PATHS}, each within `confirmTimeoutMs` (so the check takes at most that long); a node that\n * fails, redirects, answers another shape (a field of another type included), is slower, or trails the highest\n * THORChain height the nodes report by more than `confirmMaxLagBlocks` is skipped. In `nodeUrl` order, a node's\n * refusal refuses; two confirming nodes pass.\n */\nexport function thorchainPins(opts: {\n nodeUrl?: string | string[];\n affiliate?: string;\n affiliateBps?: string;\n trustedRouters?: Readonly<Record<string, readonly string[]>>;\n clientId?: string;\n /** Blocks a node may trail the highest THORChain height the nodes report before it is skipped. Default 50; 0–100000. */\n confirmMaxLagBlocks?: number;\n /** Time each node gets for all of its reads, in ms; the nodes are asked in parallel. Default 2500; 100–8000. */\n confirmTimeoutMs?: number;\n} = {}): RemotePins & {verifyBuild(quote: Quote, tx: UnsignedTx, params?: QuoteParams): Promise<string | null>} {\n const nodes = [...new Set((Array.isArray(opts.nodeUrl) ? opts.nodeUrl : opts.nodeUrl ? opts.nodeUrl.split(\",\") : HOSTS).map((h) => h.trim().replace(/\\/$/, \"\")).filter(Boolean))];\n for (const n of nodes) if (!/^https:\\/\\//i.test(n)) throw new Error(\"thorchain: thorchainPins nodeUrl must use https\");\n const clientId = opts.clientId?.trim() || DEFAULT_CLIENT_ID;\n const {maxLagBlocks, timeoutMs} = confirmOptions(opts);\n /**\n * One node's THORChain height and verdict on the claim; null when it failed, `verdict` null when only the verdict did.\n * A failure's classification (HostUnavailable) goes to `failures`, for the refusal when two nodes could not confirm.\n */\n const askNode = async (host: string, claim: VaultClaim, failures: (Swap2RefusalInfo | undefined)[]): Promise<{height: number; verdict: VaultVerdict | null} | null> => {\n const node = nodeDeadline(timeoutMs);\n const read = (path: string) => nodeRead(host, path, clientId, node.signal);\n try {\n const head = await nodeHead(host, read);\n try {\n return {height: head.height, verdict: await vaultVerdict(host, read, head.inbound, claim)};\n } catch (error) {\n if (error instanceof HostUnavailable) {\n failures.push(refusalOf(error));\n return {height: head.height, verdict: null};\n }\n throw error;\n }\n } catch (error) {\n if (error instanceof HostUnavailable) {\n failures.push(refusalOf(error));\n return null;\n }\n throw error;\n } finally {\n node.clear();\n }\n };\n const routersFor = (chain: string): readonly string[] => [...(THORCHAIN_ROUTERS[chain] ?? []), ...(opts.trustedRouters?.[chain] ?? [])];\n // Each text verifyBuild returns, with its reason (`reasonOf`, so a remote stub's refusal carries it).\n const {note, reasonOf} = refusalNotes();\n return Object.freeze({\n callTargets: routersFor,\n spenders: routersFor,\n reasonOf,\n // A Tron source is a send to the inbound vault; verifyBuild confirms that vault with two THORNodes (scan 2026-10-28 F9).\n depositAddressRoutes: true,\n async verifyBuild(quote: Quote, tx: UnsignedTx, params?: QuoteParams): Promise<string | null> {\n if (!params) return note(\"the request this quote answered is unknown\", \"policy_refused\");\n const src = ccAsset(params.sourceChain, params.sourceToken);\n const dst = destAsset(params.destChain, params.destToken);\n if (!src || !dst) return note(\"unknown source or destination asset\", \"unsupported_pair\");\n const chainId = CHAIN_ID[params.sourceChain];\n let vault: string, memo: string, router: string | undefined;\n if (chainId) {\n if (!tx.data) return note(\"no router calldata\", \"policy_refused\");\n let args: readonly unknown[] | undefined;\n try {\n const d = decodeFunctionData({abi: ROUTER_ABI, data: tx.data as `0x${string}`});\n if (d.functionName !== \"depositWithExpiry\") return note(`${d.functionName} is not depositWithExpiry`, \"policy_refused\");\n args = d.args;\n } catch { return note(\"the router calldata does not decode\", \"policy_refused\"); }\n if (!args || args.length !== 5) return note(\"the router calldata does not decode\", \"policy_refused\");\n router = tx.to;\n if (!routersFor(params.sourceChain).some((r) => sameTarget(r, router))) return note(`router ${tx.to} is not pinned`, \"vault_mismatch\");\n vault = String(args[0]);\n const asset = String(args[1]);\n if (!sameTarget(asset, src.contract ?? NATIVE)) return note(`the router call moves ${asset}, not the source asset`, \"policy_refused\");\n if (BigInt(args[2] as bigint) !== BigInt(quote.sourceAmount)) return note(`the router call moves ${String(args[2])}, not the ${quote.sourceAmount} input`, \"policy_refused\");\n memo = String(args[3]);\n } else {\n // A deposit source (Tron): a plain send of the input to the vault with the memo.\n if (!tx.memo || tx.value !== quote.sourceAmount) return note(\"the deposit is not a send of the input with a memo\", \"policy_refused\");\n vault = tx.to;\n memo = tx.memo;\n }\n let memoRefusal: Swap2RefusalReason = \"recipient_mismatch\";\n const checked = verifiedMemo(memo, dst.asset, params.destAddress, params.refundAddress ?? \"\", opts.affiliate ?? \"\", opts.affiliateBps ?? \"\", (why) => { memoRefusal = why; });\n if (!checked) return note(`the memo does not pay ${params.destAddress} in ${dst.asset} with this app's refund and affiliate`, memoRefusal);\n // The server's provider signs only the canonical memo it rebuilds from route facts, so the build must be that\n // memo byte for byte: a fuzzy or swapped output asset (scan 2026-10-30 F2) is refused here.\n if (memo !== checked.canonical) return note(`the memo is not the canonical ${checked.canonical}`, \"policy_refused\");\n if ((checked.limit * 10n ** BigInt(dst.decimals)) / 100_000_000n < BigInt(quote.minDestAmount)) return note(`the memo's limit ${checked.limit} is below the quoted minimum`, \"price_check_failed\");\n // Two nodes of different operators must confirm this vault (and router), trading open on both chains.\n const sourceChain = THOR_CHAIN[params.sourceChain] ?? params.sourceChain;\n const claim: VaultClaim = {chain: sourceChain, destChain: THOR_CHAIN[params.destChain] ?? params.destChain, vault, ...(router !== undefined ? {router} : {})};\n // Each node that failed, classified: what two nodes not confirming adds up to (all throttled → rate_limited).\n const failures: (Swap2RefusalInfo | undefined)[] = [];\n const views = await Promise.all(nodes.map((host) => askNode(host, claim, failures)));\n // The freshest height any node reports is the reference: a node far behind it may still list a vault that has\n // since retired or been flagged.\n const top = views.reduce((max, v) => (v && v.height > max ? v.height : max), -1);\n let agreeing = 0;\n let lagging = false;\n for (const view of views) {\n if (!view?.verdict) continue;\n if (top - view.height > maxLagBlocks) {\n lagging = true;\n continue;\n }\n const v = view.verdict;\n if (!v.ok) {\n switch (v.why) {\n case \"halted\": return note(`${v.chain} is halted / paused`, \"chain_halted\");\n case \"another-vault\": return note(`a THORNode reports another inbound vault than ${vault}`, \"vault_mismatch\");\n case \"not-active\": return note(`a THORNode lists the inbound vault as ${v.status}, not ActiveVault`, \"vault_mismatch\");\n case \"flagged\": return note(`a THORNode's mimir flags the inbound vault as ${v.flag}`, \"vault_mismatch\");\n case \"another-router\": return note(\"a THORNode reports another router\", \"vault_mismatch\");\n }\n }\n if (++agreeing >= 2) return null;\n }\n return lagging\n ? note(`two THORNodes within ${maxLagBlocks} blocks of the highest THORChain height they report could not confirm the inbound vault (behind or unreachable)`, \"stale_node\")\n : note(\"two THORNodes could not confirm the inbound vault\", nodesFailed(failures));\n },\n });\n}\n\nexport function thorchainProvider(config: ThorchainProviderConfig = {}): CrossChainProvider {\n config = Object.freeze({...config});\n const configuredHosts = (Array.isArray(config.nodeUrl) ? config.nodeUrl : (config.nodeUrl ?? \"\").split(\",\"))\n .map((h) => h.trim())\n .filter(Boolean);\n const hosts = [...new Set((configuredHosts.length ? configuredHosts : HOSTS).map((h) => {\n let url: URL;\n try {\n url = new URL(h);\n } catch {\n throw new Error(\"thorchain: nodeUrl must be an absolute http(s) URL\");\n }\n if (url.protocol !== \"https:\" && !(url.protocol === \"http:\" && config.allowInsecureNodeUrl === true)) {\n throw new Error(\"thorchain: nodeUrl must use https (allowInsecureNodeUrl for local development)\");\n }\n return url.toString().replace(/\\/$/, \"\");\n }))];\n const parseHosts = (input: string | string[] | undefined): string[] => (Array.isArray(input) ? input : (input ?? \"\").split(\",\"))\n .map((h) => h.trim()).filter(Boolean).map((h) => {\n let url: URL;\n try { url = new URL(h); } catch { throw new Error(\"thorchain: confirmNodeUrl must be an absolute https URL\"); }\n if (url.protocol !== \"https:\" && !(url.protocol === \"http:\" && config.allowInsecureNodeUrl === true)) throw new Error(\"thorchain: confirmNodeUrl must use https\");\n return url.toString().replace(/\\/$/, \"\");\n });\n const confirmHosts = [...new Set([...parseHosts(config.confirmNodeUrl), ...hosts, ...HOSTS])];\n const routers = new Map<string, Set<string>>();\n for (const [chain, list] of [...Object.entries(THORCHAIN_ROUTERS), ...Object.entries(config.trustedRouters ?? {})]) {\n const set = routers.get(chain) ?? new Set<string>();\n for (const r of list) {\n if (!/^0x[0-9a-fA-F]{40}$/.test(r)) throw new Error(`thorchain: trusted router for ${chain} is not an EVM address`);\n set.add(r.toLowerCase());\n }\n routers.set(chain, set);\n }\n const pinnedRouter = (chain: string, router: string | undefined) => !!router && routers.get(chain)?.has(router.toLowerCase()) === true;\n const {maxLagBlocks: confirmMaxLagBlocks, timeoutMs: confirmTimeoutMs} = confirmOptions(config);\n /**\n * The inbound snapshot (`inbound_addresses`) and THORChain height (`/thorchain/lastblock`) of the node that quoted\n * (or, before broadcast, refreshes the snapshot), read in parallel and each bounded at NODE_READ_TIMEOUT_MS — the\n * height read does not use `confirmTimeoutMs`, which bounds confirming nodes only. A snapshot failure fails the host\n * at once; when only the height fails, the snapshot is awaited and the answer says so (`heightError`), so a refusal\n * can tell the two apart. Anything but a host failure (the caller aborting) rejects at once.\n */\n const nodeSnapshot = (host: string, outer?: AbortSignal) =>\n new Promise<{inbounds: InboundAddress[]; height: number} | {inbounds: InboundAddress[]; heightError: HostUnavailable}>((resolve, reject) => {\n let inbounds: InboundAddress[] | undefined;\n let height: number | undefined;\n let heightError: HostUnavailable | undefined;\n let done = false;\n const tip = nodeDeadline(NODE_READ_TIMEOUT_MS, outer);\n const settle = () => {\n if (done || inbounds === undefined || (height === undefined && heightError === undefined)) return;\n done = true;\n resolve(heightError ? {inbounds, heightError} : {inbounds, height: height!});\n };\n const fail = (error: unknown) => {\n if (done) return;\n done = true;\n tip.clear(); // a height read still running is dropped with the host\n reject(error);\n };\n inboundAddressesOn(host, clientId).then((v) => {\n inbounds = v;\n settle();\n }, fail);\n nodeRead(host, THORNODE_CONFIRM_PATHS.lastblock, clientId, tip.signal, outer).then(\n (body) => {\n tip.clear();\n const h = lastblockHeight(body);\n if (h === null) heightError = new HostUnavailable(host, \"lastblock is not a THORNode lastblock list\");\n else height = h;\n settle();\n },\n (error: unknown) => {\n tip.clear();\n if (!(error instanceof HostUnavailable)) return fail(error);\n heightError = error;\n settle();\n },\n );\n });\n /**\n * The provider's refusal for a confirming node's verdict (the texts of the second-node check), with its reason. The\n * reason travels next to the text: the same text (\"no second node answered…\") can carry different reasons.\n */\n const confirmText = (v: Exclude<VaultVerdict, {ok: true}>): Unconfirmed => {\n switch (v.why) {\n case \"halted\": return {text: `${v.chain} is halted / paused on the confirming node`, info: {reason: \"chain_halted\"}};\n case \"another-vault\": return {text: \"a second node reports another inbound vault — refused until they agree\", info: {reason: \"vault_mismatch\"}};\n case \"not-active\": return {text: `a second node lists the inbound vault as ${v.status}, not ActiveVault — refused`, info: {reason: \"vault_mismatch\"}};\n case \"flagged\": return {text: `a second node's mimir flags the inbound vault as ${v.flag} — refused`, info: {reason: \"vault_mismatch\"}};\n case \"another-router\": return {text: \"a second node reports another router — refused until they agree\", info: {reason: \"vault_mismatch\"}};\n }\n };\n /**\n * One confirming node's verdict on the vault (and router) a quote names ({@link vaultVerdict}); null when it\n * confirms, LAGGING when it trails the quoting node by more than `confirmMaxLagBlocks`.\n */\n const confirmOn = async (\n host: string,\n signal: AbortSignal,\n outer: AbortSignal | undefined,\n quoteHeight: number,\n claim: VaultClaim,\n ): Promise<Unconfirmed | null | typeof LAGGING> => {\n const read = (path: string) => nodeRead(host, path, clientId, signal, outer);\n const head = await nodeHead(host, read);\n if (quoteHeight - head.height > confirmMaxLagBlocks) return LAGGING;\n const verdict = await vaultVerdict(host, read, head.inbound, claim);\n return verdict.ok ? null : confirmText(verdict);\n };\n /**\n * A second node's view of the source chain, from a host other than `quoteHost` (the next one when a node trails the\n * quoting node by more than `confirmMaxLagBlocks`, fails, or takes longer than `confirmTimeoutMs`): the vault (and\n * router) the quote names must be confirmed, and trading open on both chains. Each node gets `confirmTimeoutMs` or\n * what is left of the budget ending at `deadlineAt`, and none is asked with less than MIN_CONFIRM_TIMEOUT_MS left.\n * Why it fails (the text and its reason), or null.\n */\n const confirmedElsewhere = async (\n quoteHost: string,\n quoteHeight: number,\n chain: string,\n destChain: string | undefined,\n vault: string,\n router: string | undefined,\n deadlineAt: number,\n outer?: AbortSignal,\n ): Promise<Unconfirmed | null> => {\n const claim: VaultClaim = {\n chain: THOR_CHAIN[chain] ?? chain,\n ...(destChain !== undefined ? {destChain: THOR_CHAIN[destChain] ?? destChain} : {}),\n vault,\n ...(router !== undefined ? {router} : {}),\n };\n let lagging = false;\n let asked = 0;\n // Each confirming node's failure (HostUnavailable), and a node the budget left unasked: what no second node\n // answering adds up to (every node throttled → rate_limited with the shortest wait).\n const failures: (Swap2RefusalInfo | undefined)[] = [];\n for (const host of confirmHosts) {\n if (host === quoteHost) continue;\n const budget = Math.min(confirmTimeoutMs, deadlineAt - Date.now());\n if (budget < MIN_CONFIRM_TIMEOUT_MS) {\n failures.push({reason: \"upstream_unavailable\"}); // out of time before this node could be asked\n break;\n }\n asked++;\n const node = nodeDeadline(budget, outer);\n try {\n const verdict = await confirmOn(host, node.signal, outer, quoteHeight, claim);\n if (verdict === LAGGING) {\n lagging = true;\n continue;\n }\n return verdict;\n } catch (error) {\n if (outer?.aborted) throw error;\n if (error instanceof HostUnavailable) {\n failures.push(refusalOf(error));\n continue;\n }\n throw error;\n } finally {\n node.clear();\n }\n }\n if (lagging) {\n return {text: `no confirming node is within ${confirmMaxLagBlocks} blocks of the quoting node's THORChain height (behind or unreachable) — refused until one catches up`, info: {reason: \"stale_node\"}};\n }\n if (asked === 0) {\n return {text: `the ${CONFIRM_BUDGET_MS / 1000} s confirmation budget ran out before a second node could be asked to confirm the inbound vault — retry`, info: {reason: \"upstream_unavailable\"}};\n }\n return {text: \"no second node answered to confirm the inbound vault (configure confirmNodeUrl)\", info: nodesFailed(failures)};\n };\n const configuredAffiliate = config.affiliate ?? \"\";\n const configuredAffiliateBps = config.affiliateBps ?? \"\";\n if (!!configuredAffiliate !== !!configuredAffiliateBps) {\n throw new Error(\"thorchain: affiliate and affiliateBps must be configured together\");\n }\n if (configuredAffiliate && !/^[A-Za-z0-9._~-]+$/.test(configuredAffiliate)) {\n throw new Error(\"thorchain: affiliate contains unsupported memo characters\");\n }\n if (configuredAffiliateBps && (!/^\\d+$/.test(configuredAffiliateBps) || BigInt(configuredAffiliateBps) > 10_000n)) {\n throw new Error(\"thorchain: affiliateBps must be an integer between 0 and 10000\");\n }\n const clientId = config.clientId?.trim() || DEFAULT_CLIENT_ID;\n if (!/^[\\x21-\\x7e]{1,128}$/.test(clientId)) throw new Error(\"thorchain: clientId must contain 1-128 visible ASCII characters\");\n const tronSource = config.tronSource === true;\n const isDepositSource = (caip2: string): boolean => tronSource && DEPOSIT_SOURCES.has(caip2);\n return {\n name: \"thorchain\",\n describeActivity: describeThorchainActivity,\n enabled: () => config.enabled ?? true,\n\n // Capability discovery comes from the provider itself, so it can run alone\n // or inside the optional aggregator without a central capability table.\n supportsChain: (chain: string) => thorCfg.supportsChain(chain),\n supportsChainPair: (fromChain: string, toChain: string) => thorCfg.supports(fromChain, toChain),\n // Inbound: EVM/Tron source → the mainnet vault. Outbound (step-2 off-ramp):\n // EVM source (Ethereum) → any THOR-supported chain. The SOURCE must be EVM\n // (router calldata) or, when opted in, Tron (send + memo); both legs must\n // be THOR chains and differ.\n supportsRoute(from: Asset, to: Asset): boolean {\n const srcExec = isEvm(from.chain) || isDepositSource(from.chain);\n if (!(srcExec && !!THOR_CHAIN[from.chain] && !!THOR_CHAIN[to.chain] && from.chain !== to.chain)) return false;\n // Asset level too: claiming a chain pair whose assets THORChain has no\n // pool for (e.g. USDC on Solana) put the provider in every route list\n // and then answered a silent null.\n const fromAsset = thorAsset(from.chain, from.token) ?? thorAsset(from.chain, ccAssetByToken(from.chain, from.token)?.symbol ?? \"\");\n const toAsset = destAsset(to.chain, to.token) ?? (thorAsset(to.chain, to.token) ? {asset: thorAsset(to.chain, to.token)!} : undefined);\n return !!fromAsset && !!toAsset && fromAsset !== toAsset.asset;\n },\n\n async getQuote(params: QuoteParams, signal?: AbortSignal): Promise<Quote | null> {\n if (!(config.enabled ?? true)) return null;\n if (params.flex) return null; // memo/LIM embed the exact amount\n const chainId = CHAIN_ID[params.sourceChain];\n // EVM sources execute via the router; opted-in deposit sources (Tron)\n // via send + memo. Anything else has no safe executor.\n if (!chainId && !isDepositSource(params.sourceChain)) return null;\n if (params.sourceChain === params.destChain) return null; // same-chain: not a swap\n\n const src = ccAsset(params.sourceChain, params.sourceToken);\n const fromAsset = thorAsset(params.sourceChain, params.sourceToken);\n const dst = destAsset(params.destChain, params.destToken);\n if (!src || !fromAsset || !dst || fromAsset === dst.asset) {\n params.onRefusal?.(`thorchain: no pool for ${params.sourceToken} on ${params.sourceChain} → ${params.destToken} on ${params.destChain}`, {reason: \"unsupported_pair\"});\n return null;\n }\n\n // THORChain amounts are universally 1e8-scaled.\n const amountIn = BigInt(params.amountIn);\n const amount1e8 = (amountIn * 100000000n) / 10n ** BigInt(src.decimals);\n if (amount1e8 <= 0n) return null;\n // THOR quotes only 1e8 units. Never send a larger high-precision source\n // amount than the amount priced by the quote (the remainder is dust the\n // memo cannot account for and may be donated to the vault).\n if (amount1e8 * 10n ** BigInt(src.decimals) !== amountIn * 100_000_000n) {\n params.onRefusal?.(`thorchain: amount has more precision than THORChain's 8 decimals — round it to 8 decimals`, {reason: \"policy_refused\"});\n return null;\n }\n\n const requestedTolerance = params.slippageBps ?? Number(TOLERANCE_BPS);\n if (!Number.isInteger(requestedTolerance) || requestedTolerance < 0 || requestedTolerance > bigintToNumber(MAX_TOLERANCE_BPS)) {\n params.onRefusal?.(`thorchain: slippage ${String(params.slippageBps)} bps is outside 0–${MAX_TOLERANCE_BPS} bps`, {reason: \"policy_refused\"});\n return null;\n }\n // An explicit slippage → `liquidity_tolerance_bps`. The node floors LIM in\n // 1e8 units; for a destination with more than 8 decimals that floor lands\n // a hair below expected × (1 − slippage) in base units, so ask 1 bp\n // tighter there (never looser). 0 bp cannot carry a LIM that way: such a\n // request goes out as `tolerance_bps` and the node's answer stands.\n const explicitSlippage = params.slippageBps !== undefined;\n const liquidityBps = explicitSlippage ? (dst.decimals > 8 ? requestedTolerance - 1 : requestedTolerance) : 0;\n const limitMode = liquidityBps > 0 ? \"liquidity_tolerance_bps\" : \"tolerance_bps\";\n // The HTTP status of the last quote answer, and whether it came without a JSON body (classifies a rejection).\n let quoteStatus = 0;\n let quoteBodyless = false;\n // The last quote answer's body was lost while the caller's own signal was aborted (hostGet reads it as no body):\n // what a missing body would say about the node is unknown, so only the status classifies it.\n let quoteBodyAborted = false;\n // `tolerance_bps` → LIM from the feeless spot output; `liquidity_tolerance_bps`\n // → LIM from the expected output after fees (the node accepts only one).\n const quoteOn = async (\n host: string,\n bps: string,\n limitMode: \"tolerance_bps\" | \"liquidity_tolerance_bps\" = \"tolerance_bps\",\n ): Promise<ThorQuoteResponse | null> => {\n const qs = new URLSearchParams({\n from_asset: fromAsset,\n to_asset: dst.asset,\n amount: amount1e8.toString(),\n destination: params.destAddress,\n [limitMode]: bps,\n // Pin a single (non-streaming) swap. Left to itself the node picks\n // streaming for thin pools (max_streaming_quantity > 1) and then\n // simulates the LIM per sub-swap — the adaptive retry could never\n // pass on BASE.ETH / BSC stables (verified 2026-09-16). We reject\n // streaming memos anyway, so the quote must be simulated atomically.\n streaming_quantity: \"1\",\n });\n if (configuredAffiliate && configuredAffiliateBps) {\n qs.set(\"affiliate\", configuredAffiliate);\n qs.set(\"affiliate_bps\", configuredAffiliateBps);\n }\n if (params.refundAddress) qs.set(\"refund_address\", params.refundAddress);\n const res = await hostGet(host, `/thorchain/quote/swap?${qs.toString()}`, clientId, signal);\n quoteStatus = res.status;\n quoteBodyless = res.body === null && !res.ok;\n quoteBodyAborted = res.body === null && signal?.aborted === true;\n if (Array.isArray(res.body)) return null;\n // A 4xx carries the node's rejection body (used by the adaptive retry).\n return (res.body ?? (res.ok ? null : {error: `HTTP ${res.status}`})) as ThorQuoteResponse | null;\n };\n\n // Host failover: the quote AND the inbound snapshot it is bound to must\n // come from one node. If either call fails at the host level, the whole\n // pair is re-run on the next host; a node's business rejection is final.\n let q: ThorQuoteResponse | null = null;\n let checkedMemo: ReturnType<typeof verifiedMemo> = null;\n let inbounds: InboundAddress[] | null = null;\n let quoteHost = \"\";\n let quoteHeight = 0;\n // When the vault check's budget ends (CONFIRM_BUDGET_MS from the moment the quote is in hand).\n let confirmDeadlineAt = 0;\n // A node answered its inbound addresses but not its THORChain height.\n let heightUnavailable = false;\n // Each failed host's classification (HostUnavailable), for the refusal when every host failed.\n const hostFailures: (Swap2RefusalInfo | undefined)[] = [];\n for (const host of hosts) {\n try {\n if (limitMode === \"liquidity_tolerance_bps\") {\n q = await quoteOn(host, String(liquidityBps), \"liquidity_tolerance_bps\");\n const feeBps = Number(q?.fees?.total_bps);\n if (Number.isFinite(feeBps) && feeBps > bigintToNumber(MAX_TOLERANCE_BPS)) {\n // Dust amounts: a fixed outbound fee eats the swap. `total_bps` also counts the liquidity (slip) fee, so a\n // large swap through a thin pool lands here too: this module's own fee cap, not a size limit (policy_refused).\n params.onRefusal?.(`thorchain: THORChain fees ${(feeBps / 100).toFixed(2)}% — too expensive at this amount (cap ${bigintToNumber(MAX_TOLERANCE_BPS) / 100}%)`, {reason: \"policy_refused\"});\n return null;\n }\n } else {\n q = await quoteOn(host, String(requestedTolerance));\n // Legacy quotes without a slippage: fees > tolerance makes the node\n // reject the quote; the rejection carries the actual emit vs the\n // limit the tolerance implied. ONE retry, on the same host, widens\n // the tolerance to what the pool needs (+buffer), capped. An\n // explicit 0 bp slippage is never widened — the rejection stands.\n const rejected = (q?.error ?? q?.message)?.match(/emit asset (\\d+) less than price limit (\\d+)/);\n if (rejected && !explicitSlippage) {\n const emit = BigInt(rejected[1] ?? \"0\");\n const limit = BigInt(rejected[2] ?? \"0\");\n if (emit > 0n && limit > emit) {\n // limit = spot × (1 − tolerance/10000) → spot; needed = 1 − emit/spot.\n const spot = (limit * 10000n) / (10000n - BigInt(requestedTolerance));\n const needed = 10000n - (emit * 10000n) / spot + 50n; // +0.5% buffer\n if (needed <= MAX_TOLERANCE_BPS) q = await quoteOn(host, needed.toString());\n }\n }\n }\n // Validate the node's answer BEFORE touching the network again: a\n // rejection, a malformed quote or an unbound memo is final.\n if (q?.error || q?.message) {\n // The node's own rejection (no pool, price limit, halted…) is the\n // caller's answer — surface it instead of an anonymous null.\n // A body lost to the caller's abort is not another shape (upstream_unavailable): its status alone, if it says.\n params.onRefusal?.(`thorchain: ${String(q.error ?? q.message).slice(0, 200)}`, quoteBodyAborted ? httpRefusal(quoteStatus) : quoteRejection(String(q.error ?? q.message), quoteStatus, quoteBodyless));\n return null;\n }\n if (!q || !q.expected_amount_out || !q.inbound_address || !q.memo || !q.expiry) {\n params.onRefusal?.(`thorchain: incomplete quote from ${host} (expected_amount_out / inbound_address / memo / expiry missing)`, quoteBodyAborted ? undefined : {reason: \"upstream_unavailable\", ...(quoteStatus >= 300 ? {httpStatus: quoteStatus} : {})});\n return null;\n }\n // A router is required for EVM and must be ABSENT for a deposit\n // source: a router on a Tron quote means the venue changed its\n // execution model and a plain send would no longer settle.\n if (chainId ? !q.router : !!q.router) {\n params.onRefusal?.(chainId ? \"thorchain: quote has no router for an EVM source\" : \"thorchain: quote names a router for a deposit source — execution model changed\", {reason: chainId ? \"upstream_unavailable\" : \"policy_refused\"});\n return null;\n }\n let memoRefusal: Swap2RefusalReason = \"recipient_mismatch\";\n checkedMemo = verifiedMemo(q.memo, dst.asset, params.destAddress, params.refundAddress ?? \"\", configuredAffiliate, configuredAffiliateBps, (why) => { memoRefusal = why; });\n if (!checkedMemo) {\n params.onRefusal?.(`thorchain: memo failed verification (${String(q.memo).slice(0, 80)})`, {reason: memoRefusal});\n return null;\n }\n const floor1e8 = params.minAmountOut !== undefined ? toThorUnitsCeil(BigInt(params.minAmountOut), dst.decimals) : undefined;\n if (floor1e8 !== undefined && checkedMemo.limit < floor1e8) {\n params.onRefusal?.(`thorchain: floor breach (limit=${checkedMemo.limit} < floor=${floor1e8}, 1e8 units)`, {reason: \"price_check_failed\"});\n return null;\n }\n // The quote is in hand: the vault check's own budget starts now, so time a failed host took before does\n // not count against it.\n const deadlineAt = Date.now() + CONFIRM_BUDGET_MS;\n // A quote gateway is not an authority for rotating vault/router\n // state. Bind it against a separately fetched no-store inbound\n // snapshot from the SAME host now, then repeat the check before broadcast.\n // The same host's THORChain height is what a confirming node's lag is measured against.\n const snapshot = await nodeSnapshot(host, signal);\n if (\"heightError\" in snapshot) {\n heightUnavailable = true;\n throw snapshot.heightError;\n }\n inbounds = snapshot.inbounds;\n quoteHeight = snapshot.height;\n quoteHost = host;\n confirmDeadlineAt = deadlineAt;\n break;\n } catch (error) {\n if (error instanceof HostUnavailable) {\n hostFailures.push(refusalOf(error));\n q = null;\n checkedMemo = null;\n inbounds = null;\n continue;\n }\n throw error;\n }\n }\n if (!q?.expected_amount_out || !q.inbound_address || !q.expiry || !checkedMemo || !inbounds) {\n params.onRefusal?.(\n inbounds\n ? \"thorchain: no quote from any node\"\n : heightUnavailable\n ? \"thorchain: THORChain height (/thorchain/lastblock) unavailable from every node that answered the inbound addresses\"\n : \"thorchain: inbound addresses unavailable from every node\",\n inbounds ? {reason: \"no_route\"} : nodesFailed(hostFailures),\n );\n return null;\n }\n const limit1e8 = checkedMemo.limit;\n const srcInbound = inbounds.find((entry) => entry.chain === THOR_CHAIN[params.sourceChain]);\n const dstInbound = inbounds.find((entry) => entry.chain === THOR_CHAIN[params.destChain]);\n if (paused(srcInbound) || paused(dstInbound)) {\n params.onRefusal?.(`thorchain: ${paused(srcInbound) ? THOR_CHAIN[params.sourceChain] : THOR_CHAIN[params.destChain]} chain is halted / paused on THORChain`, {reason: \"chain_halted\"});\n return null;\n }\n if (!sameTarget(srcInbound?.address, q.inbound_address)) {\n params.onRefusal?.(\"thorchain: quote inbound address differs from the node's current inbound (vault rotated) — retry\", {reason: \"vault_mismatch\"});\n return null;\n }\n if (chainId && !sameTarget(srcInbound?.router, q.router)) {\n params.onRefusal?.(\"thorchain: quote router differs from the node's current router — retry\", {reason: \"vault_mismatch\"});\n return null;\n }\n if (chainId && !pinnedRouter(params.sourceChain, q.router)) {\n params.onRefusal?.(`thorchain: router ${String(q.router)} is not a THORChain router this module trusts on ${params.sourceChain} (THORCHAIN_ROUTERS / trustedRouters)`, {reason: \"vault_mismatch\"});\n return null;\n }\n const unconfirmed = await confirmedElsewhere(\n quoteHost, quoteHeight, params.sourceChain, params.destChain, q.inbound_address, chainId ? q.router : undefined, confirmDeadlineAt, signal,\n );\n if (unconfirmed) {\n params.onRefusal?.(`thorchain: ${unconfirmed.text}`, unconfirmed.info);\n return null;\n }\n const tooSmall = belowThorMinimums(amount1e8, srcInbound, q);\n if (tooSmall) {\n params.onRefusal?.(`thorchain: ${tooSmall}`, {reason: \"amount_too_small\"});\n return null;\n }\n\n // expected_amount_out is 1e8 of the DEST asset → base units.\n const outUnits = (BigInt(q.expected_amount_out) * 10n ** BigInt(dst.decimals)) / 100000000n;\n if (outUnits <= 0n) {\n params.onRefusal?.(\"thorchain: expected output rounds to zero\", {reason: \"amount_too_small\"});\n return null;\n }\n const memoMinUnits = (limit1e8 * 10n ** BigInt(dst.decimals)) / 100_000_000n;\n const minUnits = memoMinUnits;\n if (minUnits <= 0n || minUnits > outUnits) {\n params.onRefusal?.(`thorchain: memo limit ${limit1e8} inconsistent with expected output ${q.expected_amount_out}`, {reason: \"price_check_failed\"});\n return null;\n }\n // The caller's slippage is measured from the quoted output, as validQuote\n // does for every provider. A memo LIM below that floor would only be\n // dropped later as an anonymous validation failure — name it here.\n if (params.slippageBps !== undefined) {\n const slippageFloor = (outUnits * BigInt(10_000 - params.slippageBps)) / 10_000n;\n if (minUnits < slippageFloor) {\n params.onRefusal?.(`thorchain: memo limit ${limit1e8} is below expected ${q.expected_amount_out} minus ${params.slippageBps} bps slippage (1e8 units)`, {reason: \"price_check_failed\"});\n return null;\n }\n }\n\n const nowSeconds = Math.floor(Date.now() / 1000);\n const executionExpiry = Math.min(q.expiry, nowSeconds + 15 * 60);\n if (!Number.isInteger(executionExpiry) || executionExpiry <= nowSeconds + 30) {\n params.onRefusal?.(`thorchain: quote expires in ${Number.isInteger(executionExpiry) ? executionExpiry - nowSeconds : \"?\"} s — too soon to execute`, {reason: \"quote_expired\"});\n return null;\n }\n const assetAddr = (src.contract ? src.contract : NATIVE) as `0x${string}`;\n const common = {\n provider: \"thorchain\",\n intentId: `thorchain:${chainId ?? THOR_CHAIN[params.sourceChain]}`,\n sourceAmount: params.amountIn,\n destAmount: outUnits.toString(),\n minDestAmount: minUnits.toString(),\n feeUsd: 0, // destAmount is already net of THORChain fees\n etaSeconds: q.total_swap_seconds ?? 120,\n reliability: 0.9,\n // Validity must outlive the ERC-20 approval leg: for USDT that is\n // approve(0) + approve(n), each awaited to inclusion (≈2 blocks), so a\n // 60 s window expired before the deposit and only the revoke went out\n // (2026-09-16). The on-chain LIM bounds price movement and preflight\n // re-checks vault/router/halts right before broadcast, so a longer\n // window costs nothing in safety.\n validUntilMs: Math.min(Date.now() + QUOTE_VALIDITY_MS, executionExpiry * 1000),\n providerData: {\n sourceChain: params.sourceChain,\n destChain: params.destChain,\n inboundAddress: q.inbound_address,\n router: q.router ?? \"\",\n assetAddress: assetAddr,\n expiry: String(executionExpiry),\n memo: checkedMemo.canonical,\n },\n };\n\n // Deposit source (Tron): the engine sends `sourceAmount` of the source\n // asset to the inbound vault with the canonical memo attached on-chain.\n if (!chainId) {\n return {...common, depositAddress: q.inbound_address, depositMemo: checkedMemo.canonical};\n }\n\n // EVM: router calldata depositWithExpiry(asgardVault, asset, amount, memo, expiry).\n const data = encodeFunctionData({\n abi: ROUTER_ABI,\n functionName: \"depositWithExpiry\",\n args: [q.inbound_address as `0x${string}`, assetAddr, amountIn, checkedMemo.canonical, BigInt(executionExpiry)],\n });\n return {\n ...common,\n depositAddress: \"\",\n depositMemo: null,\n txRequest: {\n to: q.router!,\n data,\n value: src.contract ? \"0\" : params.amountIn,\n chainId: chainId!,\n ...(src.contract ? {approvalAddress: q.router!} : {}),\n },\n };\n },\n\n async buildDeposit(quote: Quote): Promise<UnsignedTx> {\n if (!quote.txRequest) {\n const sourceChain = quote.providerData?.sourceChain ?? \"\";\n if (!isDepositSource(sourceChain) || !quote.depositAddress || !quote.depositMemo) {\n throw refusal(\"unsupported_pair\", \"thorchain: deposit-address execution is only supported for an opted-in Tron source\");\n }\n // Plain send to the inbound vault (the engine turns a TRC-20 source\n // into transfer()); the memo MUST ride on-chain in raw_data.data.\n return {chain: sourceChain, to: quote.depositAddress, value: quote.sourceAmount, memo: quote.depositMemo};\n }\n return {\n chain: \"\",\n to: quote.txRequest?.to ?? \"\",\n value: quote.txRequest?.value ?? \"0\",\n ...(quote.txRequest?.data ? {data: quote.txRequest.data} : {}),\n ...(quote.txRequest?.chainId !== undefined ? {chainId: quote.txRequest.chainId} : {}),\n ...(quote.txRequest?.gasLimit ? {gasLimit: quote.txRequest.gasLimit} : {}),\n ...(quote.txRequest?.approvalAddress ? {approvalAddress: quote.txRequest.approvalAddress} : {}),\n };\n },\n\n async preflightDeposit(quote: Quote, tx: UnsignedTx): Promise<void> {\n const data = quote.providerData;\n if (!data?.sourceChain || !data.destChain || !data.inboundAddress || !data.assetAddress || !data.expiry || !data.memo) {\n throw refusal(\"policy_refused\", \"thorchain: quote is missing execution-bound metadata\");\n }\n const evmSource = CHAIN_ID[data.sourceChain] !== undefined;\n if (evmSource && !data.router) throw refusal(\"policy_refused\", \"thorchain: quote is missing execution-bound metadata\");\n if (!evmSource && !isDepositSource(data.sourceChain)) throw refusal(\"unsupported_pair\", \"thorchain: source chain has no executor\");\n if (!/^\\d+$/.test(data.expiry) || BigInt(data.expiry) <= BigInt(Math.floor(Date.now() / 1000))) {\n throw refusal(\"quote_expired\", \"thorchain: quote expired before broadcast\");\n }\n if (evmSource && !pinnedRouter(data.sourceChain, data.router)) throw refusal(\"vault_mismatch\", \"thorchain: the quote's router is not one this module trusts\");\n let inbounds: InboundAddress[] | null = null;\n let snapshotHost = \"\";\n let snapshotHeight = 0;\n let confirmDeadlineAt = 0;\n let heightUnavailable = false;\n // Each failed host's classification (HostUnavailable), for the refusal when every host failed.\n const hostFailures: (Swap2RefusalInfo | undefined)[] = [];\n for (const host of hosts) {\n // The re-check's budget starts when this node is asked; a host that failed before does not use it up.\n const deadlineAt = Date.now() + CONFIRM_BUDGET_MS;\n try {\n const snapshot = await nodeSnapshot(host);\n if (\"heightError\" in snapshot) {\n heightUnavailable = true;\n hostFailures.push(refusalOf(snapshot.heightError));\n continue;\n }\n inbounds = snapshot.inbounds;\n snapshotHeight = snapshot.height;\n snapshotHost = host;\n confirmDeadlineAt = deadlineAt;\n break;\n } catch (error) {\n inbounds = null;\n if (!(error instanceof HostUnavailable)) throw error;\n hostFailures.push(refusalOf(error));\n }\n }\n if (!inbounds) {\n throw withReason(new Error(\n heightUnavailable\n ? \"thorchain: cannot read THORChain height (/thorchain/lastblock) before broadcast from any node that answered the inbound addresses\"\n : \"thorchain: cannot refresh inbound addresses before broadcast\",\n ), nodesFailed(hostFailures));\n }\n // The vault the funds go to is confirmed by a second node right before broadcast too (after this node's own checks).\n const confirm = async () => {\n const unconfirmed = await confirmedElsewhere(\n snapshotHost, snapshotHeight, data.sourceChain!, data.destChain, data.inboundAddress!, evmSource ? data.router : undefined, confirmDeadlineAt,\n );\n if (unconfirmed) throw withReason(new Error(`thorchain: ${unconfirmed.text}`), unconfirmed.info);\n };\n const src = inbounds.find((entry) => entry.chain === THOR_CHAIN[data.sourceChain!]);\n const dst = inbounds.find((entry) => entry.chain === THOR_CHAIN[data.destChain!]);\n if (paused(src) || paused(dst)) throw refusal(\"chain_halted\", \"thorchain: source or destination chain trading is paused\");\n if (!sameTarget(src?.address, data.inboundAddress)) throw refusal(\"vault_mismatch\", \"thorchain: inbound vault rotated after quote\");\n if (!evmSource) {\n // Deposit source: exactly a plain send of the validated amount to the\n // validated vault carrying the validated memo — nothing else.\n if (tx.data !== undefined || tx.approvalAddress !== undefined || tx.bodyBoc !== undefined || tx.typedData !== undefined || tx.serializedTx !== undefined || tx.stateInitBoc !== undefined) {\n throw refusal(\"policy_refused\", \"thorchain: deposit-address execution must be a plain send with memo\");\n }\n if (!sameTarget(tx.to, data.inboundAddress) || tx.memo !== data.memo || tx.value !== quote.sourceAmount || (tx.chain && tx.chain !== data.sourceChain)) {\n // Another recipient than the validated vault is a changed deposit target; any other difference, a changed send.\n throw refusal(!sameTarget(tx.to, data.inboundAddress) ? \"vault_mismatch\" : \"policy_refused\", \"thorchain: deposit does not match the validated quote\");\n }\n const srcAsset = ccAssetByToken(data.sourceChain, sameTarget(data.assetAddress, NATIVE) ? \"\" : data.assetAddress);\n if (!srcAsset) throw refusal(\"unsupported_pair\", \"thorchain: unknown source asset\");\n const amount1e8 = (BigInt(quote.sourceAmount) * 100_000_000n) / 10n ** BigInt(srcAsset.decimals);\n const tooSmall = belowThorMinimums(amount1e8, src, null);\n if (tooSmall) throw refusal(\"amount_too_small\", `thorchain: ${tooSmall}`);\n await confirm();\n return;\n }\n if (!sameTarget(src?.router, data.router) || !sameTarget(tx.to, data.router)) {\n throw refusal(\"vault_mismatch\", \"thorchain: router rotated after quote\");\n }\n if (!tx.data) throw refusal(\"policy_refused\", \"thorchain: missing depositWithExpiry calldata\");\n let decoded: {functionName: string; args?: readonly unknown[]};\n try {\n decoded = decodeFunctionData({abi: ROUTER_ABI, data: tx.data as `0x${string}`});\n } catch {\n throw refusal(\"policy_refused\", \"thorchain: malformed depositWithExpiry calldata\");\n }\n const args = decoded.args;\n if (\n decoded.functionName !== \"depositWithExpiry\" || !args || args.length !== 5 ||\n !sameTarget(String(args[0]), data.inboundAddress) ||\n !sameTarget(String(args[1]), data.assetAddress) ||\n BigInt(args[2] as bigint) !== BigInt(quote.sourceAmount) ||\n String(args[3]) !== data.memo || BigInt(args[4] as bigint) !== BigInt(data.expiry) ||\n tx.chainId !== CHAIN_ID[data.sourceChain]\n ) {\n // The call pays another vault than the validated one: a changed deposit target; any other difference, a changed call.\n const vaultChanged = decoded.functionName === \"depositWithExpiry\" && !!args && args.length === 5 && !sameTarget(String(args[0]), data.inboundAddress);\n throw refusal(vaultChanged ? \"vault_mismatch\" : \"policy_refused\", \"thorchain: calldata does not match the validated quote\");\n }\n const tokenSource = !sameTarget(data.assetAddress, NATIVE);\n if (\n tx.value !== (tokenSource ? \"0\" : quote.sourceAmount) ||\n (tokenSource ? !sameTarget(tx.approvalAddress, data.router) : tx.approvalAddress !== undefined)\n ) {\n // An approval for another spender than the validated router is a changed deposit target; any other difference, a changed call.\n const spenderChanged = tokenSource && tx.approvalAddress !== undefined && !sameTarget(tx.approvalAddress, data.router);\n throw refusal(spenderChanged ? \"vault_mismatch\" : \"policy_refused\", \"thorchain: value/approval does not match the validated source asset\");\n }\n await confirm();\n },\n\n async trackIntent(ref: IntentRef): Promise<IntentStatus> {\n if (!ref.sourceTxHash) return {state: \"pending\"}; // not broadcast yet\n // THORNode keys EVM inbounds by the tx hash without 0x, uppercase.\n if (!/^(?:0x)?[0-9a-fA-F]{64}$/.test(ref.sourceTxHash)) {\n throw new Error(\"thorchain: source transaction hash must be 32-byte hex\");\n }\n const hash = ref.sourceTxHash.replace(/^0x/i, \"\").toUpperCase();\n const j = await thornodeGet(`/thorchain/tx/status/${hash}`, undefined, hosts, clientId) ??\n await thornodeGet(`/thorchain/tx/${hash}`, undefined, hosts, clientId);\n if (!j) return {state: \"pending\"};\n const stages = j.stages as {\n inbound_observed?: {started?: boolean; completed?: boolean};\n inbound_finalised?: {completed?: boolean};\n outbound_signed?: {completed?: boolean};\n } | undefined;\n if (stages) {\n const planned = (j.planned_out_txs ?? []) as {refund?: boolean}[];\n const refunded = planned.some((out) => out.refund === true);\n const delivered = planned.some((out) => out.refund === false);\n const outTxs = (j.out_txs ?? []) as {id?: string; memo?: string}[];\n const outHash = outTxs.find((out) => typeof out.id === \"string\" && out.id.length > 0 && !/^0+$/.test(out.id))?.id;\n const deliveredHash = outTxs.find((out) =>\n typeof out.id === \"string\" && out.id.length > 0 && !/^0+$/.test(out.id) && typeof out.memo === \"string\" && !/^REFUND/i.test(out.memo)\n )?.id;\n if (stages.outbound_signed?.completed) {\n // `completed` describes the signing stage, not the economic outcome.\n // A truncated/malformed status response with no classified plan or\n // observed outbound must not be promoted to successful delivery.\n if ((!refunded && !delivered) || !outHash) {\n return {state: \"pending\", depositReceived: true};\n }\n return refunded && delivered\n // A refund hash is not a destination transaction. For mixed plans,\n // expose a hash only when the observed outbound is classifiable.\n ? {state: \"partial\", depositReceived: true, ...(deliveredHash ? {destTxHash: deliveredHash} : {})}\n : refunded\n ? {state: \"refunded\", depositReceived: true}\n : {state: \"completed\", depositReceived: true, ...(outHash ? {destTxHash: outHash} : {})};\n }\n return {\n state: \"pending\",\n depositReceived: !!(stages.inbound_observed?.started || stages.inbound_observed?.completed || stages.inbound_finalised?.completed),\n };\n }\n const obs = j.observed_tx as {status?: string; out_hashes?: string[]} | undefined;\n const outHash = obs?.out_hashes?.find((h) => typeof h === \"string\" && h.length > 0 && !/^0+$/.test(h));\n if (obs?.status === \"done\") {\n // A slipped-past-LIM (or halted) swap ALSO finalizes \"done\", but its\n // outbound is a REFUND to the source chain — never report that as a\n // completed swap (audit M1). Planned outbounds carry the memo.\n const planned = (j.planned_out_txs ?? j.out_txs ?? []) as {memo?: string; refund?: boolean}[];\n const refunded = planned.some(\n (o) => o?.refund === true || /^REFUND/i.test(o?.memo ?? \"\"),\n );\n const delivered = planned.some(\n (o) => o?.refund === false && !/^REFUND/i.test(o?.memo ?? \"\"),\n );\n if ((!refunded && !delivered) || !outHash) return {state: \"pending\", depositReceived: true};\n if (refunded && delivered) return {state: \"partial\", depositReceived: true};\n if (refunded) return {state: \"refunded\", depositReceived: true};\n return {state: \"completed\", ...(outHash ? {destTxHash: outHash} : {})};\n }\n return {state: \"pending\", depositReceived: !!obs};\n },\n };\n}\n","import {evmRef, isEvm, namespace} from \"@anywalletkit/protocol-swap2-core/util\";\n\n// ── THORChain — native L1 assets: BTC/ETH/BSC/BASE/Cosmos/Tron/Solana, and\n// (2026-08, pools live) XRP/LTC/DOGE/BCH + GAIA.ATOM ──────────────────────\n// Only EVM source executors actually implemented by provider.ts.\nconst THOR_EVM = new Set([1, 8453, 56, 43114]); // ETH, BASE, BSC, AVAX (2026-09-16)\nconst THOR_NS = new Set([\"bitcoin\", \"cosmos\", \"solana\", \"tron\", \"xrp\", \"litecoin\", \"doge\", \"bch\"]);\nexport const thorchain = {\n enabled: () => true,\n affiliate: () => \"\",\n affiliateBps: () => \"\",\n supportsChain(chain: string): boolean {\n if (THOR_NS.has(namespace(chain))) return true;\n return isEvm(chain) && THOR_EVM.has(evmRef(chain));\n },\n supports(from: string, to: string): boolean {\n return this.supportsChain(from) && this.supportsChain(to);\n },\n};\n","/**\n * Activity recognition for THORChain on its EVM source chains.\n *\n * Routers and Asgard vaults rotate, so nothing is matched by address: the\n * THORChain router ABI is unique enough. `depositWithExpiry` is our source leg\n * (`bridge`, \"Bridged A\"; `swap` when the swap settled back on the same chain\n * and both legs netted). `transferOut` / `transferOutAndCall` are the router\n * paying a destination leg — recognized only when the owner actually received\n * something (\"Received A via THORChain\"). Native sends to an inbound vault with\n * a memo (Tron, BTC) carry no router call and are not recognizable offline.\n */\nimport type {ActivityItem, ChainTx, DescribeActivityContext} from \"@anywalletkit/core\";\nimport {callSelector, describeSwapLike, ownerAssets} from \"@anywalletkit/protocol-swap2-core/activity\";\nimport {thorchain as thorchainCfg} from \"./config.js\";\n\nexport const THORCHAIN_MODULE = \"@anywalletkit/protocol-swap2-thorchain\";\n\n/** depositWithExpiry(address,address,uint256,string,uint256) */\nexport const THORCHAIN_DEPOSIT_WITH_EXPIRY = \"0x44bc937b\";\n/** transferOut(address,address,uint256,string) */\nexport const THORCHAIN_TRANSFER_OUT = \"0x574da717\";\n/** transferOutAndCall(address,address,uint256,address,address,string) */\nexport const THORCHAIN_TRANSFER_OUT_AND_CALL = \"0xec341444\";\n\nexport function describeThorchainActivity(tx: ChainTx, ctx: DescribeActivityContext): ActivityItem | null {\n if (!tx.chain.startsWith(\"eip155:\") || !thorchainCfg.supportsChain(tx.chain)) return null;\n const selector = callSelector(tx);\n if (selector === THORCHAIN_DEPOSIT_WITH_EXPIRY) {\n // The owner must be the depositor: a stranger's deposit that paid us is a transferOut, not ours.\n const isOwn = (a: string) => ctx.own.has(a) || ctx.own.has(a.toLowerCase());\n if (!isOwn(tx.from)) return null;\n return describeSwapLike(tx, ctx, {protocol: THORCHAIN_MODULE, subtitle: \"THORChain\", kind: \"auto\"});\n }\n if (selector === THORCHAIN_TRANSFER_OUT || selector === THORCHAIN_TRANSFER_OUT_AND_CALL) {\n const {assetsIn} = ownerAssets(tx, ctx);\n if (assetsIn.length === 0) return null;\n return describeSwapLike(tx, ctx, {protocol: THORCHAIN_MODULE, subtitle: \"THORChain\", kind: \"bridge\", inSuffix: \"via THORChain\"});\n }\n return null;\n}\n","/**\n * What a confirming THORNode is asked, how its answers are read, and the rule that decides whether it confirms the\n * vault a quote (or a remote build) pays (the second-node check of scan 2026-10-27 modules, F15). Shapes follow the\n * THORNode OpenAPI (`LastBlockResponse`, `InboundAddressesResponse`, `VaultsResponse`, `MimirResponse`); every reader\n * checks the type of each field it reads and returns null on anything else, so a node that answers in another shape\n * (a field of another type included) is skipped, never trusted. The provider's confirming nodes and\n * `thorchainPins().verifyBuild` on the device apply the same rule ({@link vaultVerdict}); the quoting node's\n * `inbound_addresses` and `lastblock` go through the same readers, and another shape makes that node unavailable.\n */\n\nimport {httpRefusal, withReason, type Swap2RefusalInfo} from \"@anywalletkit/protocol-swap2-core/errors\";\n\n/**\n * The only reads sent to a confirming node: GET, these fixed paths, no query string, no body. A proxy in front of a\n * node may pass exactly these and refuse everything else. `lastblock` and `inbound_addresses` go to every node;\n * `vaults/asgard` and `mimir` only when the node's current inbound vault is not the one the quote names.\n */\nexport const THORNODE_CONFIRM_PATHS = Object.freeze({\n lastblock: \"/thorchain/lastblock\",\n inboundAddresses: \"/thorchain/inbound_addresses\",\n asgardVaults: \"/thorchain/vaults/asgard\",\n mimir: \"/thorchain/mimir\",\n} as const);\n\n/**\n * Blocks a confirming node may trail the reference height before it is skipped for the next one. Public nodes\n * reachable from a browser ran ~25–28 blocks behind the Liquify gateway on 2026-11-12.\n */\nexport const DEFAULT_CONFIRM_MAX_LAG_BLOCKS = 50;\n/** Time one confirming node gets for all of its reads. */\nexport const DEFAULT_CONFIRM_TIMEOUT_MS = 2_500;\n/** The smallest per-node time: `confirmTimeoutMs` may not be lower, and no node is asked with less budget left. */\nexport const MIN_CONFIRM_TIMEOUT_MS = 100;\n/** The largest `confirmTimeoutMs` (and the provider's confirmation budget). */\nexport const MAX_CONFIRM_TIMEOUT_MS = 8_000;\n\n/** Validated `confirmMaxLagBlocks` / `confirmTimeoutMs`, defaults filled in; throws on anything else. */\nexport function confirmOptions(o: {confirmMaxLagBlocks?: number; confirmTimeoutMs?: number}): {maxLagBlocks: number; timeoutMs: number} {\n const maxLagBlocks = o.confirmMaxLagBlocks ?? DEFAULT_CONFIRM_MAX_LAG_BLOCKS;\n if (!Number.isInteger(maxLagBlocks) || maxLagBlocks < 0 || maxLagBlocks > 100_000) {\n throw new Error(\"thorchain: confirmMaxLagBlocks must be an integer between 0 and 100000\");\n }\n const timeoutMs = o.confirmTimeoutMs ?? DEFAULT_CONFIRM_TIMEOUT_MS;\n if (!Number.isInteger(timeoutMs) || timeoutMs < MIN_CONFIRM_TIMEOUT_MS || timeoutMs > MAX_CONFIRM_TIMEOUT_MS) {\n throw new Error(`thorchain: confirmTimeoutMs must be an integer between ${MIN_CONFIRM_TIMEOUT_MS} and ${MAX_CONFIRM_TIMEOUT_MS}`);\n }\n return {maxLagBlocks, timeoutMs};\n}\n\n/**\n * A host-level failure (unreachable, gateway error, rate-limited, blocked, redirected, another shape): the next host\n * may answer. Anything else the node says — including a 4xx business rejection such as \"no pool\" — is an answer, not\n * a reason to shop the same question to another node.\n */\nexport class HostUnavailable extends Error {\n /**\n * `info` classifies the failure (`refusalOf` reads it back): what the HTTP status says (429 `rate_limited`, 401 / 403\n * `key_rejected`), else `upstream_unavailable` — unreachable, timed out, a 5xx, redirected or another shape.\n */\n constructor(host: string, reason: string, info?: Swap2RefusalInfo) {\n super(`thorchain: ${host} unavailable (${reason})`);\n withReason(this, info ?? \"upstream_unavailable\");\n }\n}\n\n/** A non-2xx answer's classification: what its status says, else `upstream_unavailable` with the status. */\nexport function statusRefusal(status: number, retryAfter?: string | null): Swap2RefusalInfo {\n return httpRefusal(status, retryAfter) ?? {reason: \"upstream_unavailable\", httpStatus: status};\n}\n\nexport interface InboundAddress {\n chain?: string;\n address?: string;\n router?: string;\n halted?: boolean;\n global_trading_paused?: boolean;\n chain_trading_paused?: boolean;\n /** 1e8 source units; inbounds at or below it are IGNORED by THORChain. */\n dust_threshold?: string;\n}\n\n/** No entry for the chain, or the chain halted / trading paused. */\nexport function paused(entry: InboundAddress | undefined): boolean {\n return !entry || entry.halted === true || entry.global_trading_paused === true || entry.chain_trading_paused === true;\n}\n\n/** Same address: EVM (`0x…`) case-insensitively, every other chain exactly. Anything but two non-empty strings is not. */\nexport function sameTarget(a: unknown, b: unknown): boolean {\n if (typeof a !== \"string\" || typeof b !== \"string\" || !a || !b) return false;\n return a.startsWith(\"0x\") || b.startsWith(\"0x\") ? a.toLowerCase() === b.toLowerCase() : a === b;\n}\n\n/**\n * A signal that aborts after `ms` or when `outer` aborts, and `clear()` that drops the timer and the listener and\n * aborts whatever read of that node is still running (a sibling of one that failed). Built from AbortController +\n * setTimeout (no AbortSignal.timeout / AbortSignal.any: Hermes lacks them).\n */\nexport function nodeDeadline(ms: number, outer?: AbortSignal): {signal: AbortSignal; clear(): void} {\n const ctrl = new AbortController();\n const timer = setTimeout(() => ctrl.abort(), Math.max(0, ms));\n const onAbort = () => ctrl.abort();\n if (outer) {\n if (outer.aborted) ctrl.abort();\n else outer.addEventListener(\"abort\", onAbort);\n }\n return {\n signal: ctrl.signal,\n clear() {\n clearTimeout(timer);\n outer?.removeEventListener(\"abort\", onAbort);\n if (!ctrl.signal.aborted) ctrl.abort();\n },\n };\n}\n\n/** True when `actual` (a Response's `url`) is `expected` itself: no redirect elsewhere, no query, no fragment. */\nexport function sameRequestUrl(actual: unknown, expected: string): boolean {\n if (actual === undefined || actual === null || actual === \"\") return true; // runtimes that do not report it\n if (typeof actual !== \"string\") return false;\n try {\n const a = new URL(actual);\n const e = new URL(expected);\n return a.origin === e.origin && a.pathname === e.pathname && a.search === \"\" && a.hash === \"\";\n } catch {\n return false;\n }\n}\n\n/**\n * One read for the vault check (THORNODE_CONFIRM_PATHS): GET on a fixed path, no query string, no `cache` option —\n * React Native's fetch turns `cache: \"no-store\"` into a `?_=<time>` query, which a pass-through proxy refuses; THORNode\n * answers carry no cache validators, so nothing is reused. A redirect (`redirect: \"error\"`, and by `res.url` where a\n * runtime follows redirects itself, as React Native's fetch does), a non-2xx status or a body that is not JSON is a\n * host failure (the next node is asked); `outer` aborting is the caller giving up and is rethrown as is.\n */\nexport async function nodeRead(host: string, path: string, clientId: string, signal: AbortSignal, outer?: AbortSignal): Promise<unknown> {\n const url = `${host}${path}`;\n let res: Response;\n try {\n res = await fetch(url, {method: \"GET\", headers: {accept: \"application/json\", \"x-client-id\": clientId}, redirect: \"error\", signal});\n } catch (error) {\n if (outer?.aborted) throw error;\n throw new HostUnavailable(host, error instanceof Error ? error.message : \"fetch failed\");\n }\n if (res.redirected === true || !sameRequestUrl(res.url, url)) throw new HostUnavailable(host, `${path} redirected`);\n if (!res.ok) throw new HostUnavailable(host, `${path} HTTP ${res.status}`, statusRefusal(res.status, res.headers?.get?.(\"retry-after\")));\n try {\n return await res.json();\n } catch (error) {\n if (outer?.aborted) throw error;\n throw new HostUnavailable(host, `${path} is not JSON`);\n }\n}\n\n/** An int64 JSON field: a number, or (proto3 JSON) a decimal string. */\nfunction int64(v: unknown): number | null {\n if (typeof v === \"number\") return Number.isSafeInteger(v) ? v : null;\n if (typeof v === \"string\" && /^-?\\d{1,15}$/.test(v)) return Number(v);\n return null;\n}\n\nconst isObject = (v: unknown): v is Record<string, unknown> => typeof v === \"object\" && v !== null && !Array.isArray(v);\n\n/** The string fields read from an inbound entry (THORNode `InboundAddress`: `string`, omitted when empty). */\nconst INBOUND_STRINGS = [\"address\", \"router\", \"dust_threshold\"] as const;\n/** The halt / pause flags read from an inbound entry (THORNode `InboundAddress`: `bool`). */\nconst INBOUND_FLAGS = [\"halted\", \"global_trading_paused\", \"chain_trading_paused\"] as const;\n\n/**\n * `GET /thorchain/inbound_addresses`: one entry per chain with the fields this module reads, or null for another\n * shape — an entry that is not an object, a `chain` that is not a string, an `address`, `router` or `dust_threshold`\n * present and not a string, a `halted`, `global_trading_paused` or `chain_trading_paused` present and not a boolean.\n * Fields this module does not read are left out unchecked.\n */\nexport function inboundAddresses(body: unknown): InboundAddress[] | null {\n if (!Array.isArray(body)) return null;\n const out: InboundAddress[] = [];\n for (const e of body) {\n if (!isObject(e) || typeof e.chain !== \"string\") return null;\n const entry: InboundAddress = {chain: e.chain};\n for (const k of INBOUND_STRINGS) {\n const v = e[k];\n if (v === undefined) continue;\n if (typeof v !== \"string\") return null;\n entry[k] = v;\n }\n for (const k of INBOUND_FLAGS) {\n const v = e[k];\n if (v === undefined) continue;\n if (typeof v !== \"boolean\") return null;\n entry[k] = v;\n }\n out.push(entry);\n }\n return out;\n}\n\n/**\n * THORChain's own block height from `GET /thorchain/lastblock` (the highest `thorchain` field of its entries), or null\n * for another shape: not a non-empty list, an entry that is not an object, a `thorchain` that is not a non-negative\n * int64 (a safe integer, or a decimal string of up to 15 digits). The other fields of an entry are not read.\n */\nexport function lastblockHeight(body: unknown): number | null {\n if (!Array.isArray(body) || body.length === 0) return null;\n let height = -1;\n for (const entry of body) {\n if (!isObject(entry)) return null;\n const h = int64(entry.thorchain);\n if (h === null || h < 0) return null;\n if (h > height) height = h;\n }\n return height;\n}\n\nexport interface AsgardVaultView {\n pubKey: string;\n status: string;\n addresses: readonly {chain: string; address: string}[];\n}\n\n/**\n * `GET /thorchain/vaults/asgard`: each vault's pub key, status and per-chain addresses, or null for another shape — a\n * vault that is not an object, a `status` that is not a string, a `pub_key` that is not a `thorpub1…` string, a\n * `type` present and not \"AsgardVault\", `addresses` not a list, an address entry that is not an object or whose\n * `chain` or `address` is not a string.\n */\nexport function asgardVaults(body: unknown): AsgardVaultView[] | null {\n if (!Array.isArray(body)) return null;\n const out: AsgardVaultView[] = [];\n for (const v of body) {\n if (!isObject(v)) return null;\n if (typeof v.status !== \"string\" || typeof v.pub_key !== \"string\" || !/^thorpub1[0-9a-z]{20,}$/.test(v.pub_key)) return null;\n if (v.type !== undefined && v.type !== \"AsgardVault\") return null;\n if (!Array.isArray(v.addresses)) return null;\n const addresses: {chain: string; address: string}[] = [];\n for (const a of v.addresses) {\n if (!isObject(a) || typeof a.chain !== \"string\" || typeof a.address !== \"string\") return null;\n addresses.push({chain: a.chain, address: a.address});\n }\n out.push({pubKey: v.pub_key, status: v.status, addresses});\n }\n return out;\n}\n\nexport type VaultFlag = \"compromised\" | \"insolvent\";\n\n/**\n * `GET /thorchain/mimir` read for one vault: THORNode drops a vault from inbound election while\n * `CompromisedVault-<pubkey>` or any `SolvencyHaltVault-<pubkey>-<chain>` is above zero, and no-ops an inbound to a\n * compromised vault (funds are not credited). Returns a lookup, or null when the answer is not a mimir map: not a\n * non-empty object, or a value that is neither a number nor a string (THORNode's mimir is a map of int64, which JSON\n * writes either way; values above 2^53 such as `MAXIMUMLIQUIDITYRUNE` are numbers too, so only the type is checked\n * here). A flag's value must also be an int64 ({@link int64}); the lookup answers \"malformed\" when it is not.\n */\nexport function mimirFlags(body: unknown): ((pubKey: string) => VaultFlag | null | \"malformed\") | null {\n if (!isObject(body) || Object.keys(body).length === 0) return null;\n const keys = Object.keys(body).map((k) => [k.toUpperCase(), body[k]] as const);\n if (keys.some(([, value]) => typeof value !== \"number\" && typeof value !== \"string\")) return null;\n return (pubKey: string) => {\n const pub = pubKey.toUpperCase();\n const compromisedKey = `COMPROMISEDVAULT-${pub}`;\n const insolventPrefix = `SOLVENCYHALTVAULT-${pub}-`;\n let flag: VaultFlag | null = null;\n for (const [key, value] of keys) {\n const kind: VaultFlag | null = key === compromisedKey ? \"compromised\" : key.startsWith(insolventPrefix) ? \"insolvent\" : null;\n if (!kind) continue;\n const n = int64(value);\n if (n === null) return \"malformed\";\n if (n > 0 && flag !== \"compromised\") flag = kind;\n }\n return flag;\n };\n}\n\n/** What a node is asked to confirm. Chains in THORChain notation (`ETH`, `BASE`, `TRON`, `BTC`…). */\nexport interface VaultClaim {\n /** The source chain: its inbound entry carries the vault (and router) and must be open. */\n chain: string;\n /** The destination chain, which must be open too; omitted when only the source is checked. */\n destChain?: string;\n /** The vault the funds go to (the router call's `vault`, or the deposit's recipient). */\n vault: string;\n /** EVM: the router the transaction calls, which must be the node's router for the chain. */\n router?: string;\n}\n\n/** A node's answer to a {@link VaultClaim}. */\nexport type VaultVerdict =\n | {ok: true}\n | {ok: false; why: \"halted\"; chain: string}\n | {ok: false; why: \"another-vault\"}\n | {ok: false; why: \"not-active\"; status: string}\n | {ok: false; why: \"flagged\"; flag: VaultFlag}\n | {ok: false; why: \"another-router\"};\n\n/** A node's THORChain height (`lastblock`) and its raw `inbound_addresses` answer, read in parallel. */\nexport async function nodeHead(host: string, read: (path: string) => Promise<unknown>): Promise<{height: number; inbound: unknown}> {\n const [lastblock, inbound] = await Promise.all([read(THORNODE_CONFIRM_PATHS.lastblock), read(THORNODE_CONFIRM_PATHS.inboundAddresses)]);\n const height = lastblockHeight(lastblock);\n if (height === null) throw new HostUnavailable(host, \"lastblock is not a THORNode lastblock list\");\n return {height, inbound};\n}\n\n/**\n * One node's verdict on the vault (and router) a quote or a build names. The vault must be the node's current inbound\n * address for the source chain, or — the inbound rotates among the active vaults every few minutes, and a node a few\n * blocks behind still names the previous one — that chain's address of a vault the node lists as ActiveVault in\n * `/thorchain/vaults/asgard` that its mimir does not flag compromised or insolvent (THORNode leaves those out of\n * inbound election). A RetiringVault, or any other status, never confirms. Both chains must be open, and on EVM the\n * node's router must be the claim's. `vaults/asgard` and `mimir` are read only when the current inbound differs.\n * Throws HostUnavailable when the node answers in another shape, a field of another type included\n * ({@link inboundAddresses}, {@link asgardVaults}, {@link mimirFlags}).\n */\nexport async function vaultVerdict(host: string, read: (path: string) => Promise<unknown>, inbound: unknown, claim: VaultClaim): Promise<VaultVerdict> {\n if (!Array.isArray(inbound)) throw new HostUnavailable(host, \"inbound_addresses is not a list\");\n const entries = inboundAddresses(inbound);\n if (!entries) throw new HostUnavailable(host, \"inbound_addresses is not a THORNode inbound address list\");\n const entry = entries.find((e) => e.chain === claim.chain);\n if (paused(entry)) return {ok: false, why: \"halted\", chain: claim.chain};\n if (claim.destChain !== undefined && paused(entries.find((e) => e.chain === claim.destChain))) {\n return {ok: false, why: \"halted\", chain: claim.destChain};\n }\n if (!sameTarget(entry?.address, claim.vault)) {\n const [asgardBody, mimirBody] = await Promise.all([read(THORNODE_CONFIRM_PATHS.asgardVaults), read(THORNODE_CONFIRM_PATHS.mimir)]);\n const vaults = asgardVaults(asgardBody);\n if (!vaults) throw new HostUnavailable(host, \"vaults/asgard is not a THORNode vault list\");\n const flags = mimirFlags(mimirBody);\n if (!flags) throw new HostUnavailable(host, \"mimir is not a THORNode mimir map\");\n const holders = vaults.filter((v) => v.addresses.some((a) => a.chain === claim.chain && sameTarget(a.address, claim.vault)));\n const active = holders.find((v) => v.status === \"ActiveVault\");\n if (!active) {\n if (!holders.length) return {ok: false, why: \"another-vault\"};\n return {ok: false, why: \"not-active\", status: /^[A-Za-z]{1,32}$/.test(holders[0]!.status) ? holders[0]!.status : \"an unknown status\"};\n }\n const flag = flags(active.pubKey);\n if (flag === \"malformed\") throw new HostUnavailable(host, \"mimir holds a non-integer vault flag\");\n if (flag) return {ok: false, why: \"flagged\", flag};\n }\n if (claim.router !== undefined && !sameTarget(entry?.router, claim.router)) return {ok: false, why: \"another-router\"};\n return {ok: true};\n}\n"],"mappings":"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","names":["import_util","import_errors","isEvm","limitMode","outHash"]}
|