@vultisig/core-chain 2.26.0 → 2.27.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (115) hide show
  1. package/CHANGELOG.md +83 -0
  2. package/dist/chains/cosmos/account/getCosmosAccountInfo.d.ts +1 -0
  3. package/dist/chains/cosmos/account/getCosmosAccountInfo.d.ts.map +1 -1
  4. package/dist/chains/cosmos/account/getCosmosAccountInfo.js +112 -30
  5. package/dist/chains/cosmos/account/getCosmosAccountInfo.js.map +1 -1
  6. package/dist/chains/cosmos/parseUint64.d.ts +6 -0
  7. package/dist/chains/cosmos/parseUint64.d.ts.map +1 -0
  8. package/dist/chains/cosmos/parseUint64.js +12 -0
  9. package/dist/chains/cosmos/parseUint64.js.map +1 -0
  10. package/dist/chains/cosmos/qbtc/claim/broadcastClaimTx.d.ts.map +1 -1
  11. package/dist/chains/cosmos/qbtc/claim/broadcastClaimTx.js +3 -28
  12. package/dist/chains/cosmos/qbtc/claim/broadcastClaimTx.js.map +1 -1
  13. package/dist/chains/cosmos/qbtc/getQbtcAccountInfo.d.ts.map +1 -1
  14. package/dist/chains/cosmos/qbtc/getQbtcAccountInfo.js +11 -13
  15. package/dist/chains/cosmos/qbtc/getQbtcAccountInfo.js.map +1 -1
  16. package/dist/chains/cosmos/qbtc/waitForQbtcTxInclusion.d.ts +32 -0
  17. package/dist/chains/cosmos/qbtc/waitForQbtcTxInclusion.d.ts.map +1 -0
  18. package/dist/chains/cosmos/qbtc/waitForQbtcTxInclusion.js +33 -0
  19. package/dist/chains/cosmos/qbtc/waitForQbtcTxInclusion.js.map +1 -0
  20. package/dist/coin/balance/getEvmChainBalances.d.ts +6 -0
  21. package/dist/coin/balance/getEvmChainBalances.d.ts.map +1 -1
  22. package/dist/coin/balance/getEvmChainBalances.js +11 -5
  23. package/dist/coin/balance/getEvmChainBalances.js.map +1 -1
  24. package/dist/coin/price/resolveTokenPriceId.d.ts +8 -10
  25. package/dist/coin/price/resolveTokenPriceId.d.ts.map +1 -1
  26. package/dist/coin/price/resolveTokenPriceId.js +21 -14
  27. package/dist/coin/price/resolveTokenPriceId.js.map +1 -1
  28. package/dist/swap/general/GeneralSwapQuote.d.ts +19 -3
  29. package/dist/swap/general/GeneralSwapQuote.d.ts.map +1 -1
  30. package/dist/swap/general/cowswap/sign/buildCowSwapOrderTypedData.d.ts +0 -9
  31. package/dist/swap/general/cowswap/sign/buildCowSwapOrderTypedData.d.ts.map +1 -1
  32. package/dist/swap/general/cowswap/sign/buildCowSwapOrderTypedData.js +52 -22
  33. package/dist/swap/general/cowswap/sign/buildCowSwapOrderTypedData.js.map +1 -1
  34. package/dist/swap/general/knownAggregatorRouters.d.ts +59 -2
  35. package/dist/swap/general/knownAggregatorRouters.d.ts.map +1 -1
  36. package/dist/swap/general/knownAggregatorRouters.js +118 -12
  37. package/dist/swap/general/knownAggregatorRouters.js.map +1 -1
  38. package/dist/swap/general/kyber/chains.d.ts +1 -1
  39. package/dist/swap/general/kyber/chains.d.ts.map +1 -1
  40. package/dist/swap/general/kyber/chains.js +5 -2
  41. package/dist/swap/general/kyber/chains.js.map +1 -1
  42. package/dist/swap/general/lifi/api/getLifiSwapQuote.d.ts +2 -9
  43. package/dist/swap/general/lifi/api/getLifiSwapQuote.d.ts.map +1 -1
  44. package/dist/swap/general/lifi/api/getLifiSwapQuote.js +29 -81
  45. package/dist/swap/general/lifi/api/getLifiSwapQuote.js.map +1 -1
  46. package/dist/swap/general/lifi/api/lifiSlippage.d.ts +25 -0
  47. package/dist/swap/general/lifi/api/lifiSlippage.d.ts.map +1 -0
  48. package/dist/swap/general/lifi/api/lifiSlippage.js +51 -0
  49. package/dist/swap/general/lifi/api/lifiSlippage.js.map +1 -0
  50. package/dist/swap/general/oneInch/api/getOneInchSwapQuote.d.ts.map +1 -1
  51. package/dist/swap/general/oneInch/api/getOneInchSwapQuote.js +8 -0
  52. package/dist/swap/general/oneInch/api/getOneInchSwapQuote.js.map +1 -1
  53. package/dist/swap/general/swapkit/api/getSwapKitQuote.d.ts.map +1 -1
  54. package/dist/swap/general/swapkit/api/getSwapKitQuote.js +23 -2
  55. package/dist/swap/general/swapkit/api/getSwapKitQuote.js.map +1 -1
  56. package/dist/swap/general/swapkit/getSwapKitTrackerUrl.d.ts +43 -0
  57. package/dist/swap/general/swapkit/getSwapKitTrackerUrl.d.ts.map +1 -0
  58. package/dist/swap/general/swapkit/getSwapKitTrackerUrl.js +47 -0
  59. package/dist/swap/general/swapkit/getSwapKitTrackerUrl.js.map +1 -0
  60. package/dist/swap/native/NativeSwapChain.d.ts +2 -0
  61. package/dist/swap/native/NativeSwapChain.d.ts.map +1 -1
  62. package/dist/swap/native/NativeSwapChain.js +1 -0
  63. package/dist/swap/native/NativeSwapChain.js.map +1 -1
  64. package/dist/swap/native/halts/getNativeSwapTradingHalt.d.ts.map +1 -1
  65. package/dist/swap/native/halts/getNativeSwapTradingHalt.js +2 -2
  66. package/dist/swap/native/halts/getNativeSwapTradingHalt.js.map +1 -1
  67. package/dist/swap/native/limitSwapMemo.d.ts.map +1 -1
  68. package/dist/swap/native/limitSwapMemo.js +1 -24
  69. package/dist/swap/native/limitSwapMemo.js.map +1 -1
  70. package/dist/swap/native/minimum/getNativeSwapMinAmountIn.d.ts.map +1 -1
  71. package/dist/swap/native/minimum/getNativeSwapMinAmountIn.js +9 -3
  72. package/dist/swap/native/minimum/getNativeSwapMinAmountIn.js.map +1 -1
  73. package/dist/swap/native/thorchainMemoAsset.d.ts +76 -0
  74. package/dist/swap/native/thorchainMemoAsset.d.ts.map +1 -0
  75. package/dist/swap/native/thorchainMemoAsset.js +126 -0
  76. package/dist/swap/native/thorchainMemoAsset.js.map +1 -0
  77. package/dist/swap/quote/findSwapQuote.d.ts.map +1 -1
  78. package/dist/swap/quote/findSwapQuote.js +6 -1
  79. package/dist/swap/quote/findSwapQuote.js.map +1 -1
  80. package/dist/swap/swapEnabledChains.d.ts.map +1 -1
  81. package/dist/swap/swapEnabledChains.js +12 -0
  82. package/dist/swap/swapEnabledChains.js.map +1 -1
  83. package/dist/swap/utils/getSwapExplorerUrl/index.d.ts +10 -7
  84. package/dist/swap/utils/getSwapExplorerUrl/index.d.ts.map +1 -1
  85. package/dist/swap/utils/getSwapExplorerUrl/index.js +13 -12
  86. package/dist/swap/utils/getSwapExplorerUrl/index.js.map +1 -1
  87. package/dist/tx/broadcast/resolvers/bittensor.d.ts.map +1 -1
  88. package/dist/tx/broadcast/resolvers/bittensor.js +21 -15
  89. package/dist/tx/broadcast/resolvers/bittensor.js.map +1 -1
  90. package/dist/tx/broadcast/resolvers/cosmos.d.ts +1 -0
  91. package/dist/tx/broadcast/resolvers/cosmos.d.ts.map +1 -1
  92. package/dist/tx/broadcast/resolvers/cosmos.js +30 -2
  93. package/dist/tx/broadcast/resolvers/cosmos.js.map +1 -1
  94. package/dist/tx/broadcast/resolvers/polkadot.d.ts.map +1 -1
  95. package/dist/tx/broadcast/resolvers/polkadot.js +3 -36
  96. package/dist/tx/broadcast/resolvers/polkadot.js.map +1 -1
  97. package/dist/tx/broadcast/resolvers/qbtc.d.ts.map +1 -1
  98. package/dist/tx/broadcast/resolvers/qbtc.js +37 -7
  99. package/dist/tx/broadcast/resolvers/qbtc.js.map +1 -1
  100. package/dist/tx/broadcast/resolvers/substrate.d.ts +8 -0
  101. package/dist/tx/broadcast/resolvers/substrate.d.ts.map +1 -0
  102. package/dist/tx/broadcast/resolvers/substrate.js +15 -0
  103. package/dist/tx/broadcast/resolvers/substrate.js.map +1 -0
  104. package/dist/tx/broadcast/resolvers/sui.d.ts +8 -0
  105. package/dist/tx/broadcast/resolvers/sui.d.ts.map +1 -1
  106. package/dist/tx/broadcast/resolvers/sui.js +33 -7
  107. package/dist/tx/broadcast/resolvers/sui.js.map +1 -1
  108. package/dist/tx/broadcast/transientRetry.d.ts +17 -0
  109. package/dist/tx/broadcast/transientRetry.d.ts.map +1 -1
  110. package/dist/tx/broadcast/transientRetry.js +23 -0
  111. package/dist/tx/broadcast/transientRetry.js.map +1 -1
  112. package/dist/tx/status/resolvers/cardano.d.ts.map +1 -1
  113. package/dist/tx/status/resolvers/cardano.js +19 -3
  114. package/dist/tx/status/resolvers/cardano.js.map +1 -1
  115. package/package.json +32 -2
