@anywalletkit/protocol-swap2-chainflip 0.4.6 → 0.4.7

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/dist/activity.cjs CHANGED
@@ -26,6 +26,9 @@ __export(activity_exports, {
26
26
  module.exports = __toCommonJS(activity_exports);
27
27
  var import_activity = require("@anywalletkit/protocol-swap2-core/activity");
28
28
 
29
+ // src/config.ts
30
+ var import_errors = require("@anywalletkit/protocol-swap2-core/errors");
31
+
29
32
  // src/codec.ts
30
33
  var import_base = require("@scure/base");
31
34
  var import_sha2 = require("@noble/hashes/sha2.js");
@@ -198,50 +201,69 @@ function cfAsset(chain, token) {
198
201
  if (NATIVE.has(token.toLowerCase())) return on.find((a) => a.token === null);
199
202
  return on.find((a) => a.token !== null && sameToken(chain, a.token, token) || a.asset === token.toUpperCase());
200
203
  }
204
+ var notes = (0, import_errors.refusalNotes)();
205
+ var unparsed = /* @__PURE__ */ new Set();
206
+ function decodeFailure(text, requestParsed) {
207
+ unparsed.delete(text);
208
+ if (requestParsed) return notes.note(text, "upstream_unavailable");
209
+ unparsed.add(text);
210
+ if (unparsed.size > 64) unparsed.delete(unparsed.values().next().value);
211
+ return text;
212
+ }
213
+ var reasonOf = (text) => unparsed.has(text) ? void 0 : notes.reasonOf(text);
201
214
  function chainflipVerifyQuote(params, quote) {
215
+ let readingRequest = false;
202
216
  try {
203
217
  const src = cfAsset(params.sourceChain, params.sourceToken);
204
218
  const dst = cfAsset(params.destChain, params.destToken);
205
219
  const dstChain = CF_CHAINS[params.destChain];
206
220
  const vault = Object.prototype.hasOwnProperty.call(CF_VAULTS, params.sourceChain) ? CF_VAULTS[params.sourceChain] : void 0;
207
- if (!src || !dst || !dstChain || !vault || !CF_SOURCE_CHAINS.has(params.sourceChain)) return "not a vault swap this release signs";
221
+ if (!src || !dst || !dstChain || !vault || !CF_SOURCE_CHAINS.has(params.sourceChain)) return notes.note("not a vault swap this release signs", "unsupported_pair");
208
222
  if (!quote.txRequest && !quote.depositAddress) return null;
209
- if (!params.refundAddress) return "a live quote needs the refund address";
223
+ if (!params.refundAddress) return notes.note("a live quote needs the refund address", "policy_refused");
224
+ readingRequest = true;
210
225
  const amountIn = BigInt(params.amountIn);
211
226
  const dest = destAddressBytes(params.destChain, params.destAddress);
212
227
  const refund = destAddressBytes(params.sourceChain, params.refundAddress);
228
+ readingRequest = false;
213
229
  const checkParams = (p) => {
214
- if (!sameBytes(fromHex(p.refundAddress), refund)) return "the refund address is not the sender";
215
- if (minOutOf(amountIn, p.minPriceX128) < BigInt(quote.minDestAmount)) return "the minimum price does not guarantee the quoted minimum";
216
- if (p.dca !== null || p.boostFeeBps !== 0 || p.broker.feeBps !== 0 || p.affiliates.length) return "DCA, boost, a broker fee or affiliates";
230
+ if (!sameBytes(fromHex(p.refundAddress), refund)) return notes.note("the refund address is not the sender", "recipient_mismatch");
231
+ if (minOutOf(amountIn, p.minPriceX128) < BigInt(quote.minDestAmount)) return notes.note("the minimum price does not guarantee the quoted minimum", "price_check_failed");
232
+ if (p.dca !== null || p.boostFeeBps !== 0 || p.broker.feeBps !== 0 || p.affiliates.length) return notes.note("DCA, boost, a broker fee or affiliates", "policy_refused");
217
233
  return null;
218
234
  };
219
235
  if (params.sourceChain.startsWith("eip155:")) {
220
236
  const tx = quote.txRequest;
221
- if (quote.depositAddress || !tx?.data || tx.serializedTx !== void 0) return "an EVM vault swap is a vault call, not a deposit";
222
- if (!tx.to || tx.to.toLowerCase() !== vault.toLowerCase()) return `the call targets ${tx.to}, not the Vault`;
237
+ if (quote.depositAddress || !tx?.data || tx.serializedTx !== void 0) return notes.note("an EVM vault swap is a vault call, not a deposit", "policy_refused");
238
+ if (!tx.to || tx.to.toLowerCase() !== vault.toLowerCase()) return notes.note(`the call targets ${tx.to}, not the Vault`, "vault_mismatch");
223
239
  const v = decodeEvmVaultCall(tx.data);
224
- if (v.dstChain !== dstChain.id || v.dstToken !== dst.id || !sameBytes(v.dstAddress, dest)) return "the vault call names another destination";
240
+ if (v.dstChain !== dstChain.id || v.dstToken !== dst.id || !sameBytes(v.dstAddress, dest)) return notes.note("the vault call names another destination", "recipient_mismatch");
225
241
  if (src.token === null) {
226
- if (!v.native || BigInt(tx.value ?? "0") !== amountIn || tx.approvalAddress) return "the native vault call moves another amount";
242
+ if (!v.native || BigInt(tx.value ?? "0") !== amountIn || tx.approvalAddress) return notes.note("the native vault call moves another amount", "policy_refused");
227
243
  } else if (v.native || v.srcToken?.toLowerCase() !== src.token.toLowerCase() || v.amount !== amountIn || BigInt(tx.value ?? "0") !== 0n || tx.approvalAddress?.toLowerCase() !== vault.toLowerCase()) {
228
- return "the token vault call moves another token or amount";
244
+ return notes.note("the token vault call moves another token or amount", "policy_refused");
229
245
  }
230
246
  return checkParams(v.params);
231
247
  }
232
- if (quote.txRequest || quote.depositAddress !== vault || !quote.depositMemo) return "a Tron vault swap is a send to the Tron Vault with its note";
248
+ if (quote.txRequest || quote.depositAddress !== vault || !quote.depositMemo) {
249
+ return notes.note(
250
+ "a Tron vault swap is a send to the Tron Vault with its note",
251
+ quote.txRequest ? "policy_refused" : quote.depositAddress !== vault ? "vault_mismatch" : "recipient_unverifiable"
252
+ );
253
+ }
233
254
  const n = decodeTronNote(quote.depositMemo);
234
- if (n.outputAsset !== dst.id || n.destTag !== dstChain.addrTag || !sameBytes(n.destAddress, dest)) return "the note names another destination";
255
+ if (n.outputAsset !== dst.id || n.destTag !== dstChain.addrTag || !sameBytes(n.destAddress, dest)) return notes.note("the note names another destination", "recipient_mismatch");
235
256
  return checkParams(n.params);
236
257
  } catch (e) {
237
- return `the vault swap does not decode (${(e instanceof Error ? e.message : String(e)).slice(0, 120)})`;
258
+ return decodeFailure(`the vault swap does not decode (${(e instanceof Error ? e.message : String(e)).slice(0, 120)})`, !readingRequest);
238
259
  }
239
260
  }
240
261
  var chainflipPins = Object.freeze({
241
262
  callTargets: (chain) => chainflipVaultFor(chain),
242
263
  spenders: (chain) => chainflipVaultFor(chain),
243
264
  verifyQuote: chainflipVerifyQuote,
244
- verifyBuild: (quote, tx) => quote.depositMemo && tx.memoEncoding !== "hex" ? "the Tron note is not sent as hex bytes" : null,
265
+ verifyBuild: (quote, tx) => quote.depositMemo && tx.memoEncoding !== "hex" ? notes.note("the Tron note is not sent as hex bytes", "policy_refused") : null,
266
+ reasonOf,
245
267
  depositAddressRoutes: true
246
268
  });
247
269
  function chainflipVaultFor(chain) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/activity.ts","../src/codec.ts","../src/config.ts"],"sourcesContent":["/**\n * Activity recognition for Chainflip vault swaps: the source leg is a call to (EVM) or a transfer into (Tron) the\n * Chainflip Vault — a fixed, well-known counterparty, so the leg is recognizable offline. The destination leg is a\n * transfer from Chainflip's egress keys (rotating), tied back through the intent journal.\n */\nimport type {ActivityItem, ChainTx, DescribeActivityContext} from \"@anywalletkit/core\";\nimport {describeSwapLike} from \"@anywalletkit/protocol-swap2-core/activity\";\nimport {CF_VAULTS} from \"./config.js\";\n\nexport const CHAINFLIP_MODULE = \"@anywalletkit/protocol-swap2-chainflip\";\n\nconst same = (chain: string, a: string | null | undefined, b: string) => !!a && (chain.startsWith(\"eip155:\") ? a.toLowerCase() === b.toLowerCase() : a === b);\n\n/** Wallet history names Tron by its genesis-hash form (`tron:0x2b6653dc`); swap2 routes by chain id (`tron:728126428`). */\nconst CHAIN_ALIAS: Readonly<Record<string, string>> = {\"tron:0x2b6653dc\": \"tron:728126428\"};\n\nexport function describeChainflipActivity(tx: ChainTx, ctx: DescribeActivityContext): ActivityItem | null {\n const vault = CF_VAULTS[CHAIN_ALIAS[tx.chain] ?? tx.chain];\n if (!vault) return null;\n const toVault = same(tx.chain, (tx as {to?: string}).to, vault) || tx.transfers.some((t) => same(tx.chain, t.to, vault) && ctx.own.has(t.from));\n if (!toVault) return null;\n return describeSwapLike(tx, ctx, {protocol: CHAINFLIP_MODULE, subtitle: \"Chainflip\", kind: \"bridge\", counterparty: vault, inSuffix: \"via Chainflip\"});\n}\n","/**\n * Decoders for what Chainflip's encoder returns, so a vault swap is checked byte by byte before anyone signs it:\n * - VersionedCfParameters (SCALE): retry window, refund address, minimum price (X128), oracle slippage, DCA, boost,\n * broker + its fee, affiliates — the EVM vault call's `cfParameters` and the tail of the Tron note;\n * - the Tron note: output asset id, encoded destination address, CCM option, then the length-prefixed parameters;\n * - the EVM vault calls xSwapNative / xSwapToken.\n * Layouts were decoded from live encoder outputs (2026-10-20) and match the state chain's types.\n */\nimport {base58} from \"@scure/base\";\nimport {sha256} from \"@noble/hashes/sha2.js\";\nimport {decodeFunctionData, parseAbi, type Hex} from \"viem\";\n\nexport interface CfParameters {\n version: number;\n retryDurationBlocks: number;\n /** raw refund address bytes (20 for EVM / Tron, 32 for Solana) as 0x-hex */\n refundAddress: Hex;\n /** minimum output price × 2^128, scaled by 10^(destDecimals − srcDecimals) */\n minPriceX128: bigint;\n refundCcm: boolean;\n maxOraclePriceSlippageBps: number | null;\n dca: {chunks: number; intervalBlocks: number} | null;\n boostFeeBps: number;\n broker: {account: Hex; feeBps: number};\n affiliates: {account: number; feeBps: number}[];\n}\n\nclass Reader {\n i = 0;\n constructor(readonly b: Uint8Array) {}\n need(n: number) { if (this.i + n > this.b.length) throw new Error(`chainflip codec: truncated at ${this.i} (+${n} of ${this.b.length})`); }\n u8() { this.need(1); return this.b[this.i++]!; }\n bytes(n: number) { this.need(n); const out = this.b.slice(this.i, this.i + n); this.i += n; return out; }\n uLE(n: number): bigint { const x = this.bytes(n); let v = 0n; for (let k = n - 1; k >= 0; k--) v = (v << 8n) | BigInt(x[k]!); return v; }\n /** Little-endian unsigned of up to 6 bytes as a number (exact: below 2^48). */\n uNum(n: number): number { if (n > 6) throw new Error(\"chainflip codec: uNum takes at most 6 bytes\"); const x = this.bytes(n); let v = 0; for (let k = n - 1; k >= 0; k--) v = v * 256 + x[k]!; return v; }\n /** SCALE compact integer */\n compact(): number {\n const first = this.u8();\n const mode = first & 3;\n if (mode === 0) return first >> 2;\n if (mode === 1) return ((this.u8() << 8) | first) >> 2;\n if (mode === 2) { const rest = this.uNum(3); return ((rest << 8) | first) >>> 2; }\n throw new Error(\"chainflip codec: big compact integers are not used here\");\n }\n done() { if (this.i !== this.b.length) throw new Error(`chainflip codec: ${this.b.length - this.i} trailing bytes`); }\n}\n\nexport const toHex = (b: Uint8Array): Hex => `0x${[...b].map((x) => x.toString(16).padStart(2, \"0\")).join(\"\")}` as Hex;\nexport function fromHex(h: string): Uint8Array {\n const s = h.startsWith(\"0x\") ? h.slice(2) : h;\n if (s.length % 2 || /[^0-9a-f]/i.test(s)) throw new Error(\"chainflip codec: not hex\");\n return Uint8Array.from(s.match(/../g) ?? [], (x) => Number.parseInt(x, 16));\n}\n\n/** VersionedCfParameters V1. `refundLen` = 20 for EVM / Tron sources, 32 for Solana. */\nexport function decodeCfParameters(bytes: Uint8Array, refundLen: 20 | 32): CfParameters {\n const r = new Reader(bytes);\n const p = readCfParameters(r, refundLen);\n r.done();\n return p;\n}\n\nfunction readCfParameters(r: Reader, refundLen: number): CfParameters {\n const version = r.u8();\n if (version !== 1) throw new Error(`chainflip codec: cf parameters version ${version}`);\n // ccm_additional_data is `()` for non-CCM swaps: zero bytes\n const retryDurationBlocks = r.uNum(4);\n const refundAddress = toHex(r.bytes(refundLen));\n const minPriceX128 = r.uLE(32);\n const refundCcm = r.u8() !== 0;\n if (refundCcm) throw new Error(\"chainflip codec: refund CCM metadata is not expected\");\n const maxOraclePriceSlippageBps = r.u8() ? r.uNum(2) : null;\n const dca = r.u8() ? {chunks: r.uNum(4), intervalBlocks: r.uNum(4)} : null;\n const boostFeeBps = r.u8();\n const broker = {account: toHex(r.bytes(32)), feeBps: r.uNum(2)};\n const n = r.compact();\n const affiliates = Array.from({length: n}, () => ({account: r.u8(), feeBps: r.uNum(2)}));\n return {version, retryDurationBlocks, refundAddress, minPriceX128, refundCcm, maxOraclePriceSlippageBps, dca, boostFeeBps, broker, affiliates};\n}\n\nexport interface TronNote {\n outputAsset: number;\n /** EncodedAddress variant of the destination (Eth 0, Dot 1, Btc 2, Arb 3, Sol 4, Hub 5, Tron 6) and its raw bytes */\n destTag: number;\n destAddress: Uint8Array;\n ccm: boolean;\n params: CfParameters;\n}\n\n/** Address byte length per encoded-address tag (EncodedAddress enum: Eth, Dot, Btc, Arb, Sol, Hub, Tron …). */\nconst TAG_LEN: Record<number, number | \"vec\"> = {0: 20, 1: 32, 2: \"vec\", 3: 20, 4: 32, 5: 32, 6: 20};\n\n/** The note a Tron vault swap carries in raw_data.data. */\nexport function decodeTronNote(note: string): TronNote {\n const r = new Reader(fromHex(note));\n const outputAsset = r.u8();\n const destTag = r.u8();\n const len = TAG_LEN[destTag];\n if (len === undefined) throw new Error(`chainflip codec: unknown address tag ${destTag}`);\n const destAddress = len === \"vec\" ? r.bytes(r.compact()) : r.bytes(len);\n const ccm = r.u8() !== 0;\n if (ccm) throw new Error(\"chainflip codec: CCM swaps are not expected\");\n const paramsLen = r.compact();\n const start = r.i;\n const params = readCfParameters(r, 20);\n if (r.i - start !== paramsLen) throw new Error(`chainflip codec: cf parameters length ${r.i - start} ≠ declared ${paramsLen}`);\n r.done();\n return {outputAsset, destTag, destAddress, ccm, params};\n}\n\nconst VAULT_ABI = parseAbi([\n \"function xSwapNative(uint32 dstChain, bytes dstAddress, uint32 dstToken, bytes cfParameters) payable\",\n \"function xSwapToken(uint32 dstChain, bytes dstAddress, uint32 dstToken, address srcToken, uint256 amount, bytes cfParameters)\",\n]);\n\nexport interface EvmVaultCall {\n native: boolean;\n dstChain: number;\n dstAddress: Uint8Array;\n dstToken: number;\n srcToken: string | null;\n amount: bigint | null;\n params: CfParameters;\n}\n\nexport function decodeEvmVaultCall(data: string): EvmVaultCall {\n const d = decodeFunctionData({abi: VAULT_ABI, data: data as Hex});\n if (d.functionName === \"xSwapNative\") {\n const [dstChain, dstAddress, dstToken, cf] = d.args;\n return {native: true, dstChain, dstAddress: fromHex(dstAddress), dstToken, srcToken: null, amount: null, params: decodeCfParameters(fromHex(cf), 20)};\n }\n const [dstChain, dstAddress, dstToken, srcToken, amount, cf] = d.args;\n return {native: false, dstChain, dstAddress: fromHex(dstAddress), dstToken, srcToken, amount, params: decodeCfParameters(fromHex(cf), 20)};\n}\n\n/** Tron base58check `T…` ↔ the 20 raw bytes Chainflip encodes (0x41 prefix dropped). */\nexport function tronToBytes(address: string): Uint8Array {\n const b = base58.decode(address);\n if (b.length !== 25 || b[0] !== 0x41) throw new Error(`not a Tron address: ${address}`);\n const check = sha256(sha256(b.subarray(0, 21))).subarray(0, 4);\n if (toHex(check) !== toHex(b.subarray(21))) throw new Error(`bad Tron checksum: ${address}`);\n return b.subarray(1, 21);\n}\n\n/** The raw bytes a destination address is encoded with, per destination chain (EVM / Tron 20, Solana 32, BTC ASCII). */\nexport function destAddressBytes(chain: string, address: string): Uint8Array {\n if (chain.startsWith(\"eip155:\")) return fromHex(address);\n if (chain.startsWith(\"tron:\")) return tronToBytes(address);\n if (chain.startsWith(\"solana:\")) { const b = base58.decode(address); if (b.length !== 32) throw new Error(`not a Solana address: ${address}`); return b; }\n if (chain.startsWith(\"bitcoin:\")) return new TextEncoder().encode(address);\n throw new Error(`chainflip: no address encoding for ${chain}`);\n}\n\nexport const sameBytes = (a: Uint8Array, b: Uint8Array) => a.length === b.length && a.every((x, i) => x === b[i]);\n\n/** minPriceX128 for a guaranteed output: ceil(minOut × 2^128 / amountIn) (base units on both sides carry the decimals). */\nexport function minPriceX128For(amountIn: bigint, minOut: bigint): bigint {\n return (minOut * 2n ** 128n + amountIn - 1n) / amountIn;\n}\n/** The output a min price guarantees for `amountIn` (floor). */\nexport function minOutOf(amountIn: bigint, minPriceX128: bigint): bigint {\n return (amountIn * minPriceX128) / 2n ** 128n;\n}\n","/**\n * Chainflip (JIT-AMM state chain) — chains, assets and contracts as the public backend and the vault encodings name them.\n * Asset ids, chain ids and decimals are the protocol's own (`cf_environment` / networkInfo, verified 2026-10-20); the\n * contract addresses are Chainflip's mainnet deployments (docs mainnet-addresses, confirmed by live encodings).\n *\n * Only VAULT SWAPS are offered: the donor signs a transaction whose every Chainflip parameter (destination, minimum price,\n * refund address) is decoded and checked locally before signing — no off-chain deposit channel to trust, and on Tron no\n * 3.4 USDT ingress fee. Sources: EVM (Ethereum, Arbitrum) and Tron in this release; Solana / Bitcoin vault swaps need an\n * instruction / OP_RETURN builder and come next. Destinations: every live chain.\n */\nimport type {Quote, QuoteParams, RemotePins, UnsignedTx} from \"@anywalletkit/protocol-swap2-core/types\";\nimport {decodeEvmVaultCall, decodeTronNote, destAddressBytes, fromHex, minOutOf, sameBytes, type CfParameters} from \"./codec.js\";\n\nexport type CfChain = \"Ethereum\" | \"Bitcoin\" | \"Arbitrum\" | \"Solana\" | \"Tron\";\n\nexport interface CfAsset {\n chain: CfChain;\n /** the API's asset symbol */\n asset: string;\n /** the u32 asset id inside vault encodings */\n id: number;\n decimals: number;\n /** token contract / mint on its chain, null for the native coin */\n token: string | null;\n /** smallest deposit the state chain accepts (base units) */\n minDeposit: bigint;\n}\n\n/**\n * CAIP-2 → Chainflip chain: `id` = the ForeignChain number an EVM vault call names (`dstChain`), `addrTag` = the\n * EncodedAddress variant a Tron note names (Eth 0, Dot 1, Btc 2, Arb 3, Sol 4, Hub 5, Tron 6) — two different enums.\n */\nexport const CF_CHAINS: Readonly<Record<string, {name: CfChain; id: number; addrTag: number}>> = {\n \"eip155:1\": {name: \"Ethereum\", id: 1, addrTag: 0},\n \"bitcoin:mainnet\": {name: \"Bitcoin\", id: 3, addrTag: 2},\n \"eip155:42161\": {name: \"Arbitrum\", id: 4, addrTag: 3},\n \"solana:mainnet\": {name: \"Solana\", id: 5, addrTag: 4},\n \"tron:728126428\": {name: \"Tron\", id: 7, addrTag: 6},\n};\n\nexport const CF_ASSETS: readonly CfAsset[] = [\n {chain: \"Ethereum\", asset: \"ETH\", id: 1, decimals: 18, token: null, minDeposit: 10n ** 16n},\n {chain: \"Ethereum\", asset: \"USDC\", id: 3, decimals: 6, token: \"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48\", minDeposit: 20_000_000n},\n {chain: \"Ethereum\", asset: \"USDT\", id: 8, decimals: 6, token: \"0xdAC17F958D2ee523a2206206994597C13D831ec7\", minDeposit: 20_000_000n},\n {chain: \"Ethereum\", asset: \"WBTC\", id: 14, decimals: 8, token: \"0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599\", minDeposit: 40_000n},\n {chain: \"Bitcoin\", asset: \"BTC\", id: 5, decimals: 8, token: null, minDeposit: 40_000n},\n {chain: \"Arbitrum\", asset: \"ETH\", id: 6, decimals: 18, token: null, minDeposit: 3_900_000_000_000_000n},\n {chain: \"Arbitrum\", asset: \"USDC\", id: 7, decimals: 6, token: \"0xaf88d065e77c8cC2239327C5EDb3A432268e5831\", minDeposit: 10_000_000n},\n {chain: \"Arbitrum\", asset: \"USDT\", id: 15, decimals: 6, token: \"0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9\", minDeposit: 10_000_000n},\n {chain: \"Solana\", asset: \"SOL\", id: 9, decimals: 9, token: null, minDeposit: 68_000_000n},\n {chain: \"Solana\", asset: \"USDC\", id: 10, decimals: 6, token: \"EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v\", minDeposit: 10_000_000n},\n {chain: \"Solana\", asset: \"USDT\", id: 16, decimals: 6, token: \"Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB\", minDeposit: 10_000_000n},\n {chain: \"Tron\", asset: \"TRX\", id: 17, decimals: 6, token: null, minDeposit: 30_000_000n},\n {chain: \"Tron\", asset: \"USDT\", id: 18, decimals: 6, token: \"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t\", minDeposit: 10_000_000n},\n];\n\n/** Vault contracts that receive vault swaps (the deposit transaction's target). */\nexport const CF_VAULTS: Readonly<Record<string, string>> = {\n \"eip155:1\": \"0xF5e10380213880111522dd0efD3dbb45b9f62Bcc\",\n \"eip155:42161\": \"0x79001a5e762f3bEFC8e5871b42F6734e00498920\",\n \"tron:728126428\": \"TEcDijvKSXcfWT7S6rd44H5vNgufm7Y4XC\",\n};\n\n/** Sources this release signs (vault swaps the engine can execute and the verifier can decode). */\nexport const CF_SOURCE_CHAINS = new Set([\"eip155:1\", \"eip155:42161\", \"tron:728126428\"]);\n\nexport const CF_API_DEFAULT = \"https://chainflip-swap.chainflip.io\";\n\nconst sameToken = (chain: string, a: string, b: string) => (chain.startsWith(\"eip155:\") ? a.toLowerCase() === b.toLowerCase() : a === b);\nconst NATIVE = new Set([\"\", \"native\", \"0x0000000000000000000000000000000000000000\"]);\n\n/** The Chainflip asset for a CAIP-2 chain + token (contract / mint, a native marker, or the asset symbol). */\nexport function cfAsset(chain: string, token: string): CfAsset | undefined {\n const c = CF_CHAINS[chain];\n if (!c) return undefined;\n const on = CF_ASSETS.filter((a) => a.chain === c.name);\n if (NATIVE.has(token.toLowerCase())) return on.find((a) => a.token === null);\n return on.find((a) => (a.token !== null && sameToken(chain, a.token, token)) || a.asset === token.toUpperCase());\n}\n\nexport const chainflip = {\n supportsChain: (chain: string) => !!CF_CHAINS[chain],\n supports: (from: string, to: string) => CF_SOURCE_CHAINS.has(from) && !!CF_CHAINS[to] && from !== to,\n};\n\n/**\n * The provider's own decode of a vault swap, run on the client against the app's request (scan 2026-10-28, F9): an\n * EVM source is a vault call (`xSwapNative` / `xSwapToken`) on the pinned Vault, a Tron source a send to the pinned\n * Tron Vault whose note carries the swap; either way the destination chain, asset and address, the source token and\n * amount, the refund address and a minimum price that guarantees the quoted minimum must be the app's, with no DCA,\n * boost, broker fee or affiliates. The reason it fails, or null.\n */\nexport function chainflipVerifyQuote(params: QuoteParams, quote: Quote): string | null {\n try {\n const src = cfAsset(params.sourceChain, params.sourceToken);\n const dst = cfAsset(params.destChain, params.destToken);\n const dstChain = CF_CHAINS[params.destChain];\n const vault = Object.prototype.hasOwnProperty.call(CF_VAULTS, params.sourceChain) ? CF_VAULTS[params.sourceChain] : undefined;\n if (!src || !dst || !dstChain || !vault || !CF_SOURCE_CHAINS.has(params.sourceChain)) return \"not a vault swap this release signs\";\n // A dry quote lists a route and pays nobody; execution re-quotes live.\n if (!quote.txRequest && !quote.depositAddress) return null;\n if (!params.refundAddress) return \"a live quote needs the refund address\";\n const amountIn = BigInt(params.amountIn);\n const dest = destAddressBytes(params.destChain, params.destAddress);\n const refund = destAddressBytes(params.sourceChain, params.refundAddress);\n const checkParams = (p: CfParameters): string | null => {\n if (!sameBytes(fromHex(p.refundAddress), refund)) return \"the refund address is not the sender\";\n if (minOutOf(amountIn, p.minPriceX128) < BigInt(quote.minDestAmount)) return \"the minimum price does not guarantee the quoted minimum\";\n if (p.dca !== null || p.boostFeeBps !== 0 || p.broker.feeBps !== 0 || p.affiliates.length) return \"DCA, boost, a broker fee or affiliates\";\n return null;\n };\n if (params.sourceChain.startsWith(\"eip155:\")) {\n const tx = quote.txRequest;\n if (quote.depositAddress || !tx?.data || tx.serializedTx !== undefined) return \"an EVM vault swap is a vault call, not a deposit\";\n if (!tx.to || tx.to.toLowerCase() !== vault.toLowerCase()) return `the call targets ${tx.to}, not the Vault`;\n const v = decodeEvmVaultCall(tx.data);\n if (v.dstChain !== dstChain.id || v.dstToken !== dst.id || !sameBytes(v.dstAddress, dest)) return \"the vault call names another destination\";\n if (src.token === null) {\n if (!v.native || BigInt(tx.value ?? \"0\") !== amountIn || tx.approvalAddress) return \"the native vault call moves another amount\";\n } else if (v.native || v.srcToken?.toLowerCase() !== src.token.toLowerCase() || v.amount !== amountIn || BigInt(tx.value ?? \"0\") !== 0n ||\n tx.approvalAddress?.toLowerCase() !== vault.toLowerCase()) {\n return \"the token vault call moves another token or amount\";\n }\n return checkParams(v.params);\n }\n // Tron: the deposit is a send of the input to the Vault, the swap riding in the note.\n if (quote.txRequest || quote.depositAddress !== vault || !quote.depositMemo) return \"a Tron vault swap is a send to the Tron Vault with its note\";\n const n = decodeTronNote(quote.depositMemo);\n if (n.outputAsset !== dst.id || n.destTag !== dstChain.addrTag || !sameBytes(n.destAddress, dest)) return \"the note names another destination\";\n return checkParams(n.params);\n } catch (e) {\n return `the vault swap does not decode (${(e instanceof Error ? e.message : String(e)).slice(0, 120)})`;\n }\n}\n\n/**\n * The Chainflip Vault a vault swap calls and approves on an EVM chain ({@link CF_VAULTS}), and\n * {@link chainflipVerifyQuote} — the app's pins for `remoteProvider({name: \"chainflip\", baseUrl, ...chainflipPins})`\n * (scan 2026-10-27 modules, F8/F16). A Tron vault swap is a send to the Tron Vault the verifier pins, so the stub is\n * opened to that deposit route (`depositAddressRoutes`, scan 2026-10-28 F9); its note must ride as hex bytes.\n */\nexport const chainflipPins: RemotePins = Object.freeze({\n callTargets: (chain: string): readonly string[] => chainflipVaultFor(chain),\n spenders: (chain: string): readonly string[] => chainflipVaultFor(chain),\n verifyQuote: chainflipVerifyQuote,\n verifyBuild: (quote: Quote, tx: UnsignedTx): string | null =>\n quote.depositMemo && tx.memoEncoding !== \"hex\" ? \"the Tron note is not sent as hex bytes\" : null,\n depositAddressRoutes: true,\n});\nfunction chainflipVaultFor(chain: string): readonly string[] {\n const vault = chain.startsWith(\"eip155:\") && Object.prototype.hasOwnProperty.call(CF_VAULTS, chain) ? CF_VAULTS[chain] : undefined;\n return vault ? [vault] : [];\n}\n"],"mappings":"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","names":["dstChain","dstAddress","dstToken","cf"]}