@@ -11,10 +11,11 @@ const getFallbackBalances = async ({ chain, address, coins }) => {
11
11
  return [accountCoinKeyToString(input), await getEvmCoinBalance(input)];
12
12
  }
13
13
  catch {
14
- return [accountCoinKeyToString(input), 0n];
14
+ // OMIT the key rather than reporting 0n: the read failed, so the balance is unknown.
15
+ return undefined;
15
16
  }
16
17
  }));
17
- return Object.fromEntries(entries);
18
+ return Object.fromEntries(entries.filter(entry => entry !== undefined));
18
19
  };
19
20
  export const getEvmChainBalances = async (input) => {
20
21
  const { chain, address, coins } = input;
@@ -48,10 +49,15 @@ export const getEvmChainBalances = async (input) => {
48
49
  if (!results) {
49
50
  return getFallbackBalances(input);
50
51
  }
51
- return Object.fromEntries(coins.map((coin, index) => {
52
+ return Object.fromEntries(coins.flatMap((coin, index) => {
52
53
  const result = results[index];
53
- const amount = result?.status === 'success' ? BigInt(result.result) : 0n;
54
- return [accountCoinKeyToString({ ...coin, chain, address }), amount];
54
+ // A reverted / failed sub-call (allowFailure keeps it in the array as status 'failure') carries
55
+ // NO balance. Omit it instead of decoding it as 0n, so the caller can tell an unread coin from a
56
+ // genuinely empty one and refetch it rather than caching a fabricated zero.
57
+ if (result?.status !== 'success') {
58
+ return [];
59
+ }
60
+ return [[accountCoinKeyToString({ ...coin, chain, address }), BigInt(result.result)]];
55
61
  }));
56
62
  };
57
63
  //# sourceMappingURL=getEvmChainBalances.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"getEvmChainBalances.js","sourceRoot":"","sources":["../../../../../../packages/core/chain/coin/balance/getEvmChainBalances.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"getEvmChainBalances.js","sourceRoot":"","sources":["../../../../../../packages/core/chain/coin/balance/getEvmChainBalances.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,wCAAwC,CAAA;AACrE,OAAO,EAAkB,sBAAsB,EAAE,MAAM,uCAAuC,CAAA;AAC9F,OAAO,EAAE,SAAS,EAAE,MAAM,2CAA2C,CAAA;AACrE,OAAO,EAAW,QAAQ,EAAE,QAAQ,EAAE,MAAM,MAAM,CAAA;AAElD,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAA;AAEnD,MAAM,aAAa,GAAG,QAAQ,CAAC,CAAC,6DAA6D,CAAC,CAAC,CAAA;AAgB/F,MAAM,mBAAmB,GAAG,KAAK,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAA4B,EAA6B,EAAE;IACnH,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,CAC/B,KAAK,CAAC,GAAG,CAAC,KAAK,EAAC,IAAI,EAAC,EAAE;QACrB,MAAM,KAAK,GAAG,EAAE,GAAG,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,CAAA;QAEzC,IAAI,CAAC;YACH,OAAO,CAAC,sBAAsB,CAAC,KAAK,CAAC,EAAE,MAAM,iBAAiB,CAAC,KAAK,CAAC,CAAU,CAAA;QACjF,CAAC;QAAC,MAAM,CAAC;YACP,qFAAqF;YACrF,OAAO,SAAS,CAAA;QAClB,CAAC;IACH,CAAC,CAAC,CACH,CAAA;IAED,OAAO,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAA;AACzE,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,mBAAmB,GAAG,KAAK,EAAE,KAA+B,EAA6B,EAAE;IACtG,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,KAAK,CAAA;IAEvC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,OAAO,EAAE,CAAA;IACX,CAAC;IAED,MAAM,YAAY,GAAG,YAAY,CAAC,KAAK,CAAC,CAAA;IACxC,MAAM,iBAAiB,GAAG,YAAY,CAAC,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,OAAO,CAAA;IAE5E,IAAI,CAAC,iBAAiB,EAAE,CAAC;QACvB,OAAO,mBAAmB,CAAC,KAAK,CAAC,CAAA;IACnC,CAAC;IAED,MAAM,SAAS,GAAG,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CACjC,SAAS,CAAC,IAAI,CAAC;QACb,CAAC,CAAC;YACE,OAAO,EAAE,iBAAiB;YAC1B,GAAG,EAAE,aAAa;YAClB,YAAY,EAAE,eAAe;YAC7B,IAAI,EAAE,CAAC,OAAO,CAAC;SAChB;QACH,CAAC,CAAC;YACE,OAAO,EAAE,IAAI,CAAC,EAAa;YAC3B,GAAG,EAAE,QAAQ;YACb,YAAY,EAAE,WAAW;YACzB,IAAI,EAAE,CAAC,OAAO,CAAC;SAChB,CACN,CAAA;IAED,MAAM,OAAO,GAAG,MAAM,YAAY;SAC/B,SAAS,CAAC;QACT,YAAY,EAAE,IAAI;QAClB,SAAS;KACV,CAAC;SACD,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAA;IAEzB,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,mBAAmB,CAAC,KAAK,CAAC,CAAA;IACnC,CAAC;IAED,OAAO,MAAM,CAAC,WAAW,CACvB,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE;QAC5B,MAAM,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,CAAA;QAE7B,gGAAgG;QAChG,iGAAiG;QACjG,4EAA4E;QAC5E,IAAI,MAAM,EAAE,MAAM,KAAK,SAAS,EAAE,CAAC;YACjC,OAAO,EAAE,CAAA;QACX,CAAC;QAED,OAAO,CAAC,CAAC,sBAAsB,CAAC,EAAE,GAAG,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,EAAE,MAAM,CAAC,MAAM,CAAC,MAAgB,CAAC,CAAU,CAAC,CAAA;IAC1G,CAAC,CAAC,CACH,CAAA;AACH,CAAC,CAAA"}
@@ -6,17 +6,15 @@ import type { Chain } from '../../Chain.js';
6
6
  * - When `denomOrAddress` is omitted, empty, or whitespace-only, returns the
7
7
  * native chain coin's priceProviderId from chainFeeCoin (e.g.
8
8
  * resolveTokenPriceId('Ethereum') -> 'ethereum').
9
- * - When `denomOrAddress` is provided, it is trimmed and lowercased, then
10
- * looked up in knownTokensIndex[chain]. The lookup is case-insensitive (the
11
- * index stores all keys lowercased) and tolerant of incidental surrounding
12
- * whitespace from upstream string sources. Note: lowercasing is locale-
13
- * independent (String.prototype.toLowerCase, not toLocaleLowerCase) and the
14
- * index keys are built with the same call, so the build/lookup casing is
15
- * always symmetric.
9
+ * - When `denomOrAddress` is provided, incidental surrounding whitespace is
10
+ * trimmed. EVM contract addresses are matched case-insensitively; identifiers
11
+ * for every other chain are matched exactly because Solana mints, Cosmos
12
+ * denoms, TON jettons, and other non-EVM identifiers may be case-sensitive.
16
13
  *
17
- * Returns `undefined` if no registry entry exists never guesses or
18
- * fabricates an id. The caller decides whether to fall back to CoinGecko
19
- * search, DeFiLlama, or surface a `price_unavailable` to the user.
14
+ * The native Cosmos fee denom is also resolved to its chain fee coin's
15
+ * priceProviderId. Other unknown identifiers return `undefined` the caller
16
+ * decides whether to fall back to CoinGecko search, DeFiLlama, or surface a
17
+ * `price_unavailable` to the user.
20
18
  *
21
19
  * Referenced by vultisig/mcp-ts#255 — registry-driven price resolution.
22
20
  */
@@ -1 +1 @@
1
- {"version":3,"file":"resolveTokenPriceId.d.ts","sourceRoot":"","sources":["../../../../../../packages/core/chain/coin/price/resolveTokenPriceId.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;AAIxC;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,KAAK,EAAE,cAAc,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAM7F"}
1
+ {"version":3,"file":"resolveTokenPriceId.d.ts","sourceRoot":"","sources":["../../../../../../packages/core/chain/coin/price/resolveTokenPriceId.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;AAMxC;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,KAAK,EAAE,cAAc,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAe7F"}
@@ -1,5 +1,7 @@
1
+ import { getChainKind } from '../../ChainKind.js';
2
+ import { cosmosFeeCoinDenom } from '../../chains/cosmos/cosmosFeeCoinDenom.js';
1
3
  import { chainFeeCoin } from '../chainFeeCoin.js';
2
- import { knownTokensIndex } from '../knownTokens/index.js';
4
+ import { knownTokens, knownTokensIndex } from '../knownTokens/index.js';
3
5
  /**
4
6
  * Resolve a token's CoinGecko price-provider id from the SDK's curated
5
7
  * registry. Pure synchronous lookup, no I/O.
@@ -7,25 +9,30 @@ import { knownTokensIndex } from '../knownTokens/index.js';
7
9
  * - When `denomOrAddress` is omitted, empty, or whitespace-only, returns the
8
10
  * native chain coin's priceProviderId from chainFeeCoin (e.g.
9
11
  * resolveTokenPriceId('Ethereum') -> 'ethereum').
10
- * - When `denomOrAddress` is provided, it is trimmed and lowercased, then
11
- * looked up in knownTokensIndex[chain]. The lookup is case-insensitive (the
12
- * index stores all keys lowercased) and tolerant of incidental surrounding
13
- * whitespace from upstream string sources. Note: lowercasing is locale-
14
- * independent (String.prototype.toLowerCase, not toLocaleLowerCase) and the
15
- * index keys are built with the same call, so the build/lookup casing is
16
- * always symmetric.
12
+ * - When `denomOrAddress` is provided, incidental surrounding whitespace is
13
+ * trimmed. EVM contract addresses are matched case-insensitively; identifiers
14
+ * for every other chain are matched exactly because Solana mints, Cosmos
15
+ * denoms, TON jettons, and other non-EVM identifiers may be case-sensitive.
17
16
  *
18
- * Returns `undefined` if no registry entry exists never guesses or
19
- * fabricates an id. The caller decides whether to fall back to CoinGecko
20
- * search, DeFiLlama, or surface a `price_unavailable` to the user.
17
+ * The native Cosmos fee denom is also resolved to its chain fee coin's
18
+ * priceProviderId. Other unknown identifiers return `undefined` the caller
19
+ * decides whether to fall back to CoinGecko search, DeFiLlama, or surface a
20
+ * `price_unavailable` to the user.
21
21
  *
22
22
  * Referenced by vultisig/mcp-ts#255 — registry-driven price resolution.
23
23
  */
24
24
  export function resolveTokenPriceId(chain, denomOrAddress) {
25
- const normalized = denomOrAddress?.trim().toLowerCase();
26
- if (!normalized) {
25
+ const identifier = denomOrAddress?.trim();
26
+ if (!identifier) {
27
27
  return chainFeeCoin[chain]?.priceProviderId || undefined;
28
28
  }
29
- return knownTokensIndex[chain]?.[normalized]?.priceProviderId || undefined;
29
+ const knownPriceProviderId = getChainKind(chain) === 'evm'
30
+ ? knownTokensIndex[chain]?.[identifier.toLowerCase()]?.priceProviderId
31
+ : knownTokens[chain]?.find(coin => coin.id === identifier)?.priceProviderId;
32
+ if (knownPriceProviderId)
33
+ return knownPriceProviderId;
34
+ return cosmosFeeCoinDenom[chain] === identifier
35
+ ? chainFeeCoin[chain]?.priceProviderId || undefined
36
+ : undefined;
30
37
  }
31
38
  //# sourceMappingURL=resolveTokenPriceId.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"resolveTokenPriceId.js","sourceRoot":"","sources":["../../../../../../packages/core/chain/coin/price/resolveTokenPriceId.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AAC9C,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAA;AAEjD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,UAAU,mBAAmB,CAAC,KAAY,EAAE,cAAuB;IACvE,MAAM,UAAU,GAAG,cAAc,EAAE,IAAI,EAAE,CAAC,WAAW,EAAE,CAAA;IACvD,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,OAAO,YAAY,CAAC,KAAK,CAAC,EAAE,eAAe,IAAI,SAAS,CAAA;IAC1D,CAAC;IACD,OAAO,gBAAgB,CAAC,KAAK,CAAC,EAAE,CAAC,UAAU,CAAC,EAAE,eAAe,IAAI,SAAS,CAAA;AAC5E,CAAC"}
1
+ {"version":3,"file":"resolveTokenPriceId.js","sourceRoot":"","sources":["../../../../../../packages/core/chain/coin/price/resolveTokenPriceId.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AAC9C,OAAO,EAAE,kBAAkB,EAAE,MAAM,wCAAwC,CAAA;AAC3E,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AAC9C,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAA;AAE9D;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,UAAU,mBAAmB,CAAC,KAAY,EAAE,cAAuB;IACvE,MAAM,UAAU,GAAG,cAAc,EAAE,IAAI,EAAE,CAAA;IACzC,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,OAAO,YAAY,CAAC,KAAK,CAAC,EAAE,eAAe,IAAI,SAAS,CAAA;IAC1D,CAAC;IAED,MAAM,oBAAoB,GACxB,YAAY,CAAC,KAAK,CAAC,KAAK,KAAK;QAC3B,CAAC,CAAC,gBAAgB,CAAC,KAAK,CAAC,EAAE,CAAC,UAAU,CAAC,WAAW,EAAE,CAAC,EAAE,eAAe;QACtE,CAAC,CAAC,WAAW,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,KAAK,UAAU,CAAC,EAAE,eAAe,CAAA;IAC/E,IAAI,oBAAoB;QAAE,OAAO,oBAAoB,CAAA;IAErD,OAAO,kBAAkB,CAAC,KAAwC,CAAC,KAAK,UAAU;QAChF,CAAC,CAAC,YAAY,CAAC,KAAK,CAAC,EAAE,eAAe,IAAI,SAAS;QACnD,CAAC,CAAC,SAAS,CAAA;AACf,CAAC"}
@@ -10,6 +10,22 @@ export type GeneralSwapTx = {
10
10
  value: string;
11
11
  gasLimit?: bigint;
12
12
  affiliateFee?: SwapFee;
13
+ /**
14
+ * The address that will be called as `transferFrom` spender for the
15
+ * input ERC-20 token. Set by LI.FI quotes from `estimate.approvalAddress`
16
+ * when it differs from `to` (e.g. when 1inch or another inner executor
17
+ * does the token pull directly instead of the Diamond/router).
18
+ *
19
+ * On-chain proof of the gap: tx 0xa3aadf17 (Ethereum, block 25415989)
20
+ * reverted with "ERC20: transfer amount exceeds allowance" because the
21
+ * vault had 9.41 USDC approved to the Diamond (`to` = 0x9025B8ff…) but
22
+ * zero allowance to the 1inch executor (`approvalAddress`). The Diamond
23
+ * being approved is not sufficient when an inner executor does the pull.
24
+ *
25
+ * Consumers building an ERC-20 approve leg MUST use this field as the
26
+ * spender when present, falling back to `to` only when absent.
27
+ */
28
+ approvalAddress?: string;
13
29
  };
14
30
  } | {
15
31
  solana: {
@@ -56,9 +72,9 @@ export type GeneralSwapTx = {
56
72
  * Consumers building a "View on Explorer" link should call
57
73
  * `getSwapExplorerUrl({ provider, txHash, fromChain })` from
58
74
  * `@vultisig/core-chain/swap/utils/getSwapExplorerUrl` instead of routing
59
- * by hand — the helper covers the LI.FI / Helius scanners and falls back to
60
- * the source-chain explorer for `1inch` / `jupiter` / `kyber` / `swapkit` (none of which
61
- * expose a per-tx aggregator page).
75
+ * by hand — the helper covers LI.FI / Helius and SwapKit scanners, accepts the
76
+ * provider-specific CoW order UID for pending CowSwap orders, and falls back to
77
+ * the source-chain explorer for `1inch` / `jupiter` / `kyber`.
62
78
  */
63
79
  export type GeneralSwapQuote = {
64
80
  dstAmount: string;
@@ -1 +1 @@
1
- {"version":3,"file":"GeneralSwapQuote.d.ts","sourceRoot":"","sources":["../../../../../../packages/core/chain/swap/general/GeneralSwapQuote.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,mCAAmC,CAAA;AAE3D,OAAO,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAA;AACtE,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;AAClD,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAA;AAE3D,MAAM,MAAM,aAAa,GACrB;IACE,GAAG,EAAE;QACH,IAAI,EAAE,MAAM,CAAA;QACZ,EAAE,EAAE,MAAM,CAAA;QACV,IAAI,EAAE,MAAM,CAAA;QACZ,KAAK,EAAE,MAAM,CAAA;QACb,QAAQ,CAAC,EAAE,MAAM,CAAA;QACjB,YAAY,CAAC,EAAE,OAAO,CAAA;KACvB,CAAA;CACF,GACD;IACE,MAAM,EAAE;QACN,IAAI,EAAE,MAAM,CAAA;QACZ,UAAU,EAAE,MAAM,CAAA;QAClB,OAAO,EAAE,OAAO,CAAA;KACjB,CAAA;CACF,GACD;IACE,QAAQ,EAAE;QACR,EAAE,EAAE,MAAM,CAAA;QACV,MAAM,EAAE,MAAM,CAAA;QACd,IAAI,CAAC,EAAE,MAAM,CAAA;QACb,MAAM,CAAC,EAAE,MAAM,CAAA;QACf,SAAS,CAAC,EAAE,UAAU,CAAA;QACtB,cAAc,CAAC,EAAE,MAAM,CAAA;QACvB,MAAM,CAAC,EAAE,MAAM,CAAA;KAChB,CAAA;CACF,GACD;IACE,aAAa,EAAE;QACb,SAAS,EAAE,MAAM,CAAA;QACjB,QAAQ,EAAE,MAAM,CAAA;QAChB,QAAQ,EAAE,MAAM,CAAA;QAChB,UAAU,EAAE,MAAM,CAAA;QAClB,SAAS,EAAE,MAAM,CAAA;QACjB,OAAO,EAAE,MAAM,CAAA;QACf,OAAO,EAAE,MAAM,CAAA;QACf,WAAW,EAAE,MAAM,CAAA;QACnB,SAAS,EAAE,MAAM,CAAA;QACjB,IAAI,EAAE,gBAAgB,CAAA;QACtB,iBAAiB,EAAE,OAAO,CAAA;QAC1B,gBAAgB,EAAE,mBAAmB,CAAA;QACrC,eAAe,EAAE,mBAAmB,CAAA;QACpC,OAAO,EAAE,MAAM,CAAA;QACf,OAAO,EAAE,MAAM,CAAA;QACf;;kFAE0E;QAC1E,cAAc,CAAC,EAAE,IAAI,CAAA;KACtB,CAAA;CACF,CAAA;AAEL;;;;;;;;;GASG;AACH,MAAM,MAAM,gBAAgB,GAAG;IAC7B,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,EAAE,mBAAmB,CAAA;IAC7B,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,EAAE,EAAE,aAAa,CAAA;CAClB,CAAA"}
1
+ {"version":3,"file":"GeneralSwapQuote.d.ts","sourceRoot":"","sources":["../../../../../../packages/core/chain/swap/general/GeneralSwapQuote.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,mCAAmC,CAAA;AAE3D,OAAO,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAA;AACtE,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;AAClD,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAA;AAE3D,MAAM,MAAM,aAAa,GACrB;IACE,GAAG,EAAE;QACH,IAAI,EAAE,MAAM,CAAA;QACZ,EAAE,EAAE,MAAM,CAAA;QACV,IAAI,EAAE,MAAM,CAAA;QACZ,KAAK,EAAE,MAAM,CAAA;QACb,QAAQ,CAAC,EAAE,MAAM,CAAA;QACjB,YAAY,CAAC,EAAE,OAAO,CAAA;QACtB;;;;;;;;;;;;;;WAcG;QACH,eAAe,CAAC,EAAE,MAAM,CAAA;KACzB,CAAA;CACF,GACD;IACE,MAAM,EAAE;QACN,IAAI,EAAE,MAAM,CAAA;QACZ,UAAU,EAAE,MAAM,CAAA;QAClB,OAAO,EAAE,OAAO,CAAA;KACjB,CAAA;CACF,GACD;IACE,QAAQ,EAAE;QACR,EAAE,EAAE,MAAM,CAAA;QACV,MAAM,EAAE,MAAM,CAAA;QACd,IAAI,CAAC,EAAE,MAAM,CAAA;QACb,MAAM,CAAC,EAAE,MAAM,CAAA;QACf,SAAS,CAAC,EAAE,UAAU,CAAA;QACtB,cAAc,CAAC,EAAE,MAAM,CAAA;QACvB,MAAM,CAAC,EAAE,MAAM,CAAA;KAChB,CAAA;CACF,GACD;IACE,aAAa,EAAE;QACb,SAAS,EAAE,MAAM,CAAA;QACjB,QAAQ,EAAE,MAAM,CAAA;QAChB,QAAQ,EAAE,MAAM,CAAA;QAChB,UAAU,EAAE,MAAM,CAAA;QAClB,SAAS,EAAE,MAAM,CAAA;QACjB,OAAO,EAAE,MAAM,CAAA;QACf,OAAO,EAAE,MAAM,CAAA;QACf,WAAW,EAAE,MAAM,CAAA;QACnB,SAAS,EAAE,MAAM,CAAA;QACjB,IAAI,EAAE,gBAAgB,CAAA;QACtB,iBAAiB,EAAE,OAAO,CAAA;QAC1B,gBAAgB,EAAE,mBAAmB,CAAA;QACrC,eAAe,EAAE,mBAAmB,CAAA;QACpC,OAAO,EAAE,MAAM,CAAA;QACf,OAAO,EAAE,MAAM,CAAA;QACf;;kFAE0E;QAC1E,cAAc,CAAC,EAAE,IAAI,CAAA;KACtB,CAAA;CACF,CAAA;AAEL;;;;;;;;;GASG;AACH,MAAM,MAAM,gBAAgB,GAAG;IAC7B,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,EAAE,mBAAmB,CAAA;IAC7B,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,EAAE,EAAE,aAAa,CAAA;CAClB,CAAA"}
@@ -98,15 +98,6 @@ type BuildCowSwapOrderTypedDataInput = {
98
98
  order: CowSwapOrder;
99
99
  chainId: number;
100
100
  };
101
- /**
102
- * Build the `eth_signTypedData_v4` document for a CowSwap order.
103
- *
104
- * The resulting digest (EIP-712 hash of this document) is what the MPC ceremony
105
- * signs; the 65-byte `r||s||v` signature is submitted to the orderbook alongside
106
- * the order via `submitCowSwapOrder`. The order's `appDataHash` becomes the
107
- * signed `appData` field — the orderbook verifies it matches the `appData`
108
- * string in the submitted order.
109
- */
110
101
  export declare const buildCowSwapOrderTypedData: ({ order, chainId, }: BuildCowSwapOrderTypedDataInput) => CowSwapOrderTypedData;
111
102
  export {};
112
103
  //# sourceMappingURL=buildCowSwapOrderTypedData.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"buildCowSwapOrderTypedData.d.ts","sourceRoot":"","sources":["../../../../../../../../packages/core/chain/swap/general/cowswap/sign/buildCowSwapOrderTypedData.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AAClD,OAAO,EAAqB,YAAY,EAAE,MAAM,qBAAqB,CAAA;AAErE;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAa3B,CAAA;AAEV,QAAA,MAAM,kBAAkB;;;;;;;;;;;;EAKd,CAAA;AAEV;;yDAEyD;AACzD,MAAM,MAAM,yBAAyB,GAAG;IACtC,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,MAAM,CAAA;IAChB,UAAU,EAAE,MAAM,CAAA;IAClB,SAAS,EAAE,MAAM,CAAA;IACjB,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,MAAM,CAAA;IACf,SAAS,EAAE,MAAM,CAAA;IACjB,IAAI,EAAE,MAAM,CAAA;IACZ,iBAAiB,EAAE,OAAO,CAAA;IAC1B,gBAAgB,EAAE,MAAM,CAAA;IACxB,eAAe,EAAE,MAAM,CAAA;CACxB,CAAA;AAED;;;gEAGgE;AAChE,MAAM,MAAM,qBAAqB,GAAG;IAClC,WAAW,EAAE,OAAO,CAAA;IACpB,MAAM,EAAE,YAAY,CAAA;IACpB,KAAK,EAAE;QACL,YAAY,EAAE,OAAO,kBAAkB,CAAA;QACvC,KAAK,EAAE,OAAO,wBAAwB,CAAA;KACvC,CAAA;IACD,OAAO,EAAE,yBAAyB,CAAA;CACnC,CAAA;AAED,KAAK,+BAA+B,GAAG;IACrC,KAAK,EAAE,YAAY,CAAA;IACnB,OAAO,EAAE,MAAM,CAAA;CAChB,CAAA;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,0BAA0B,GAAI,qBAGxC,+BAA+B,KAAG,qBAqBnC,CAAA"}
1
+ {"version":3,"file":"buildCowSwapOrderTypedData.d.ts","sourceRoot":"","sources":["../../../../../../../../packages/core/chain/swap/general/cowswap/sign/buildCowSwapOrderTypedData.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AAClD,OAAO,EAAqB,YAAY,EAAE,MAAM,qBAAqB,CAAA;AAErE;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAa3B,CAAA;AAEV,QAAA,MAAM,kBAAkB;;;;;;;;;;;;EAKd,CAAA;AAEV;;yDAEyD;AACzD,MAAM,MAAM,yBAAyB,GAAG;IACtC,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,MAAM,CAAA;IAChB,UAAU,EAAE,MAAM,CAAA;IAClB,SAAS,EAAE,MAAM,CAAA;IACjB,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,MAAM,CAAA;IACf,SAAS,EAAE,MAAM,CAAA;IACjB,IAAI,EAAE,MAAM,CAAA;IACZ,iBAAiB,EAAE,OAAO,CAAA;IAC1B,gBAAgB,EAAE,MAAM,CAAA;IACxB,eAAe,EAAE,MAAM,CAAA;CACxB,CAAA;AAED;;;gEAGgE;AAChE,MAAM,MAAM,qBAAqB,GAAG;IAClC,WAAW,EAAE,OAAO,CAAA;IACpB,MAAM,EAAE,YAAY,CAAA;IACpB,KAAK,EAAE;QACL,YAAY,EAAE,OAAO,kBAAkB,CAAA;QACvC,KAAK,EAAE,OAAO,wBAAwB,CAAA;KACvC,CAAA;IACD,OAAO,EAAE,yBAAyB,CAAA;CACnC,CAAA;AAED,KAAK,+BAA+B,GAAG;IACrC,KAAK,EAAE,YAAY,CAAA;IACnB,OAAO,EAAE,MAAM,CAAA;CAChB,CAAA;AA4CD,eAAO,MAAM,0BAA0B,GAAI,qBAGxC,+BAA+B,KAAG,qBAyBpC,CAAA"}
@@ -42,26 +42,56 @@ const eip712DomainFields = [
42
42
  * signed `appData` field — the orderbook verifies it matches the `appData`
43
43
  * string in the submitted order.
44
44
  */
45
- export const buildCowSwapOrderTypedData = ({ order, chainId, }) => ({
46
- primaryType: 'Order',
47
- domain: buildEip712Domain(chainId),
48
- types: {
49
- EIP712Domain: eip712DomainFields,
50
- Order: cowSwapOrderEip712Fields,
51
- },
52
- message: {
53
- sellToken: order.sellToken,
54
- buyToken: order.buyToken,
55
- receiver: order.receiver,
56
- sellAmount: order.sellAmount,
57
- buyAmount: order.buyAmount,
58
- validTo: order.validTo,
59
- appData: order.appDataHash,
60
- feeAmount: order.feeAmount,
61
- kind: order.kind,
62
- partiallyFillable: order.partiallyFillable,
63
- sellTokenBalance: order.sellTokenBalance,
64
- buyTokenBalance: order.buyTokenBalance,
65
- },
66
- });
45
+ // Matches a checksummed or lowercase EVM address (case-insensitive 0x prefix, per findSwapQuote's
46
+ // isEvmAddress) — CowSwap is EVM-only, so the receiver is always an EVM address.
47
+ const isEvmAddress = (address) => /^0x[0-9a-fA-F]{40}$/i.test(address);
48
+ const ZERO_EVM_ADDRESS = '0x0000000000000000000000000000000000000000';
49
+ const BURN_EVM_ADDRESS = '0x000000000000000000000000000000000000dead';
50
+ /**
51
+ * Fund-safety re-check on the SIGNING side (sdk#1358 class). `assertValidCustomRecipient`
52
+ * (findSwapQuote.ts) rejects a zero/burn/malformed CowSwap receiver at QUOTE construction, but the
53
+ * MPC co-signer never sees the quote — it decodes a `cowswap-order:` blob from the KeysignPayload
54
+ * (decodeCowSwapKeysignData, which validates SHAPE only) and builds THIS EIP-712 digest to sign. A
55
+ * hand-built payload with `receiver = 0x…dead` (or the zero address, or a malformed address) would
56
+ * otherwise be signed into an unrecoverable order. This is the digest-construction choke point every
57
+ * signer funnels through, so guarding here binds the receiver the signature actually covers.
58
+ *
59
+ * vultisig always sets an explicit receiver (`normalizedRecipient ?? from.address`,
60
+ * findSwapQuote.ts) — never CowSwap's `address(0)` "pay-the-owner" sentinel — so rejecting zero here
61
+ * matches the quote-time guard and cannot false-block a legitimately-produced order.
62
+ */
63
+ const assertCowSwapReceiverSafe = (receiver) => {
64
+ if (!isEvmAddress(receiver)) {
65
+ throw new Error(`CowSwap order receiver "${receiver}" is not a valid EVM address — refusing to sign an order to a malformed recipient.`);
66
+ }
67
+ const lower = receiver.toLowerCase();
68
+ if (lower === ZERO_EVM_ADDRESS || lower === BURN_EVM_ADDRESS) {
69
+ throw new Error(`CowSwap order receiver "${receiver}" is a zero/burn address — the swap output would be unrecoverable; refusing to sign.`);
70
+ }
71
+ };
72
+ export const buildCowSwapOrderTypedData = ({ order, chainId, }) => {
73
+ assertCowSwapReceiverSafe(order.receiver);
74
+ return {
75
+ primaryType: 'Order',
76
+ domain: buildEip712Domain(chainId),
77
+ types: {
78
+ EIP712Domain: eip712DomainFields,
79
+ Order: cowSwapOrderEip712Fields,
80
+ },
81
+ message: {
82
+ sellToken: order.sellToken,
83
+ buyToken: order.buyToken,
84
+ receiver: order.receiver,
85
+ sellAmount: order.sellAmount,
86
+ buyAmount: order.buyAmount,
87
+ validTo: order.validTo,
88
+ appData: order.appDataHash,
89
+ feeAmount: order.feeAmount,
90
+ kind: order.kind,
91
+ partiallyFillable: order.partiallyFillable,
92
+ sellTokenBalance: order.sellTokenBalance,
93
+ buyTokenBalance: order.buyTokenBalance,
94
+ },
95
+ };
96
+ };
67
97
  //# sourceMappingURL=buildCowSwapOrderTypedData.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"buildCowSwapOrderTypedData.js","sourceRoot":"","sources":["../../../../../../../../packages/core/chain/swap/general/cowswap/sign/buildCowSwapOrderTypedData.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAgB,MAAM,qBAAqB,CAAA;AAErE;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG;IACtC,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,SAAS,EAAE;IACtC,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,SAAS,EAAE;IACrC,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,SAAS,EAAE;IACrC,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,SAAS,EAAE;IACvC,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,SAAS,EAAE;IACtC,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,QAAQ,EAAE;IACnC,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE;IACpC,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,SAAS,EAAE;IACtC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE;IAChC,EAAE,IAAI,EAAE,mBAAmB,EAAE,IAAI,EAAE,MAAM,EAAE;IAC3C,EAAE,IAAI,EAAE,kBAAkB,EAAE,IAAI,EAAE,QAAQ,EAAE;IAC5C,EAAE,IAAI,EAAE,iBAAiB,EAAE,IAAI,EAAE,QAAQ,EAAE;CACnC,CAAA;AAEV,MAAM,kBAAkB,GAAG;IACzB,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE;IAChC,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,QAAQ,EAAE;IACnC,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE;IACpC,EAAE,IAAI,EAAE,mBAAmB,EAAE,IAAI,EAAE,SAAS,EAAE;CACtC,CAAA;AAuCV;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAAG,CAAC,EACzC,KAAK,EACL,OAAO,GACyB,EAAyB,EAAE,CAAC,CAAC;IAC7D,WAAW,EAAE,OAAO;IACpB,MAAM,EAAE,iBAAiB,CAAC,OAAO,CAAC;IAClC,KAAK,EAAE;QACL,YAAY,EAAE,kBAAkB;QAChC,KAAK,EAAE,wBAAwB;KAChC;IACD,OAAO,EAAE;QACP,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,UAAU,EAAE,KAAK,CAAC,UAAU;QAC5B,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,OAAO,EAAE,KAAK,CAAC,WAAW;QAC1B,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,iBAAiB,EAAE,KAAK,CAAC,iBAAiB;QAC1C,gBAAgB,EAAE,KAAK,CAAC,gBAAgB;QACxC,eAAe,EAAE,KAAK,CAAC,eAAe;KACvC;CACF,CAAC,CAAA"}
1
+ {"version":3,"file":"buildCowSwapOrderTypedData.js","sourceRoot":"","sources":["../../../../../../../../packages/core/chain/swap/general/cowswap/sign/buildCowSwapOrderTypedData.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,62 @@
1
1
  import { Chain } from '../../Chain.js';
2
- export type EnforcedRouterProvider = '1inch' | 'kyber';
2
+ export type EnforcedRouterProvider = '1inch' | 'kyber' | 'cowswap';
3
+ /**
4
+ * Signing-path re-assert (sdk#1358): the same allow-list check as {@link assertKnownAggregatorRouter},
5
+ * but keyed off an arbitrary provider STRING (the value carried in KeysignSwapPayload.general.provider,
6
+ * which is a plain `string`). Enforced providers (1inch/kyber/cowswap) fail closed; the small closed set
7
+ * of genuinely unenforceable providers (li.fi/swapkit, plus the legacy `''` unattributed provider - see
8
+ * RECOGNIZED_UNENFORCED_PROVIDERS) fall through to the same log-only path they take at quote construction;
9
+ * anything else is rejected outright (sdk#1457, see below).
10
+ *
11
+ * WHY THIS EXISTS SEPARATELY FROM quote construction: a compromised initiator (or server composing the
12
+ * intent) can hand a co-signer a KeysignPayload whose swapPayload.quote.tx.to was NEVER run through the
13
+ * quote-time check - every co-signer independently rebuilds the signing input from that payload, so the
14
+ * guard has to run HERE too, on the signing-input path, or a co-signer (e.g. VultiServer in a 2-of-2)
15
+ * signs a destination it never validated. Mirrors the Ripple resolver's in-resolver fail-closed binding.
16
+ *
17
+ * THREAT MODEL / TRUST OF `provider` (CodeRabbit security review; sdk#1457): `provider` here is the free
18
+ * `provider` STRING on the OneInchSwapPayload proto (the `oneinchSwapPayload` oneof case carries
19
+ * 1inch/li.fi/cowswap/kyber with only this string to tell them apart; swapkit's dedicated transfer route
20
+ * is the one general provider that has its own oneof case - see getKeysignSwapPayload.ts). It is
21
+ * therefore part of the attacker-influenceable payload, NOT a trusted oneof discriminant, and a payload
22
+ * whose `provider` disagrees with its actual executing shape (an attacker relabeling to dodge
23
+ * enforcement) is a real, closable gap - not just a theoretical one.
24
+ *
25
+ * sdk#1457 FIX: two structural improvements that need no proto change. (1) CowSwap is now enforced -
26
+ * unlike li.fi/swapkit it settles through ONE fixed, deterministic contract (the GPv2VaultRelayer, see
27
+ * assertKnownAggregatorRouter), so its destination is exactly as allow-listable as 1inch/Kyber's; a
28
+ * payload can no longer relabel itself 'cowswap' to dodge a router check the way it previously could. (2)
29
+ * the log-only fallback is now a CLOSED list of the provider values the codebase legitimately produces
30
+ * (li.fi/swapkit, plus the legacy `''` unattributed provider) - a `provider` string outside every known
31
+ * value (enforced or unenforced) is unrecognized and REJECTED, not silently passed through. Together
32
+ * these shrink "relabel to escape enforcement" from "any string at all" down to exactly li.fi, swapkit,
33
+ * and the legacy `''`, which remain unenforceable by address because they legitimately route through
34
+ * many different contracts by design (see the file doc comment) - closing that residual gap needs the
35
+ * provider identity to be a trusted wire discriminant instead of a free string, i.e. a proto oneof case
36
+ * per provider (tracked in sdk#1457, not attempted here: a schema change on the shared commondata proto
37
+ * is a cross-repo, cross-consumer change every native client (iOS/Android/Windows) also builds against).
38
+ *
39
+ * This guard remains MONOTONIC beyond that residual gap: it only ever THROWS (rejects) or no-ops - it
40
+ * never makes anything signable that wasn't already.
41
+ */
42
+ export declare function assertKnownAggregatorRouterOnSigningPath(provider: string, address: string, chain: Chain): void;
43
+ /**
44
+ * Signing-path approval-spender bind (sdk#1358 review follow-up, requested by neavra). The
45
+ * follow-on to {@link assertKnownAggregatorRouterOnSigningPath}: that guard validates the swap-leg
46
+ * destination (`quote.tx.to`), but a general swap that needs an allowance also carries a SEPARATE,
47
+ * independent wire field - `erc20ApprovePayload.spender` - which the approve resolver (erc20.ts)
48
+ * reads verbatim and nothing binds to `quote.tx.to`. So a payload can pass the router check with a
49
+ * genuine 1inch/kyber `tx.to` yet still carry an approve granting an ATTACKER an allowance over the
50
+ * user's token (a classic approval-drain the co-signer would otherwise sign blind).
51
+ *
52
+ * On the initiator these coincide by construction (build.ts sets the approve spender to
53
+ * `getSwapDestinationAddress` === `tx.to`), so this only ever fires on a hand-built/tampered payload.
54
+ * Enforced providers (1inch/kyber/cowswap) MUST have `spender === routerDestination`; unenforced
55
+ * providers (li.fi/swapkit) are NOT bound. CowSwap's spender IS its `tx.to` (both are the fixed
56
+ * GPv2VaultRelayer - see getSwapDestinationAddress.ts), so it binds the same way 1inch/kyber do. Like
57
+ * its sibling this is a MONOTONIC gate: it only throws or no-ops, never changes the signed bytes.
58
+ */
59
+ export declare function assertEnforcedSwapApprovalSpenderBound(provider: string, spender: string, routerDestination: string, chain: Chain): void;
3
60
  /**
4
61
  * Throws if `address` isn't the known router for `provider` on `chain`. Call this at quote
5
62
  * construction, before a GeneralSwapQuote carrying `address` as `tx.evm.to` can exist.
@@ -10,5 +67,5 @@ export declare function assertKnownAggregatorRouter(provider: EnforcedRouterProv
10
67
  * contracts. Structured so the data is queryable (provider + address) and a future allowlist
11
68
  * is easy to build if a stable pattern emerges from real usage.
12
69
  */
13
- export declare function logUnenforcedAggregatorDestination(provider: 'li.fi' | 'swapkit', address: string): void;
70
+ export declare function logUnenforcedAggregatorDestination(provider: string, address: string): void;
14
71
  //# sourceMappingURL=knownAggregatorRouters.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"knownAggregatorRouters.d.ts","sourceRoot":"","sources":["../../../../../../packages/core/chain/swap/general/knownAggregatorRouters.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;AA8DnC,MAAM,MAAM,sBAAsB,GAAG,OAAO,GAAG,OAAO,CAAA;AAEtD;;;GAGG;AACH,wBAAgB,2BAA2B,CAAC,QAAQ,EAAE,sBAAsB,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,GAAG,IAAI,CAcjH;AAED;;;;GAIG;AACH,wBAAgB,kCAAkC,CAAC,QAAQ,EAAE,OAAO,GAAG,SAAS,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAKvG"}
1
+ {"version":3,"file":"knownAggregatorRouters.d.ts","sourceRoot":"","sources":["../../../../../../packages/core/chain/swap/general/knownAggregatorRouters.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;AAmEnC,MAAM,MAAM,sBAAsB,GAAG,OAAO,GAAG,OAAO,GAAG,SAAS,CAAA;AAclE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,wBAAgB,wCAAwC,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,GAAG,IAAI,CAkB9G;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,sCAAsC,CACpD,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,iBAAiB,EAAE,MAAM,EACzB,KAAK,EAAE,KAAK,GACX,IAAI,CASN;AAED;;;GAGG;AACH,wBAAgB,2BAA2B,CAAC,QAAQ,EAAE,sBAAsB,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,GAAG,IAAI,CAwBjH;AAED;;;;GAIG;AACH,wBAAgB,kCAAkC,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAK1F"}
@@ -1,4 +1,6 @@
1
+ import { isOneOf } from '@vultisig/lib-utils/array/isOneOf';
1
2
  import { Chain } from '../../Chain.js';
3
+ import { COW_VAULT_RELAYER_ADDRESS, cowSwapSupportedChains } from './cowswap/config.js';
2
4
  /**
3
5
  * Fund-safety allowlist for the general-purpose EVM swap aggregators (AGG-02, round-2
4
6
  * spec-level fund-safety audit, 2026-07-08).
@@ -18,6 +20,12 @@ import { Chain } from '../../Chain.js';
18
20
  * stable, deterministically-deployed constant on almost every chain — verified against each
19
21
  * provider's OWN live quote API (not just docs/explorers), chain by chain, on 2026-07-08.
20
22
  *
23
+ * CowSwap is ALSO enforced (sdk#1457): unlike 1inch/Kyber it doesn't route to a swap router at
24
+ * all - orders settle off-chain via solvers, and the on-chain leg (both the swap-leg address AND
25
+ * the ERC-20 approval spender) is always the same fixed GPv2VaultRelayer contract across every
26
+ * supported chain (see build.ts / getSwapDestinationAddress.ts). That determinism makes it just
27
+ * as allow-listable as 1inch/Kyber's routers.
28
+ *
21
29
  * CHAIN-SCOPING MATTERS (codex review, PR #1079): 1inch's V6 router is NOT the same address
22
30
  * on zkSync Era — confirmed live (a real 200 response from a real quote request returned a
23
31
  * DIFFERENT contract there). This is exactly the caveat chains/evm/contract/knownContracts.ts
@@ -30,7 +38,10 @@ import { Chain } from '../../Chain.js';
30
38
  * bridge/DEX contracts by design (diamond routing, multi-hop, chain-specific deployments),
31
39
  * so a hard allowlist would false-block legitimate routes. Those two are logged (never
32
40
  * thrown) via logUnenforcedAggregatorDestination so an anomaly is queryable, and so a future
33
- * allowlist has real usage data to build from if a pattern emerges.
41
+ * allowlist has real usage data to build from if a pattern emerges. sdk#1457: because they are
42
+ * the only genuinely unenforceable-by-address providers, they are the one residual gap
43
+ * assertKnownAggregatorRouterOnSigningPath's provider-string closed-list still can't structurally
44
+ * close - see that function's doc comment.
34
45
  */
35
46
  // 1inch Aggregation Router V5 (legacy). Same address as
36
47
  // chains/evm/contract/knownContracts.ts's display-only registry; kept separate here since
@@ -45,15 +56,100 @@ const ONE_INCH_V6_STANDARD_ROUTER = '0x111111125421ca6dc452d289314280a0f8842a65'
45
56
  // V6 on zkSync Era ONLY — live-confirmed 2026-07-08 via a real api.vultisig.com/1inch
46
57
  // v6.0 quote request returning this address (NOT the standard one above).
47
58
  const ONE_INCH_V6_ZKSYNC_ROUTER = '0x6fd4383cb451173d5f9304f041c7bcbf27d561ff';
48
- // KyberSwap MetaAggregationRouterV2 — same address confirmed live 2026-07-08 on every chain
49
- // that returned a response through aggregator-api.kyberswap.com's /routes (Ethereum, BSC,
50
- // Arbitrum, Optimism, Avalanche, Base, Polygon — 7 of 9 kyberSwapEnabledChains chains).
51
- // zkSync/Blast 404'd on this exact API path during verification — that looks like those two
52
- // chains aren't actually live through this aggregator endpoint today (a pre-existing,
53
- // separate question from this fix — kyberSwapEnabledChains may be ahead of what the live API
54
- // serves), not evidence of a differing router address. No chain-scoping needed unless that
55
- // changes.
59
+ // KyberSwap MetaAggregationRouterV2 — same address confirmed live 2026-07-08 on every
60
+ // kyberSwapEnabledChains chain through aggregator-api.kyberswap.com's /routes
61
+ // (Ethereum, BSC, Arbitrum, Optimism, Avalanche, Base, Polygon).
56
62
  const KYBER_STANDARD_ROUTER = '0x6131b5fae19ea4f9d964eac0408e4408b66337b5';
63
+ const ENFORCED_ROUTER_PROVIDERS = new Set(['1inch', 'kyber', 'cowswap']);
64
+ // sdk#1457: the small, closed set of provider values the codebase legitimately produces for a
65
+ // route that is genuinely NOT address-allow-listable. `li.fi`/`swapkit` route through many
66
+ // different bridge/DEX contracts by design (see the file doc comment). `''` is NOT an attacker
67
+ // label - it is the documented fallback mapSwapPayload.ts (and getKeysignSwapPayload's own
68
+ // callers) use for pre-provider-field mobile captures, proven by real golden fixtures
69
+ // (mobileFixtures.golden.test.ts's arb.json/lifiswap.json) that still carry an unset provider.
70
+ // This is a CLOSED list, not "everything not enforced": a `provider` string outside BOTH this
71
+ // set and ENFORCED_ROUTER_PROVIDERS is unrecognized and rejected below, instead of silently logged.
72
+ const RECOGNIZED_UNENFORCED_PROVIDERS = new Set(['li.fi', 'swapkit', '']);
73
+ /**
74
+ * Signing-path re-assert (sdk#1358): the same allow-list check as {@link assertKnownAggregatorRouter},
75
+ * but keyed off an arbitrary provider STRING (the value carried in KeysignSwapPayload.general.provider,
76
+ * which is a plain `string`). Enforced providers (1inch/kyber/cowswap) fail closed; the small closed set
77
+ * of genuinely unenforceable providers (li.fi/swapkit, plus the legacy `''` unattributed provider - see
78
+ * RECOGNIZED_UNENFORCED_PROVIDERS) fall through to the same log-only path they take at quote construction;
79
+ * anything else is rejected outright (sdk#1457, see below).
80
+ *
81
+ * WHY THIS EXISTS SEPARATELY FROM quote construction: a compromised initiator (or server composing the
82
+ * intent) can hand a co-signer a KeysignPayload whose swapPayload.quote.tx.to was NEVER run through the
83
+ * quote-time check - every co-signer independently rebuilds the signing input from that payload, so the
84
+ * guard has to run HERE too, on the signing-input path, or a co-signer (e.g. VultiServer in a 2-of-2)
85
+ * signs a destination it never validated. Mirrors the Ripple resolver's in-resolver fail-closed binding.
86
+ *
87
+ * THREAT MODEL / TRUST OF `provider` (CodeRabbit security review; sdk#1457): `provider` here is the free
88
+ * `provider` STRING on the OneInchSwapPayload proto (the `oneinchSwapPayload` oneof case carries
89
+ * 1inch/li.fi/cowswap/kyber with only this string to tell them apart; swapkit's dedicated transfer route
90
+ * is the one general provider that has its own oneof case - see getKeysignSwapPayload.ts). It is
91
+ * therefore part of the attacker-influenceable payload, NOT a trusted oneof discriminant, and a payload
92
+ * whose `provider` disagrees with its actual executing shape (an attacker relabeling to dodge
93
+ * enforcement) is a real, closable gap - not just a theoretical one.
94
+ *
95
+ * sdk#1457 FIX: two structural improvements that need no proto change. (1) CowSwap is now enforced -
96
+ * unlike li.fi/swapkit it settles through ONE fixed, deterministic contract (the GPv2VaultRelayer, see
97
+ * assertKnownAggregatorRouter), so its destination is exactly as allow-listable as 1inch/Kyber's; a
98
+ * payload can no longer relabel itself 'cowswap' to dodge a router check the way it previously could. (2)
99
+ * the log-only fallback is now a CLOSED list of the provider values the codebase legitimately produces
100
+ * (li.fi/swapkit, plus the legacy `''` unattributed provider) - a `provider` string outside every known
101
+ * value (enforced or unenforced) is unrecognized and REJECTED, not silently passed through. Together
102
+ * these shrink "relabel to escape enforcement" from "any string at all" down to exactly li.fi, swapkit,
103
+ * and the legacy `''`, which remain unenforceable by address because they legitimately route through
104
+ * many different contracts by design (see the file doc comment) - closing that residual gap needs the
105
+ * provider identity to be a trusted wire discriminant instead of a free string, i.e. a proto oneof case
106
+ * per provider (tracked in sdk#1457, not attempted here: a schema change on the shared commondata proto
107
+ * is a cross-repo, cross-consumer change every native client (iOS/Android/Windows) also builds against).
108
+ *
109
+ * This guard remains MONOTONIC beyond that residual gap: it only ever THROWS (rejects) or no-ops - it
110
+ * never makes anything signable that wasn't already.
111
+ */
112
+ export function assertKnownAggregatorRouterOnSigningPath(provider, address, chain) {
113
+ if (ENFORCED_ROUTER_PROVIDERS.has(provider)) {
114
+ // assertKnownAggregatorRouter fails closed on an unrecognized address, INCLUDING an empty/missing
115
+ // one - an enforced-provider swap with no destination is itself a malformed intent we won't sign.
116
+ assertKnownAggregatorRouter(provider, address, chain);
117
+ return;
118
+ }
119
+ if (!RECOGNIZED_UNENFORCED_PROVIDERS.has(provider)) {
120
+ throw new Error(`Unrecognized swap provider "${provider}" on the co-signer signing path - refusing to sign a swap ` +
121
+ 'whose provider label does not match any known aggregator (enforced or unenforced).');
122
+ }
123
+ // Unenforced (li.fi/swapkit): log-only, and log the ACTUAL provider so the usage dataset the future
124
+ // allow-list is built from isn't poisoned by a coerced label. Skip a genuinely empty address.
125
+ if (address) {
126
+ logUnenforcedAggregatorDestination(provider, address);
127
+ }
128
+ }
129
+ /**
130
+ * Signing-path approval-spender bind (sdk#1358 review follow-up, requested by neavra). The
131
+ * follow-on to {@link assertKnownAggregatorRouterOnSigningPath}: that guard validates the swap-leg
132
+ * destination (`quote.tx.to`), but a general swap that needs an allowance also carries a SEPARATE,
133
+ * independent wire field - `erc20ApprovePayload.spender` - which the approve resolver (erc20.ts)
134
+ * reads verbatim and nothing binds to `quote.tx.to`. So a payload can pass the router check with a
135
+ * genuine 1inch/kyber `tx.to` yet still carry an approve granting an ATTACKER an allowance over the
136
+ * user's token (a classic approval-drain the co-signer would otherwise sign blind).
137
+ *
138
+ * On the initiator these coincide by construction (build.ts sets the approve spender to
139
+ * `getSwapDestinationAddress` === `tx.to`), so this only ever fires on a hand-built/tampered payload.
140
+ * Enforced providers (1inch/kyber/cowswap) MUST have `spender === routerDestination`; unenforced
141
+ * providers (li.fi/swapkit) are NOT bound. CowSwap's spender IS its `tx.to` (both are the fixed
142
+ * GPv2VaultRelayer - see getSwapDestinationAddress.ts), so it binds the same way 1inch/kyber do. Like
143
+ * its sibling this is a MONOTONIC gate: it only throws or no-ops, never changes the signed bytes.
144
+ */
145
+ export function assertEnforcedSwapApprovalSpenderBound(provider, spender, routerDestination, chain) {
146
+ if (!ENFORCED_ROUTER_PROVIDERS.has(provider)) {
147
+ return;
148
+ }
149
+ if (spender.toLowerCase() !== routerDestination.toLowerCase()) {
150
+ throw new Error(`${provider} swap approval spender (${spender}) does not match the verified swap router (${routerDestination}) on ${chain} — refusing to sign an approval to an unbound spender.`);
151
+ }
152
+ }
57
153
  /**
58
154
  * Throws if `address` isn't the known router for `provider` on `chain`. Call this at quote
59
155
  * construction, before a GeneralSwapQuote carrying `address` as `tx.evm.to` can exist.
@@ -62,9 +158,19 @@ export function assertKnownAggregatorRouter(provider, address, chain) {
62
158
  const normalized = address.toLowerCase();
63
159
  const isKnown = provider === 'kyber'
64
160
  ? normalized === KYBER_STANDARD_ROUTER
65
- : chain === Chain.Zksync
66
- ? normalized === ONE_INCH_V6_ZKSYNC_ROUTER
67
- : normalized === ONE_INCH_V5_ROUTER || normalized === ONE_INCH_V6_STANDARD_ROUTER;
161
+ : provider === 'cowswap'
162
+ ? // CHAIN-SCOPED, same reason the 1inch arm is: the relayer is a deterministic address, so it
163
+ // resolves on EVERY EVM chain, but CoW has only deployed the GPv2 stack on
164
+ // cowSwapSupportedChains (findSwapQuote gates quotes to exactly those). Accepting it
165
+ // chain-agnostically would let a tampered payload relabelled 'cowswap' on e.g. CronosChain /
166
+ // Zksync / Blast — where eth_getCode at this address is literally `0x`, verified 2026-07-21 —
167
+ // pass BOTH this guard and assertEnforcedSwapApprovalSpenderBound, so the co-signer would
168
+ // sign an ERC-20 approve to a codeless address anyone can later claim via the deterministic
169
+ // deployment proxy. Fail closed off the supported set.
170
+ isOneOf(chain, cowSwapSupportedChains) && normalized === COW_VAULT_RELAYER_ADDRESS.toLowerCase()
171
+ : chain === Chain.Zksync
172
+ ? normalized === ONE_INCH_V6_ZKSYNC_ROUTER
173
+ : normalized === ONE_INCH_V5_ROUTER || normalized === ONE_INCH_V6_STANDARD_ROUTER;
68
174
  if (!isKnown) {
69
175
  throw new Error(`${provider} swap quote returned an unrecognized router address (${address}) on ${chain} — refusing to build a signable transaction against it.`);
70
176
  }
@@ -1 +1 @@
1
- {"version":3,"file":"knownAggregatorRouters.js","sourceRoot":"","sources":["../../../../../../packages/core/chain/swap/general/knownAggregatorRouters.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;AAEnC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAEH,wDAAwD;AACxD,0FAA0F;AAC1F,4FAA4F;AAC5F,wFAAwF;AACxF,qFAAqF;AACrF,oDAAoD;AACpD,MAAM,kBAAkB,GAAG,4CAA4C,CAAA;AAEvE,sFAAsF;AACtF,yEAAyE;AACzE,MAAM,2BAA2B,GAAG,4CAA4C,CAAA;AAEhF,sFAAsF;AACtF,0EAA0E;AAC1E,MAAM,yBAAyB,GAAG,4CAA4C,CAAA;AAE9E,4FAA4F;AAC5F,0FAA0F;AAC1F,wFAAwF;AACxF,4FAA4F;AAC5F,sFAAsF;AACtF,6FAA6F;AAC7F,2FAA2F;AAC3F,WAAW;AACX,MAAM,qBAAqB,GAAG,4CAA4C,CAAA;AAI1E;;;GAGG;AACH,MAAM,UAAU,2BAA2B,CAAC,QAAgC,EAAE,OAAe,EAAE,KAAY;IACzG,MAAM,UAAU,GAAG,OAAO,CAAC,WAAW,EAAE,CAAA;IACxC,MAAM,OAAO,GACX,QAAQ,KAAK,OAAO;QAClB,CAAC,CAAC,UAAU,KAAK,qBAAqB;QACtC,CAAC,CAAC,KAAK,KAAK,KAAK,CAAC,MAAM;YACtB,CAAC,CAAC,UAAU,KAAK,yBAAyB;YAC1C,CAAC,CAAC,UAAU,KAAK,kBAAkB,IAAI,UAAU,KAAK,2BAA2B,CAAA;IAEvF,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CACb,GAAG,QAAQ,wDAAwD,OAAO,QAAQ,KAAK,yDAAyD,CACjJ,CAAA;IACH,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,kCAAkC,CAAC,QAA6B,EAAE,OAAe;IAC/F,OAAO,CAAC,IAAI,CAAC,8FAA8F,EAAE;QAC3G,QAAQ;QACR,OAAO;KACR,CAAC,CAAA;AACJ,CAAC"}
1
+ {"version":3,"file":"knownAggregatorRouters.js","sourceRoot":"","sources":["../../../../../../packages/core/chain/swap/general/knownAggregatorRouters.ts"],"names":[],"mappings":"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"}
@@ -1,3 +1,3 @@
1
- export declare const kyberSwapEnabledChains: readonly ["Ethereum", "BSC", "Arbitrum", "Polygon", "Optimism", "Avalanche", "Base", "Zksync", "Blast"];
1
+ export declare const kyberSwapEnabledChains: readonly ["Ethereum", "BSC", "Arbitrum", "Polygon", "Optimism", "Avalanche", "Base"];
2
2
  export type KyberSwapEnabledChain = (typeof kyberSwapEnabledChains)[number];
3
3
  //# sourceMappingURL=chains.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"chains.d.ts","sourceRoot":"","sources":["../../../../../../../packages/core/chain/swap/general/kyber/chains.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,sBAAsB,yGAUzB,CAAA;AAEV,MAAM,MAAM,qBAAqB,GAAG,CAAC,OAAO,sBAAsB,CAAC,CAAC,MAAM,CAAC,CAAA"}
1
+ {"version":3,"file":"chains.d.ts","sourceRoot":"","sources":["../../../../../../../packages/core/chain/swap/general/kyber/chains.ts"],"names":[],"mappings":"AAOA,eAAO,MAAM,sBAAsB,sFAQzB,CAAA;AAEV,MAAM,MAAM,qBAAqB,GAAG,CAAC,OAAO,sBAAsB,CAAC,CAAC,MAAM,CAAC,CAAA"}
@@ -1,4 +1,9 @@
1
1
  import { Chain } from '@vultisig/core-chain/Chain';
2
+ // Zksync and Blast are intentionally absent (sdk#1151): Kyber's
3
+ // aggregator-api.kyberswap.com /routes endpoint 404s on both (verified
4
+ // 2026-07-08, see knownAggregatorRouters.ts) — listing them only burned a
5
+ // doomed fetch + timeout slot per quote on those chains. Re-add if Kyber's
6
+ // API starts serving them.
2
7
  export const kyberSwapEnabledChains = [
3
8
  Chain.Ethereum,
4
9
  Chain.BSC,
@@ -7,7 +12,5 @@ export const kyberSwapEnabledChains = [
7
12
  Chain.Optimism,
8
13
  Chain.Avalanche,
9
14
  Chain.Base,
10
- Chain.Zksync,
11
- Chain.Blast,
12
15
  ];
13
16
  //# sourceMappingURL=chains.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"chains.js","sourceRoot":"","sources":["../../../../../../../packages/core/chain/swap/general/kyber/chains.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,4BAA4B,CAAA;AAElD,MAAM,CAAC,MAAM,sBAAsB,GAAG;IACpC,KAAK,CAAC,QAAQ;IACd,KAAK,CAAC,GAAG;IACT,KAAK,CAAC,QAAQ;IACd,KAAK,CAAC,OAAO;IACb,KAAK,CAAC,QAAQ;IACd,KAAK,CAAC,SAAS;IACf,KAAK,CAAC,IAAI;IACV,KAAK,CAAC,MAAM;IACZ,KAAK,CAAC,KAAK;CACH,CAAA"}
1
+ {"version":3,"file":"chains.js","sourceRoot":"","sources":["../../../../../../../packages/core/chain/swap/general/kyber/chains.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,4BAA4B,CAAA;AAElD,gEAAgE;AAChE,uEAAuE;AACvE,0EAA0E;AAC1E,2EAA2E;AAC3E,2BAA2B;AAC3B,MAAM,CAAC,MAAM,sBAAsB,GAAG;IACpC,KAAK,CAAC,QAAQ;IACd,KAAK,CAAC,GAAG;IACT,KAAK,CAAC,QAAQ;IACd,KAAK,CAAC,OAAO;IACb,KAAK,CAAC,QAAQ;IACd,KAAK,CAAC,SAAS;IACf,KAAK,CAAC,IAAI;CACF,CAAA"}