1
+ {"version":3,"sources":["../src/activity.ts","../src/config.ts","../src/codec.ts"],"sourcesContent":["/**\n * Activity recognition for Chainflip vault swaps: the source leg is a call to (EVM) or a transfer into (Tron) the\n * Chainflip Vault — a fixed, well-known counterparty, so the leg is recognizable offline. The destination leg is a\n * transfer from Chainflip's egress keys (rotating), tied back through the intent journal.\n */\nimport type {ActivityItem, ChainTx, DescribeActivityContext} from \"@anywalletkit/core\";\nimport {describeSwapLike} from \"@anywalletkit/protocol-swap2-core/activity\";\nimport {CF_VAULTS} from \"./config.js\";\n\nexport const CHAINFLIP_MODULE = \"@anywalletkit/protocol-swap2-chainflip\";\n\nconst same = (chain: string, a: string | null | undefined, b: string) => !!a && (chain.startsWith(\"eip155:\") ? a.toLowerCase() === b.toLowerCase() : a === b);\n\n/** Wallet history names Tron by its genesis-hash form (`tron:0x2b6653dc`); swap2 routes by chain id (`tron:728126428`). */\nconst CHAIN_ALIAS: Readonly<Record<string, string>> = {\"tron:0x2b6653dc\": \"tron:728126428\"};\n\nexport function describeChainflipActivity(tx: ChainTx, ctx: DescribeActivityContext): ActivityItem | null {\n const vault = CF_VAULTS[CHAIN_ALIAS[tx.chain] ?? tx.chain];\n if (!vault) return null;\n const toVault = same(tx.chain, (tx as {to?: string}).to, vault) || tx.transfers.some((t) => same(tx.chain, t.to, vault) && ctx.own.has(t.from));\n if (!toVault) return null;\n return describeSwapLike(tx, ctx, {protocol: CHAINFLIP_MODULE, subtitle: \"Chainflip\", kind: \"bridge\", counterparty: vault, inSuffix: \"via Chainflip\"});\n}\n","/**\n * Chainflip (JIT-AMM state chain) — chains, assets and contracts as the public backend and the vault encodings name them.\n * Asset ids, chain ids and decimals are the protocol's own (`cf_environment` / networkInfo, verified 2026-10-20); the\n * contract addresses are Chainflip's mainnet deployments (docs mainnet-addresses, confirmed by live encodings).\n *\n * Only VAULT SWAPS are offered: the donor signs a transaction whose every Chainflip parameter (destination, minimum price,\n * refund address) is decoded and checked locally before signing — no off-chain deposit channel to trust, and on Tron no\n * 3.4 USDT ingress fee. Sources: EVM (Ethereum, Arbitrum) and Tron in this release; Solana / Bitcoin vault swaps need an\n * instruction / OP_RETURN builder and come next. Destinations: every live chain.\n */\nimport {refusalNotes} from \"@anywalletkit/protocol-swap2-core/errors\";\nimport type {Quote, QuoteParams, RemotePins, UnsignedTx} from \"@anywalletkit/protocol-swap2-core/types\";\nimport {decodeEvmVaultCall, decodeTronNote, destAddressBytes, fromHex, minOutOf, sameBytes, type CfParameters} from \"./codec.js\";\n\nexport type CfChain = \"Ethereum\" | \"Bitcoin\" | \"Arbitrum\" | \"Solana\" | \"Tron\";\n\nexport interface CfAsset {\n chain: CfChain;\n /** the API's asset symbol */\n asset: string;\n /** the u32 asset id inside vault encodings */\n id: number;\n decimals: number;\n /** token contract / mint on its chain, null for the native coin */\n token: string | null;\n /** smallest deposit the state chain accepts (base units) */\n minDeposit: bigint;\n}\n\n/**\n * CAIP-2 → Chainflip chain: `id` = the ForeignChain number an EVM vault call names (`dstChain`), `addrTag` = the\n * EncodedAddress variant a Tron note names (Eth 0, Dot 1, Btc 2, Arb 3, Sol 4, Hub 5, Tron 6) — two different enums.\n */\nexport const CF_CHAINS: Readonly<Record<string, {name: CfChain; id: number; addrTag: number}>> = {\n \"eip155:1\": {name: \"Ethereum\", id: 1, addrTag: 0},\n \"bitcoin:mainnet\": {name: \"Bitcoin\", id: 3, addrTag: 2},\n \"eip155:42161\": {name: \"Arbitrum\", id: 4, addrTag: 3},\n \"solana:mainnet\": {name: \"Solana\", id: 5, addrTag: 4},\n \"tron:728126428\": {name: \"Tron\", id: 7, addrTag: 6},\n};\n\nexport const CF_ASSETS: readonly CfAsset[] = [\n {chain: \"Ethereum\", asset: \"ETH\", id: 1, decimals: 18, token: null, minDeposit: 10n ** 16n},\n {chain: \"Ethereum\", asset: \"USDC\", id: 3, decimals: 6, token: \"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48\", minDeposit: 20_000_000n},\n {chain: \"Ethereum\", asset: \"USDT\", id: 8, decimals: 6, token: \"0xdAC17F958D2ee523a2206206994597C13D831ec7\", minDeposit: 20_000_000n},\n {chain: \"Ethereum\", asset: \"WBTC\", id: 14, decimals: 8, token: \"0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599\", minDeposit: 40_000n},\n {chain: \"Bitcoin\", asset: \"BTC\", id: 5, decimals: 8, token: null, minDeposit: 40_000n},\n {chain: \"Arbitrum\", asset: \"ETH\", id: 6, decimals: 18, token: null, minDeposit: 3_900_000_000_000_000n},\n {chain: \"Arbitrum\", asset: \"USDC\", id: 7, decimals: 6, token: \"0xaf88d065e77c8cC2239327C5EDb3A432268e5831\", minDeposit: 10_000_000n},\n {chain: \"Arbitrum\", asset: \"USDT\", id: 15, decimals: 6, token: \"0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9\", minDeposit: 10_000_000n},\n {chain: \"Solana\", asset: \"SOL\", id: 9, decimals: 9, token: null, minDeposit: 68_000_000n},\n {chain: \"Solana\", asset: \"USDC\", id: 10, decimals: 6, token: \"EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v\", minDeposit: 10_000_000n},\n {chain: \"Solana\", asset: \"USDT\", id: 16, decimals: 6, token: \"Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB\", minDeposit: 10_000_000n},\n {chain: \"Tron\", asset: \"TRX\", id: 17, decimals: 6, token: null, minDeposit: 30_000_000n},\n {chain: \"Tron\", asset: \"USDT\", id: 18, decimals: 6, token: \"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t\", minDeposit: 10_000_000n},\n];\n\n/** Vault contracts that receive vault swaps (the deposit transaction's target). */\nexport const CF_VAULTS: Readonly<Record<string, string>> = {\n \"eip155:1\": \"0xF5e10380213880111522dd0efD3dbb45b9f62Bcc\",\n \"eip155:42161\": \"0x79001a5e762f3bEFC8e5871b42F6734e00498920\",\n \"tron:728126428\": \"TEcDijvKSXcfWT7S6rd44H5vNgufm7Y4XC\",\n};\n\n/** Sources this release signs (vault swaps the engine can execute and the verifier can decode). */\nexport const CF_SOURCE_CHAINS = new Set([\"eip155:1\", \"eip155:42161\", \"tron:728126428\"]);\n\nexport const CF_API_DEFAULT = \"https://chainflip-swap.chainflip.io\";\n\nconst sameToken = (chain: string, a: string, b: string) => (chain.startsWith(\"eip155:\") ? a.toLowerCase() === b.toLowerCase() : a === b);\nconst NATIVE = new Set([\"\", \"native\", \"0x0000000000000000000000000000000000000000\"]);\n\n/** The Chainflip asset for a CAIP-2 chain + token (contract / mint, a native marker, or the asset symbol). */\nexport function cfAsset(chain: string, token: string): CfAsset | undefined {\n const c = CF_CHAINS[chain];\n if (!c) return undefined;\n const on = CF_ASSETS.filter((a) => a.chain === c.name);\n if (NATIVE.has(token.toLowerCase())) return on.find((a) => a.token === null);\n return on.find((a) => (a.token !== null && sameToken(chain, a.token, token)) || a.asset === token.toUpperCase());\n}\n\nexport const chainflip = {\n supportsChain: (chain: string) => !!CF_CHAINS[chain],\n supports: (from: string, to: string) => CF_SOURCE_CHAINS.has(from) && !!CF_CHAINS[to] && from !== to,\n};\n\n/** The reason behind each text {@link chainflipVerifyQuote} and the pins' verifyBuild return (`chainflipPins.reasonOf`). */\nconst notes = refusalNotes();\n/**\n * Decode-failure texts last returned for the app's own field (destination, refund address, amount) that did not parse:\n * the caller's argument, so `reasonOf` leaves them unclassified. The same text can come from a quote that does not\n * decode, so the latest verdict wins; kept to the last 64.\n */\nconst unparsed = new Set<string>();\nfunction decodeFailure(text: string, requestParsed: boolean): string {\n unparsed.delete(text);\n if (requestParsed) return notes.note(text, \"upstream_unavailable\");\n unparsed.add(text);\n if (unparsed.size > 64) unparsed.delete(unparsed.values().next().value!);\n return text;\n}\nconst reasonOf = (text: string) => (unparsed.has(text) ? undefined : notes.reasonOf(text));\n\n/**\n * The provider's own decode of a vault swap, run on the client against the app's request (scan 2026-10-28, F9): an\n * EVM source is a vault call (`xSwapNative` / `xSwapToken`) on the pinned Vault, a Tron source a send to the pinned\n * Tron Vault whose note carries the swap; either way the destination chain, asset and address, the source token and\n * amount, the refund address and a minimum price that guarantees the quoted minimum must be the app's, with no DCA,\n * boost, broker fee or affiliates. The reason it fails, or null.\n */\nexport function chainflipVerifyQuote(params: QuoteParams, quote: Quote): string | null {\n // True while the app's own fields are read: a throw then is the caller's argument, not the quote's.\n let readingRequest = false;\n try {\n const src = cfAsset(params.sourceChain, params.sourceToken);\n const dst = cfAsset(params.destChain, params.destToken);\n const dstChain = CF_CHAINS[params.destChain];\n const vault = Object.prototype.hasOwnProperty.call(CF_VAULTS, params.sourceChain) ? CF_VAULTS[params.sourceChain] : undefined;\n if (!src || !dst || !dstChain || !vault || !CF_SOURCE_CHAINS.has(params.sourceChain)) return notes.note(\"not a vault swap this release signs\", \"unsupported_pair\");\n // A dry quote lists a route and pays nobody; execution re-quotes live.\n if (!quote.txRequest && !quote.depositAddress) return null;\n if (!params.refundAddress) return notes.note(\"a live quote needs the refund address\", \"policy_refused\");\n readingRequest = true;\n const amountIn = BigInt(params.amountIn);\n const dest = destAddressBytes(params.destChain, params.destAddress);\n const refund = destAddressBytes(params.sourceChain, params.refundAddress);\n readingRequest = false;\n const checkParams = (p: CfParameters): string | null => {\n if (!sameBytes(fromHex(p.refundAddress), refund)) return notes.note(\"the refund address is not the sender\", \"recipient_mismatch\");\n if (minOutOf(amountIn, p.minPriceX128) < BigInt(quote.minDestAmount)) return notes.note(\"the minimum price does not guarantee the quoted minimum\", \"price_check_failed\");\n if (p.dca !== null || p.boostFeeBps !== 0 || p.broker.feeBps !== 0 || p.affiliates.length) return notes.note(\"DCA, boost, a broker fee or affiliates\", \"policy_refused\");\n return null;\n };\n if (params.sourceChain.startsWith(\"eip155:\")) {\n const tx = quote.txRequest;\n if (quote.depositAddress || !tx?.data || tx.serializedTx !== undefined) return notes.note(\"an EVM vault swap is a vault call, not a deposit\", \"policy_refused\");\n if (!tx.to || tx.to.toLowerCase() !== vault.toLowerCase()) return notes.note(`the call targets ${tx.to}, not the Vault`, \"vault_mismatch\");\n const v = decodeEvmVaultCall(tx.data);\n if (v.dstChain !== dstChain.id || v.dstToken !== dst.id || !sameBytes(v.dstAddress, dest)) return notes.note(\"the vault call names another destination\", \"recipient_mismatch\");\n if (src.token === null) {\n if (!v.native || BigInt(tx.value ?? \"0\") !== amountIn || tx.approvalAddress) return notes.note(\"the native vault call moves another amount\", \"policy_refused\");\n } else if (v.native || v.srcToken?.toLowerCase() !== src.token.toLowerCase() || v.amount !== amountIn || BigInt(tx.value ?? \"0\") !== 0n ||\n tx.approvalAddress?.toLowerCase() !== vault.toLowerCase()) {\n return notes.note(\"the token vault call moves another token or amount\", \"policy_refused\");\n }\n return checkParams(v.params);\n }\n // Tron: the deposit is a send of the input to the Vault, the swap riding in the note.\n if (quote.txRequest || quote.depositAddress !== vault || !quote.depositMemo) {\n // A send elsewhere is the wrong vault; a send to the Vault without its note binds no destination.\n return notes.note(\"a Tron vault swap is a send to the Tron Vault with its note\",\n quote.txRequest ? \"policy_refused\" : quote.depositAddress !== vault ? \"vault_mismatch\" : \"recipient_unverifiable\");\n }\n const n = decodeTronNote(quote.depositMemo);\n if (n.outputAsset !== dst.id || n.destTag !== dstChain.addrTag || !sameBytes(n.destAddress, dest)) return notes.note(\"the note names another destination\", \"recipient_mismatch\");\n return checkParams(n.params);\n } catch (e) {\n return decodeFailure(`the vault swap does not decode (${(e instanceof Error ? e.message : String(e)).slice(0, 120)})`, !readingRequest);\n }\n}\n\n/**\n * The Chainflip Vault a vault swap calls and approves on an EVM chain ({@link CF_VAULTS}), and\n * {@link chainflipVerifyQuote} — the app's pins for `remoteProvider({name: \"chainflip\", baseUrl, ...chainflipPins})`\n * (scan 2026-10-27 modules, F8/F16). A Tron vault swap is a send to the Tron Vault the verifier pins, so the stub is\n * opened to that deposit route (`depositAddressRoutes`, scan 2026-10-28 F9); its note must ride as hex bytes. `reasonOf`\n * classifies each text the verifiers return (`Swap2RefusalReason`), so a remote stub's refusal carries it.\n */\nexport const chainflipPins: RemotePins = Object.freeze({\n callTargets: (chain: string): readonly string[] => chainflipVaultFor(chain),\n spenders: (chain: string): readonly string[] => chainflipVaultFor(chain),\n verifyQuote: chainflipVerifyQuote,\n verifyBuild: (quote: Quote, tx: UnsignedTx): string | null =>\n quote.depositMemo && tx.memoEncoding !== \"hex\" ? notes.note(\"the Tron note is not sent as hex bytes\", \"policy_refused\") : null,\n reasonOf,\n depositAddressRoutes: true,\n});\nfunction chainflipVaultFor(chain: string): readonly string[] {\n const vault = chain.startsWith(\"eip155:\") && Object.prototype.hasOwnProperty.call(CF_VAULTS, chain) ? CF_VAULTS[chain] : undefined;\n return vault ? [vault] : [];\n}\n","/**\n * Decoders for what Chainflip's encoder returns, so a vault swap is checked byte by byte before anyone signs it:\n * - VersionedCfParameters (SCALE): retry window, refund address, minimum price (X128), oracle slippage, DCA, boost,\n * broker + its fee, affiliates — the EVM vault call's `cfParameters` and the tail of the Tron note;\n * - the Tron note: output asset id, encoded destination address, CCM option, then the length-prefixed parameters;\n * - the EVM vault calls xSwapNative / xSwapToken.\n * Layouts were decoded from live encoder outputs (2026-10-20) and match the state chain's types.\n */\nimport {base58} from \"@scure/base\";\nimport {sha256} from \"@noble/hashes/sha2.js\";\nimport {decodeFunctionData, parseAbi, type Hex} from \"viem\";\n\nexport interface CfParameters {\n version: number;\n retryDurationBlocks: number;\n /** raw refund address bytes (20 for EVM / Tron, 32 for Solana) as 0x-hex */\n refundAddress: Hex;\n /** minimum output price × 2^128, scaled by 10^(destDecimals − srcDecimals) */\n minPriceX128: bigint;\n refundCcm: boolean;\n maxOraclePriceSlippageBps: number | null;\n dca: {chunks: number; intervalBlocks: number} | null;\n boostFeeBps: number;\n broker: {account: Hex; feeBps: number};\n affiliates: {account: number; feeBps: number}[];\n}\n\nclass Reader {\n i = 0;\n constructor(readonly b: Uint8Array) {}\n need(n: number) { if (this.i + n > this.b.length) throw new Error(`chainflip codec: truncated at ${this.i} (+${n} of ${this.b.length})`); }\n u8() { this.need(1); return this.b[this.i++]!; }\n bytes(n: number) { this.need(n); const out = this.b.slice(this.i, this.i + n); this.i += n; return out; }\n uLE(n: number): bigint { const x = this.bytes(n); let v = 0n; for (let k = n - 1; k >= 0; k--) v = (v << 8n) | BigInt(x[k]!); return v; }\n /** Little-endian unsigned of up to 6 bytes as a number (exact: below 2^48). */\n uNum(n: number): number { if (n > 6) throw new Error(\"chainflip codec: uNum takes at most 6 bytes\"); const x = this.bytes(n); let v = 0; for (let k = n - 1; k >= 0; k--) v = v * 256 + x[k]!; return v; }\n /** SCALE compact integer */\n compact(): number {\n const first = this.u8();\n const mode = first & 3;\n if (mode === 0) return first >> 2;\n if (mode === 1) return ((this.u8() << 8) | first) >> 2;\n if (mode === 2) { const rest = this.uNum(3); return ((rest << 8) | first) >>> 2; }\n throw new Error(\"chainflip codec: big compact integers are not used here\");\n }\n done() { if (this.i !== this.b.length) throw new Error(`chainflip codec: ${this.b.length - this.i} trailing bytes`); }\n}\n\nexport const toHex = (b: Uint8Array): Hex => `0x${[...b].map((x) => x.toString(16).padStart(2, \"0\")).join(\"\")}` as Hex;\nexport function fromHex(h: string): Uint8Array {\n const s = h.startsWith(\"0x\") ? h.slice(2) : h;\n if (s.length % 2 || /[^0-9a-f]/i.test(s)) throw new Error(\"chainflip codec: not hex\");\n return Uint8Array.from(s.match(/../g) ?? [], (x) => Number.parseInt(x, 16));\n}\n\n/** VersionedCfParameters V1. `refundLen` = 20 for EVM / Tron sources, 32 for Solana. */\nexport function decodeCfParameters(bytes: Uint8Array, refundLen: 20 | 32): CfParameters {\n const r = new Reader(bytes);\n const p = readCfParameters(r, refundLen);\n r.done();\n return p;\n}\n\nfunction readCfParameters(r: Reader, refundLen: number): CfParameters {\n const version = r.u8();\n if (version !== 1) throw new Error(`chainflip codec: cf parameters version ${version}`);\n // ccm_additional_data is `()` for non-CCM swaps: zero bytes\n const retryDurationBlocks = r.uNum(4);\n const refundAddress = toHex(r.bytes(refundLen));\n const minPriceX128 = r.uLE(32);\n const refundCcm = r.u8() !== 0;\n if (refundCcm) throw new Error(\"chainflip codec: refund CCM metadata is not expected\");\n const maxOraclePriceSlippageBps = r.u8() ? r.uNum(2) : null;\n const dca = r.u8() ? {chunks: r.uNum(4), intervalBlocks: r.uNum(4)} : null;\n const boostFeeBps = r.u8();\n const broker = {account: toHex(r.bytes(32)), feeBps: r.uNum(2)};\n const n = r.compact();\n const affiliates = Array.from({length: n}, () => ({account: r.u8(), feeBps: r.uNum(2)}));\n return {version, retryDurationBlocks, refundAddress, minPriceX128, refundCcm, maxOraclePriceSlippageBps, dca, boostFeeBps, broker, affiliates};\n}\n\nexport interface TronNote {\n outputAsset: number;\n /** EncodedAddress variant of the destination (Eth 0, Dot 1, Btc 2, Arb 3, Sol 4, Hub 5, Tron 6) and its raw bytes */\n destTag: number;\n destAddress: Uint8Array;\n ccm: boolean;\n params: CfParameters;\n}\n\n/** Address byte length per encoded-address tag (EncodedAddress enum: Eth, Dot, Btc, Arb, Sol, Hub, Tron …). */\nconst TAG_LEN: Record<number, number | \"vec\"> = {0: 20, 1: 32, 2: \"vec\", 3: 20, 4: 32, 5: 32, 6: 20};\n\n/** The note a Tron vault swap carries in raw_data.data. */\nexport function decodeTronNote(note: string): TronNote {\n const r = new Reader(fromHex(note));\n const outputAsset = r.u8();\n const destTag = r.u8();\n const len = TAG_LEN[destTag];\n if (len === undefined) throw new Error(`chainflip codec: unknown address tag ${destTag}`);\n const destAddress = len === \"vec\" ? r.bytes(r.compact()) : r.bytes(len);\n const ccm = r.u8() !== 0;\n if (ccm) throw new Error(\"chainflip codec: CCM swaps are not expected\");\n const paramsLen = r.compact();\n const start = r.i;\n const params = readCfParameters(r, 20);\n if (r.i - start !== paramsLen) throw new Error(`chainflip codec: cf parameters length ${r.i - start} ≠ declared ${paramsLen}`);\n r.done();\n return {outputAsset, destTag, destAddress, ccm, params};\n}\n\nconst VAULT_ABI = parseAbi([\n \"function xSwapNative(uint32 dstChain, bytes dstAddress, uint32 dstToken, bytes cfParameters) payable\",\n \"function xSwapToken(uint32 dstChain, bytes dstAddress, uint32 dstToken, address srcToken, uint256 amount, bytes cfParameters)\",\n]);\n\nexport interface EvmVaultCall {\n native: boolean;\n dstChain: number;\n dstAddress: Uint8Array;\n dstToken: number;\n srcToken: string | null;\n amount: bigint | null;\n params: CfParameters;\n}\n\nexport function decodeEvmVaultCall(data: string): EvmVaultCall {\n const d = decodeFunctionData({abi: VAULT_ABI, data: data as Hex});\n if (d.functionName === \"xSwapNative\") {\n const [dstChain, dstAddress, dstToken, cf] = d.args;\n return {native: true, dstChain, dstAddress: fromHex(dstAddress), dstToken, srcToken: null, amount: null, params: decodeCfParameters(fromHex(cf), 20)};\n }\n const [dstChain, dstAddress, dstToken, srcToken, amount, cf] = d.args;\n return {native: false, dstChain, dstAddress: fromHex(dstAddress), dstToken, srcToken, amount, params: decodeCfParameters(fromHex(cf), 20)};\n}\n\n/** Tron base58check `T…` ↔ the 20 raw bytes Chainflip encodes (0x41 prefix dropped). */\nexport function tronToBytes(address: string): Uint8Array {\n const b = base58.decode(address);\n if (b.length !== 25 || b[0] !== 0x41) throw new Error(`not a Tron address: ${address}`);\n const check = sha256(sha256(b.subarray(0, 21))).subarray(0, 4);\n if (toHex(check) !== toHex(b.subarray(21))) throw new Error(`bad Tron checksum: ${address}`);\n return b.subarray(1, 21);\n}\n\n/** The raw bytes a destination address is encoded with, per destination chain (EVM / Tron 20, Solana 32, BTC ASCII). */\nexport function destAddressBytes(chain: string, address: string): Uint8Array {\n if (chain.startsWith(\"eip155:\")) return fromHex(address);\n if (chain.startsWith(\"tron:\")) return tronToBytes(address);\n if (chain.startsWith(\"solana:\")) { const b = base58.decode(address); if (b.length !== 32) throw new Error(`not a Solana address: ${address}`); return b; }\n if (chain.startsWith(\"bitcoin:\")) return new TextEncoder().encode(address);\n throw new Error(`chainflip: no address encoding for ${chain}`);\n}\n\nexport const sameBytes = (a: Uint8Array, b: Uint8Array) => a.length === b.length && a.every((x, i) => x === b[i]);\n\n/** minPriceX128 for a guaranteed output: ceil(minOut × 2^128 / amountIn) (base units on both sides carry the decimals). */\nexport function minPriceX128For(amountIn: bigint, minOut: bigint): bigint {\n return (minOut * 2n ** 128n + amountIn - 1n) / amountIn;\n}\n/** The output a min price guarantees for `amountIn` (floor). */\nexport function minOutOf(amountIn: bigint, minPriceX128: bigint): bigint {\n return (amountIn * minPriceX128) / 2n ** 128n;\n}\n"],"mappings":"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","names":["dstChain","dstAddress","dstToken","cf"]}
package/dist/activity.js CHANGED
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  CHAINFLIP_MODULE,
3
3
  describeChainflipActivity
4
- } from "./chunk-ZH5XKSCP.js";
5
- import "./chunk-DGLXKJQ7.js";
4
+ } from "./chunk-C2OITXU4.js";
5
+ import "./chunk-IQSAPDND.js";
6
6
  import "./chunk-SJ6UVIVY.js";
7
7
  export {
8
8
  CHAINFLIP_MODULE,
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  CF_VAULTS
3
- } from "./chunk-DGLXKJQ7.js";
3
+ } from "./chunk-IQSAPDND.js";
4
4
 
5
5
  // src/activity.ts
6
6
  import { describeSwapLike } from "@anywalletkit/protocol-swap2-core/activity";
@@ -19,4 +19,4 @@ export {
19
19
  CHAINFLIP_MODULE,
20
20
  describeChainflipActivity
21
21
  };
22
- //# sourceMappingURL=chunk-ZH5XKSCP.js.map
22
+ //# sourceMappingURL=chunk-C2OITXU4.js.map
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  chainflipProvider
3
- } from "./chunk-RU2NXJTL.js";
3
+ } from "./chunk-XUMGQNH4.js";
4
4
  import {
5
5
  chainflip
6
- } from "./chunk-DGLXKJQ7.js";
6
+ } from "./chunk-IQSAPDND.js";
7
7
 
8
8
  // src/protocol.ts
9
9
  import { SingleProviderSwap2 } from "@anywalletkit/protocol-swap2-core/swap2/single";
@@ -24,4 +24,4 @@ var ChainflipSwap2Protocol = class extends SingleProviderSwap2 {
24
24
  export {
25
25
  ChainflipSwap2Protocol
26
26
  };
27
- //# sourceMappingURL=chunk-RRCQYT67.js.map
27
+ //# sourceMappingURL=chunk-G5FZLGMT.js.map
@@ -8,6 +8,7 @@ import {
8
8
  } from "./chunk-SJ6UVIVY.js";
9
9
 
10
10
  // src/config.ts
11
+ import { refusalNotes } from "@anywalletkit/protocol-swap2-core/errors";
11
12
  var CF_CHAINS = {
12
13
  "eip155:1": { name: "Ethereum", id: 1, addrTag: 0 },
13
14
  "bitcoin:mainnet": { name: "Bitcoin", id: 3, addrTag: 2 },
@@ -50,50 +51,69 @@ var chainflip = {
50
51
  supportsChain: (chain) => !!CF_CHAINS[chain],
51
52
  supports: (from, to) => CF_SOURCE_CHAINS.has(from) && !!CF_CHAINS[to] && from !== to
52
53
  };
54
+ var notes = refusalNotes();
55
+ var unparsed = /* @__PURE__ */ new Set();
56
+ function decodeFailure(text, requestParsed) {
57
+ unparsed.delete(text);
58
+ if (requestParsed) return notes.note(text, "upstream_unavailable");
59
+ unparsed.add(text);
60
+ if (unparsed.size > 64) unparsed.delete(unparsed.values().next().value);
61
+ return text;
62
+ }
63
+ var reasonOf = (text) => unparsed.has(text) ? void 0 : notes.reasonOf(text);
53
64
  function chainflipVerifyQuote(params, quote) {
65
+ let readingRequest = false;
54
66
  try {
55
67
  const src = cfAsset(params.sourceChain, params.sourceToken);
56
68
  const dst = cfAsset(params.destChain, params.destToken);
57
69
  const dstChain = CF_CHAINS[params.destChain];
58
70
  const vault = Object.prototype.hasOwnProperty.call(CF_VAULTS, params.sourceChain) ? CF_VAULTS[params.sourceChain] : void 0;
59
- if (!src || !dst || !dstChain || !vault || !CF_SOURCE_CHAINS.has(params.sourceChain)) return "not a vault swap this release signs";
71
+ if (!src || !dst || !dstChain || !vault || !CF_SOURCE_CHAINS.has(params.sourceChain)) return notes.note("not a vault swap this release signs", "unsupported_pair");
60
72
  if (!quote.txRequest && !quote.depositAddress) return null;
61
- if (!params.refundAddress) return "a live quote needs the refund address";
73
+ if (!params.refundAddress) return notes.note("a live quote needs the refund address", "policy_refused");
74
+ readingRequest = true;
62
75
  const amountIn = BigInt(params.amountIn);
63
76
  const dest = destAddressBytes(params.destChain, params.destAddress);
64
77
  const refund = destAddressBytes(params.sourceChain, params.refundAddress);
78
+ readingRequest = false;
65
79
  const checkParams = (p) => {
66
- if (!sameBytes(fromHex(p.refundAddress), refund)) return "the refund address is not the sender";
67
- if (minOutOf(amountIn, p.minPriceX128) < BigInt(quote.minDestAmount)) return "the minimum price does not guarantee the quoted minimum";
68
- if (p.dca !== null || p.boostFeeBps !== 0 || p.broker.feeBps !== 0 || p.affiliates.length) return "DCA, boost, a broker fee or affiliates";
80
+ if (!sameBytes(fromHex(p.refundAddress), refund)) return notes.note("the refund address is not the sender", "recipient_mismatch");
81
+ if (minOutOf(amountIn, p.minPriceX128) < BigInt(quote.minDestAmount)) return notes.note("the minimum price does not guarantee the quoted minimum", "price_check_failed");
82
+ if (p.dca !== null || p.boostFeeBps !== 0 || p.broker.feeBps !== 0 || p.affiliates.length) return notes.note("DCA, boost, a broker fee or affiliates", "policy_refused");
69
83
  return null;
70
84
  };
71
85
  if (params.sourceChain.startsWith("eip155:")) {
72
86
  const tx = quote.txRequest;
73
- if (quote.depositAddress || !tx?.data || tx.serializedTx !== void 0) return "an EVM vault swap is a vault call, not a deposit";
74
- if (!tx.to || tx.to.toLowerCase() !== vault.toLowerCase()) return `the call targets ${tx.to}, not the Vault`;
87
+ if (quote.depositAddress || !tx?.data || tx.serializedTx !== void 0) return notes.note("an EVM vault swap is a vault call, not a deposit", "policy_refused");
88
+ if (!tx.to || tx.to.toLowerCase() !== vault.toLowerCase()) return notes.note(`the call targets ${tx.to}, not the Vault`, "vault_mismatch");
75
89
  const v = decodeEvmVaultCall(tx.data);
76
- if (v.dstChain !== dstChain.id || v.dstToken !== dst.id || !sameBytes(v.dstAddress, dest)) return "the vault call names another destination";
90
+ if (v.dstChain !== dstChain.id || v.dstToken !== dst.id || !sameBytes(v.dstAddress, dest)) return notes.note("the vault call names another destination", "recipient_mismatch");
77
91
  if (src.token === null) {
78
- if (!v.native || BigInt(tx.value ?? "0") !== amountIn || tx.approvalAddress) return "the native vault call moves another amount";
92
+ if (!v.native || BigInt(tx.value ?? "0") !== amountIn || tx.approvalAddress) return notes.note("the native vault call moves another amount", "policy_refused");
79
93
  } else if (v.native || v.srcToken?.toLowerCase() !== src.token.toLowerCase() || v.amount !== amountIn || BigInt(tx.value ?? "0") !== 0n || tx.approvalAddress?.toLowerCase() !== vault.toLowerCase()) {
80
- return "the token vault call moves another token or amount";
94
+ return notes.note("the token vault call moves another token or amount", "policy_refused");
81
95
  }
82
96
  return checkParams(v.params);
83
97
  }
84
- if (quote.txRequest || quote.depositAddress !== vault || !quote.depositMemo) return "a Tron vault swap is a send to the Tron Vault with its note";
98
+ if (quote.txRequest || quote.depositAddress !== vault || !quote.depositMemo) {
99
+ return notes.note(
100
+ "a Tron vault swap is a send to the Tron Vault with its note",
101
+ quote.txRequest ? "policy_refused" : quote.depositAddress !== vault ? "vault_mismatch" : "recipient_unverifiable"
102
+ );
103
+ }
85
104
  const n = decodeTronNote(quote.depositMemo);
86
- if (n.outputAsset !== dst.id || n.destTag !== dstChain.addrTag || !sameBytes(n.destAddress, dest)) return "the note names another destination";
105
+ if (n.outputAsset !== dst.id || n.destTag !== dstChain.addrTag || !sameBytes(n.destAddress, dest)) return notes.note("the note names another destination", "recipient_mismatch");
87
106
  return checkParams(n.params);
88
107
  } catch (e) {
89
- return `the vault swap does not decode (${(e instanceof Error ? e.message : String(e)).slice(0, 120)})`;
108
+ return decodeFailure(`the vault swap does not decode (${(e instanceof Error ? e.message : String(e)).slice(0, 120)})`, !readingRequest);
90
109
  }
91
110
  }
92
111
  var chainflipPins = Object.freeze({
93
112
  callTargets: (chain) => chainflipVaultFor(chain),
94
113
  spenders: (chain) => chainflipVaultFor(chain),
95
114
  verifyQuote: chainflipVerifyQuote,
96
- verifyBuild: (quote, tx) => quote.depositMemo && tx.memoEncoding !== "hex" ? "the Tron note is not sent as hex bytes" : null,
115
+ verifyBuild: (quote, tx) => quote.depositMemo && tx.memoEncoding !== "hex" ? notes.note("the Tron note is not sent as hex bytes", "policy_refused") : null,
116
+ reasonOf,
97
117
  depositAddressRoutes: true
98
118
  });
99
119
  function chainflipVaultFor(chain) {
@@ -112,4 +132,4 @@ export {
112
132
  chainflipVerifyQuote,
113
133
  chainflipPins
114
134
  };
115
- //# sourceMappingURL=chunk-DGLXKJQ7.js.map
135
+ //# sourceMappingURL=chunk-IQSAPDND.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/config.ts"],"sourcesContent":["/**\n * Chainflip (JIT-AMM state chain) — chains, assets and contracts as the public backend and the vault encodings name them.\n * Asset ids, chain ids and decimals are the protocol's own (`cf_environment` / networkInfo, verified 2026-10-20); the\n * contract addresses are Chainflip's mainnet deployments (docs mainnet-addresses, confirmed by live encodings).\n *\n * Only VAULT SWAPS are offered: the donor signs a transaction whose every Chainflip parameter (destination, minimum price,\n * refund address) is decoded and checked locally before signing — no off-chain deposit channel to trust, and on Tron no\n * 3.4 USDT ingress fee. Sources: EVM (Ethereum, Arbitrum) and Tron in this release; Solana / Bitcoin vault swaps need an\n * instruction / OP_RETURN builder and come next. Destinations: every live chain.\n */\nimport {refusalNotes} from \"@anywalletkit/protocol-swap2-core/errors\";\nimport type {Quote, QuoteParams, RemotePins, UnsignedTx} from \"@anywalletkit/protocol-swap2-core/types\";\nimport {decodeEvmVaultCall, decodeTronNote, destAddressBytes, fromHex, minOutOf, sameBytes, type CfParameters} from \"./codec.js\";\n\nexport type CfChain = \"Ethereum\" | \"Bitcoin\" | \"Arbitrum\" | \"Solana\" | \"Tron\";\n\nexport interface CfAsset {\n chain: CfChain;\n /** the API's asset symbol */\n asset: string;\n /** the u32 asset id inside vault encodings */\n id: number;\n decimals: number;\n /** token contract / mint on its chain, null for the native coin */\n token: string | null;\n /** smallest deposit the state chain accepts (base units) */\n minDeposit: bigint;\n}\n\n/**\n * CAIP-2 → Chainflip chain: `id` = the ForeignChain number an EVM vault call names (`dstChain`), `addrTag` = the\n * EncodedAddress variant a Tron note names (Eth 0, Dot 1, Btc 2, Arb 3, Sol 4, Hub 5, Tron 6) — two different enums.\n */\nexport const CF_CHAINS: Readonly<Record<string, {name: CfChain; id: number; addrTag: number}>> = {\n \"eip155:1\": {name: \"Ethereum\", id: 1, addrTag: 0},\n \"bitcoin:mainnet\": {name: \"Bitcoin\", id: 3, addrTag: 2},\n \"eip155:42161\": {name: \"Arbitrum\", id: 4, addrTag: 3},\n \"solana:mainnet\": {name: \"Solana\", id: 5, addrTag: 4},\n \"tron:728126428\": {name: \"Tron\", id: 7, addrTag: 6},\n};\n\nexport const CF_ASSETS: readonly CfAsset[] = [\n {chain: \"Ethereum\", asset: \"ETH\", id: 1, decimals: 18, token: null, minDeposit: 10n ** 16n},\n {chain: \"Ethereum\", asset: \"USDC\", id: 3, decimals: 6, token: \"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48\", minDeposit: 20_000_000n},\n {chain: \"Ethereum\", asset: \"USDT\", id: 8, decimals: 6, token: \"0xdAC17F958D2ee523a2206206994597C13D831ec7\", minDeposit: 20_000_000n},\n {chain: \"Ethereum\", asset: \"WBTC\", id: 14, decimals: 8, token: \"0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599\", minDeposit: 40_000n},\n {chain: \"Bitcoin\", asset: \"BTC\", id: 5, decimals: 8, token: null, minDeposit: 40_000n},\n {chain: \"Arbitrum\", asset: \"ETH\", id: 6, decimals: 18, token: null, minDeposit: 3_900_000_000_000_000n},\n {chain: \"Arbitrum\", asset: \"USDC\", id: 7, decimals: 6, token: \"0xaf88d065e77c8cC2239327C5EDb3A432268e5831\", minDeposit: 10_000_000n},\n {chain: \"Arbitrum\", asset: \"USDT\", id: 15, decimals: 6, token: \"0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9\", minDeposit: 10_000_000n},\n {chain: \"Solana\", asset: \"SOL\", id: 9, decimals: 9, token: null, minDeposit: 68_000_000n},\n {chain: \"Solana\", asset: \"USDC\", id: 10, decimals: 6, token: \"EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v\", minDeposit: 10_000_000n},\n {chain: \"Solana\", asset: \"USDT\", id: 16, decimals: 6, token: \"Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB\", minDeposit: 10_000_000n},\n {chain: \"Tron\", asset: \"TRX\", id: 17, decimals: 6, token: null, minDeposit: 30_000_000n},\n {chain: \"Tron\", asset: \"USDT\", id: 18, decimals: 6, token: \"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t\", minDeposit: 10_000_000n},\n];\n\n/** Vault contracts that receive vault swaps (the deposit transaction's target). */\nexport const CF_VAULTS: Readonly<Record<string, string>> = {\n \"eip155:1\": \"0xF5e10380213880111522dd0efD3dbb45b9f62Bcc\",\n \"eip155:42161\": \"0x79001a5e762f3bEFC8e5871b42F6734e00498920\",\n \"tron:728126428\": \"TEcDijvKSXcfWT7S6rd44H5vNgufm7Y4XC\",\n};\n\n/** Sources this release signs (vault swaps the engine can execute and the verifier can decode). */\nexport const CF_SOURCE_CHAINS = new Set([\"eip155:1\", \"eip155:42161\", \"tron:728126428\"]);\n\nexport const CF_API_DEFAULT = \"https://chainflip-swap.chainflip.io\";\n\nconst sameToken = (chain: string, a: string, b: string) => (chain.startsWith(\"eip155:\") ? a.toLowerCase() === b.toLowerCase() : a === b);\nconst NATIVE = new Set([\"\", \"native\", \"0x0000000000000000000000000000000000000000\"]);\n\n/** The Chainflip asset for a CAIP-2 chain + token (contract / mint, a native marker, or the asset symbol). */\nexport function cfAsset(chain: string, token: string): CfAsset | undefined {\n const c = CF_CHAINS[chain];\n if (!c) return undefined;\n const on = CF_ASSETS.filter((a) => a.chain === c.name);\n if (NATIVE.has(token.toLowerCase())) return on.find((a) => a.token === null);\n return on.find((a) => (a.token !== null && sameToken(chain, a.token, token)) || a.asset === token.toUpperCase());\n}\n\nexport const chainflip = {\n supportsChain: (chain: string) => !!CF_CHAINS[chain],\n supports: (from: string, to: string) => CF_SOURCE_CHAINS.has(from) && !!CF_CHAINS[to] && from !== to,\n};\n\n/** The reason behind each text {@link chainflipVerifyQuote} and the pins' verifyBuild return (`chainflipPins.reasonOf`). */\nconst notes = refusalNotes();\n/**\n * Decode-failure texts last returned for the app's own field (destination, refund address, amount) that did not parse:\n * the caller's argument, so `reasonOf` leaves them unclassified. The same text can come from a quote that does not\n * decode, so the latest verdict wins; kept to the last 64.\n */\nconst unparsed = new Set<string>();\nfunction decodeFailure(text: string, requestParsed: boolean): string {\n unparsed.delete(text);\n if (requestParsed) return notes.note(text, \"upstream_unavailable\");\n unparsed.add(text);\n if (unparsed.size > 64) unparsed.delete(unparsed.values().next().value!);\n return text;\n}\nconst reasonOf = (text: string) => (unparsed.has(text) ? undefined : notes.reasonOf(text));\n\n/**\n * The provider's own decode of a vault swap, run on the client against the app's request (scan 2026-10-28, F9): an\n * EVM source is a vault call (`xSwapNative` / `xSwapToken`) on the pinned Vault, a Tron source a send to the pinned\n * Tron Vault whose note carries the swap; either way the destination chain, asset and address, the source token and\n * amount, the refund address and a minimum price that guarantees the quoted minimum must be the app's, with no DCA,\n * boost, broker fee or affiliates. The reason it fails, or null.\n */\nexport function chainflipVerifyQuote(params: QuoteParams, quote: Quote): string | null {\n // True while the app's own fields are read: a throw then is the caller's argument, not the quote's.\n let readingRequest = false;\n try {\n const src = cfAsset(params.sourceChain, params.sourceToken);\n const dst = cfAsset(params.destChain, params.destToken);\n const dstChain = CF_CHAINS[params.destChain];\n const vault = Object.prototype.hasOwnProperty.call(CF_VAULTS, params.sourceChain) ? CF_VAULTS[params.sourceChain] : undefined;\n if (!src || !dst || !dstChain || !vault || !CF_SOURCE_CHAINS.has(params.sourceChain)) return notes.note(\"not a vault swap this release signs\", \"unsupported_pair\");\n // A dry quote lists a route and pays nobody; execution re-quotes live.\n if (!quote.txRequest && !quote.depositAddress) return null;\n if (!params.refundAddress) return notes.note(\"a live quote needs the refund address\", \"policy_refused\");\n readingRequest = true;\n const amountIn = BigInt(params.amountIn);\n const dest = destAddressBytes(params.destChain, params.destAddress);\n const refund = destAddressBytes(params.sourceChain, params.refundAddress);\n readingRequest = false;\n const checkParams = (p: CfParameters): string | null => {\n if (!sameBytes(fromHex(p.refundAddress), refund)) return notes.note(\"the refund address is not the sender\", \"recipient_mismatch\");\n if (minOutOf(amountIn, p.minPriceX128) < BigInt(quote.minDestAmount)) return notes.note(\"the minimum price does not guarantee the quoted minimum\", \"price_check_failed\");\n if (p.dca !== null || p.boostFeeBps !== 0 || p.broker.feeBps !== 0 || p.affiliates.length) return notes.note(\"DCA, boost, a broker fee or affiliates\", \"policy_refused\");\n return null;\n };\n if (params.sourceChain.startsWith(\"eip155:\")) {\n const tx = quote.txRequest;\n if (quote.depositAddress || !tx?.data || tx.serializedTx !== undefined) return notes.note(\"an EVM vault swap is a vault call, not a deposit\", \"policy_refused\");\n if (!tx.to || tx.to.toLowerCase() !== vault.toLowerCase()) return notes.note(`the call targets ${tx.to}, not the Vault`, \"vault_mismatch\");\n const v = decodeEvmVaultCall(tx.data);\n if (v.dstChain !== dstChain.id || v.dstToken !== dst.id || !sameBytes(v.dstAddress, dest)) return notes.note(\"the vault call names another destination\", \"recipient_mismatch\");\n if (src.token === null) {\n if (!v.native || BigInt(tx.value ?? \"0\") !== amountIn || tx.approvalAddress) return notes.note(\"the native vault call moves another amount\", \"policy_refused\");\n } else if (v.native || v.srcToken?.toLowerCase() !== src.token.toLowerCase() || v.amount !== amountIn || BigInt(tx.value ?? \"0\") !== 0n ||\n tx.approvalAddress?.toLowerCase() !== vault.toLowerCase()) {\n return notes.note(\"the token vault call moves another token or amount\", \"policy_refused\");\n }\n return checkParams(v.params);\n }\n // Tron: the deposit is a send of the input to the Vault, the swap riding in the note.\n if (quote.txRequest || quote.depositAddress !== vault || !quote.depositMemo) {\n // A send elsewhere is the wrong vault; a send to the Vault without its note binds no destination.\n return notes.note(\"a Tron vault swap is a send to the Tron Vault with its note\",\n quote.txRequest ? \"policy_refused\" : quote.depositAddress !== vault ? \"vault_mismatch\" : \"recipient_unverifiable\");\n }\n const n = decodeTronNote(quote.depositMemo);\n if (n.outputAsset !== dst.id || n.destTag !== dstChain.addrTag || !sameBytes(n.destAddress, dest)) return notes.note(\"the note names another destination\", \"recipient_mismatch\");\n return checkParams(n.params);\n } catch (e) {\n return decodeFailure(`the vault swap does not decode (${(e instanceof Error ? e.message : String(e)).slice(0, 120)})`, !readingRequest);\n }\n}\n\n/**\n * The Chainflip Vault a vault swap calls and approves on an EVM chain ({@link CF_VAULTS}), and\n * {@link chainflipVerifyQuote} — the app's pins for `remoteProvider({name: \"chainflip\", baseUrl, ...chainflipPins})`\n * (scan 2026-10-27 modules, F8/F16). A Tron vault swap is a send to the Tron Vault the verifier pins, so the stub is\n * opened to that deposit route (`depositAddressRoutes`, scan 2026-10-28 F9); its note must ride as hex bytes. `reasonOf`\n * classifies each text the verifiers return (`Swap2RefusalReason`), so a remote stub's refusal carries it.\n */\nexport const chainflipPins: RemotePins = Object.freeze({\n callTargets: (chain: string): readonly string[] => chainflipVaultFor(chain),\n spenders: (chain: string): readonly string[] => chainflipVaultFor(chain),\n verifyQuote: chainflipVerifyQuote,\n verifyBuild: (quote: Quote, tx: UnsignedTx): string | null =>\n quote.depositMemo && tx.memoEncoding !== \"hex\" ? notes.note(\"the Tron note is not sent as hex bytes\", \"policy_refused\") : null,\n reasonOf,\n depositAddressRoutes: true,\n});\nfunction chainflipVaultFor(chain: string): readonly string[] {\n const vault = chain.startsWith(\"eip155:\") && Object.prototype.hasOwnProperty.call(CF_VAULTS, chain) ? CF_VAULTS[chain] : undefined;\n return vault ? [vault] : [];\n}\n"],"mappings":"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","names":[]}