@shapeshiftoss/swapper 20.1.1 → 20.3.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 (213) hide show
  1. package/dist/cjs/.tsbuildinfo +1 -1
  2. package/dist/cjs/swappers/BebopSwapper/utils/fetchFromBebop.d.ts +1 -2
  3. package/dist/cjs/swappers/BebopSwapper/utils/fetchFromBebop.js +4 -7
  4. package/dist/cjs/swappers/BebopSwapper/utils/getBebopSolanaTradeContext.js +0 -1
  5. package/dist/cjs/swappers/BobGatewaySwapper/BobGatewaySwapper.js +10 -1
  6. package/dist/cjs/swappers/BobGatewaySwapper/endpoints.js +2 -33
  7. package/dist/cjs/swappers/BobGatewaySwapper/swapperApi/getTradeQuote.js +5 -8
  8. package/dist/cjs/swappers/BobGatewaySwapper/swapperApi/getTradeRate.js +1 -2
  9. package/dist/cjs/swappers/BobGatewaySwapper/types.d.ts +3 -3
  10. package/dist/cjs/swappers/BobGatewaySwapper/utils/constants.d.ts +3 -2
  11. package/dist/cjs/swappers/BobGatewaySwapper/utils/constants.js +8 -5
  12. package/dist/cjs/swappers/BobGatewaySwapper/utils/getBobGatewayStepData.d.ts +2 -2
  13. package/dist/cjs/swappers/BobGatewaySwapper/utils/getBobGatewayStepData.js +30 -34
  14. package/dist/cjs/swappers/BobGatewaySwapper/utils/getBobGatewayStepData.test.d.ts +1 -0
  15. package/dist/cjs/swappers/BobGatewaySwapper/utils/getBobGatewayStepData.test.js +117 -0
  16. package/dist/cjs/swappers/BobGatewaySwapper/utils/getBobGatewayTradeContext.js +1 -2
  17. package/dist/cjs/swappers/BobGatewaySwapper/utils/helpers.d.ts +8 -11
  18. package/dist/cjs/swappers/BobGatewaySwapper/utils/helpers.js +36 -31
  19. package/dist/cjs/swappers/ButterSwap/ButterSwap.js +0 -3
  20. package/dist/cjs/swappers/ButterSwap/endpoints.js +0 -3
  21. package/dist/cjs/swappers/ButterSwap/swapperApi/getTradeQuote.js +2 -3
  22. package/dist/cjs/swappers/ButterSwap/swapperApi/getTradeRate.test.js +0 -51
  23. package/dist/cjs/swappers/ButterSwap/types.d.ts +3 -14
  24. package/dist/cjs/swappers/ButterSwap/utils/constants.d.ts +2 -0
  25. package/dist/cjs/swappers/ButterSwap/utils/constants.js +4 -1
  26. package/dist/cjs/swappers/ButterSwap/utils/getButterSwapStepData.d.ts +2 -3
  27. package/dist/cjs/swappers/ButterSwap/utils/getButterSwapStepData.js +42 -65
  28. package/dist/cjs/swappers/ButterSwap/utils/getButterSwapStepData.test.js +115 -73
  29. package/dist/cjs/swappers/ButterSwap/utils/helpers.js +1 -4
  30. package/dist/cjs/swappers/ButterSwap/xhr.js +3 -3
  31. package/dist/cjs/swappers/ChainflipSwapper/endpoints.js +3 -19
  32. package/dist/cjs/swappers/ChainflipSwapper/utils/getChainflipStepData.d.ts +1 -1
  33. package/dist/cjs/swappers/ChainflipSwapper/utils/getChainflipStepData.js +31 -12
  34. package/dist/cjs/swappers/NearIntentsSwapper/constants.d.ts +1 -0
  35. package/dist/cjs/swappers/NearIntentsSwapper/constants.js +3 -1
  36. package/dist/cjs/swappers/NearIntentsSwapper/utils/getNearIntentsStepData.js +10 -5
  37. package/dist/cjs/swappers/NearIntentsSwapper/utils/helpers.js +1 -1
  38. package/dist/cjs/swappers/RelaySwapper/constant.d.ts +1 -1
  39. package/dist/cjs/swappers/RelaySwapper/constant.js +3 -2
  40. package/dist/cjs/swappers/RelaySwapper/getTradeQuote/getTradeQuote.js +1 -2
  41. package/dist/cjs/swappers/RelaySwapper/utils/getRelayAssetAddress.js +2 -1
  42. package/dist/cjs/swappers/RelaySwapper/utils/getRelayStepData.d.ts +2 -3
  43. package/dist/cjs/swappers/RelaySwapper/utils/getRelayStepData.js +46 -13
  44. package/dist/cjs/swappers/RelaySwapper/utils/getRelayStepData.test.d.ts +1 -0
  45. package/dist/cjs/swappers/RelaySwapper/utils/getRelayStepData.test.js +139 -0
  46. package/dist/cjs/swappers/RelaySwapper/utils/helpers.js +1 -2
  47. package/dist/cjs/swappers/RelaySwapper/utils/relayTokenToAssetId.js +1 -1
  48. package/dist/cjs/swappers/RelaySwapper/utils/types.d.ts +1 -4
  49. package/dist/cjs/swappers/SunioSwapper/endpoints.js +3 -63
  50. package/dist/cjs/swappers/SunioSwapper/getSunioTradeQuote/getSunioTradeQuote.js +3 -4
  51. package/dist/cjs/swappers/SunioSwapper/getSunioTradeRate/getSunioTradeRate.js +7 -1
  52. package/dist/cjs/swappers/SunioSwapper/types.d.ts +0 -3
  53. package/dist/cjs/swappers/SunioSwapper/utils/buildSwapContractCall.d.ts +11 -6
  54. package/dist/cjs/swappers/SunioSwapper/utils/buildSwapContractCall.js +33 -30
  55. package/dist/cjs/swappers/SunioSwapper/utils/constants.d.ts +3 -3
  56. package/dist/cjs/swappers/SunioSwapper/utils/constants.js +5 -9
  57. package/dist/cjs/swappers/SunioSwapper/utils/getSunioStepData.d.ts +8 -3
  58. package/dist/cjs/swappers/SunioSwapper/utils/getSunioStepData.js +54 -20
  59. package/dist/cjs/swappers/SunioSwapper/utils/getSunioStepData.test.d.ts +1 -0
  60. package/dist/cjs/swappers/SunioSwapper/utils/getSunioStepData.test.js +177 -0
  61. package/dist/cjs/swappers/SunioSwapper/utils/getSunioTradeContext.js +3 -2
  62. package/dist/cjs/swappers/SunioSwapper/utils/helpers.js +2 -1
  63. package/dist/cjs/swappers/ThorchainSwapper/endpoints.js +3 -4
  64. package/dist/cjs/swappers/ThorchainSwapper/utils/addL1ToLongtailPartsToMemo/addL1ToLongtailPartsToMemo.js +6 -1
  65. package/dist/cjs/swappers/ThorchainSwapper/utils/addL1ToLongtailPartsToMemo/addL1ToLongtailPartsToMemo.test.js +15 -0
  66. package/dist/cjs/swappers/ThorchainSwapper/utils/assertValidLongtailTrade.js +7 -0
  67. package/dist/cjs/swappers/ThorchainSwapper/utils/getL1ToLongtailQuote.js +0 -2
  68. package/dist/cjs/swappers/ThorchainSwapper/utils/getL1ToLongtailRate.js +0 -2
  69. package/dist/cjs/swappers/ThorchainSwapper/utils/getUniqueAddressSubstring/getUniqueAddressSubstring.d.ts +1 -1
  70. package/dist/cjs/swappers/ThorchainSwapper/utils/getUniqueAddressSubstring/getUniqueAddressSubstring.js +17 -20
  71. package/dist/cjs/swappers/ThorchainSwapper/utils/getUniqueAddressSubstring/getUniqueAddressSubstring.test.js +31 -0
  72. package/dist/cjs/types.d.ts +9 -8
  73. package/dist/cjs/utils/helpers.js +3 -0
  74. package/dist/cjs/utils/helpers.test.js +3 -0
  75. package/dist/cjs/utils/thorchain/getThorStepData.js +32 -49
  76. package/dist/cjs/utils/thorchain/getThorStepData.tron.test.d.ts +1 -0
  77. package/dist/cjs/utils/thorchain/getThorStepData.tron.test.js +93 -0
  78. package/dist/cjs/utils/thorchain/index.d.ts +0 -1
  79. package/dist/cjs/utils/thorchain/index.js +1 -14
  80. package/dist/cjs/utils/tron/constants.d.ts +1 -0
  81. package/dist/cjs/utils/tron/constants.js +5 -0
  82. package/dist/cjs/utils/tron/getTronNetworkFeeCryptoBaseUnit.d.ts +27 -0
  83. package/dist/cjs/utils/tron/getTronNetworkFeeCryptoBaseUnit.js +64 -0
  84. package/dist/cjs/utils/tron/getTronNetworkFeeCryptoBaseUnit.test.d.ts +1 -0
  85. package/dist/cjs/utils/tron/getTronNetworkFeeCryptoBaseUnit.test.js +157 -0
  86. package/dist/cjs/utils/tron/getUnsignedTronTransaction.d.ts +2 -1
  87. package/dist/cjs/utils/tron/getUnsignedTronTransaction.js +14 -48
  88. package/dist/cjs/utils/tron/getUnsignedTronTransaction.test.d.ts +1 -0
  89. package/dist/cjs/utils/tron/getUnsignedTronTransaction.test.js +76 -0
  90. package/dist/cjs/utils/tron/index.d.ts +2 -0
  91. package/dist/cjs/utils/tron/index.js +2 -0
  92. package/dist/esm/.tsbuildinfo +1 -1
  93. package/dist/esm/swappers/BebopSwapper/utils/fetchFromBebop.d.ts +1 -2
  94. package/dist/esm/swappers/BebopSwapper/utils/fetchFromBebop.js +4 -7
  95. package/dist/esm/swappers/BebopSwapper/utils/getBebopSolanaTradeContext.js +0 -1
  96. package/dist/esm/swappers/BobGatewaySwapper/BobGatewaySwapper.js +11 -2
  97. package/dist/esm/swappers/BobGatewaySwapper/endpoints.js +5 -36
  98. package/dist/esm/swappers/BobGatewaySwapper/swapperApi/getTradeQuote.js +5 -8
  99. package/dist/esm/swappers/BobGatewaySwapper/swapperApi/getTradeRate.js +1 -2
  100. package/dist/esm/swappers/BobGatewaySwapper/types.d.ts +3 -3
  101. package/dist/esm/swappers/BobGatewaySwapper/utils/constants.d.ts +3 -2
  102. package/dist/esm/swappers/BobGatewaySwapper/utils/constants.js +8 -7
  103. package/dist/esm/swappers/BobGatewaySwapper/utils/getBobGatewayStepData.d.ts +2 -2
  104. package/dist/esm/swappers/BobGatewaySwapper/utils/getBobGatewayStepData.js +21 -25
  105. package/dist/esm/swappers/BobGatewaySwapper/utils/getBobGatewayStepData.test.d.ts +1 -0
  106. package/dist/esm/swappers/BobGatewaySwapper/utils/getBobGatewayStepData.test.js +115 -0
  107. package/dist/esm/swappers/BobGatewaySwapper/utils/getBobGatewayTradeContext.js +1 -2
  108. package/dist/esm/swappers/BobGatewaySwapper/utils/helpers.d.ts +8 -11
  109. package/dist/esm/swappers/BobGatewaySwapper/utils/helpers.js +13 -30
  110. package/dist/esm/swappers/ButterSwap/ButterSwap.js +0 -3
  111. package/dist/esm/swappers/ButterSwap/endpoints.js +0 -3
  112. package/dist/esm/swappers/ButterSwap/swapperApi/getTradeQuote.js +2 -3
  113. package/dist/esm/swappers/ButterSwap/swapperApi/getTradeRate.test.js +1 -49
  114. package/dist/esm/swappers/ButterSwap/types.d.ts +3 -14
  115. package/dist/esm/swappers/ButterSwap/utils/constants.d.ts +2 -0
  116. package/dist/esm/swappers/ButterSwap/utils/constants.js +3 -0
  117. package/dist/esm/swappers/ButterSwap/utils/getButterSwapStepData.d.ts +2 -3
  118. package/dist/esm/swappers/ButterSwap/utils/getButterSwapStepData.js +42 -65
  119. package/dist/esm/swappers/ButterSwap/utils/getButterSwapStepData.test.js +116 -74
  120. package/dist/esm/swappers/ButterSwap/utils/helpers.js +2 -5
  121. package/dist/esm/swappers/ButterSwap/xhr.js +3 -3
  122. package/dist/esm/swappers/ChainflipSwapper/endpoints.js +3 -19
  123. package/dist/esm/swappers/ChainflipSwapper/utils/getChainflipStepData.d.ts +1 -1
  124. package/dist/esm/swappers/ChainflipSwapper/utils/getChainflipStepData.js +32 -13
  125. package/dist/esm/swappers/NearIntentsSwapper/constants.d.ts +1 -0
  126. package/dist/esm/swappers/NearIntentsSwapper/constants.js +2 -0
  127. package/dist/esm/swappers/NearIntentsSwapper/utils/getNearIntentsStepData.js +10 -5
  128. package/dist/esm/swappers/NearIntentsSwapper/utils/helpers.js +2 -2
  129. package/dist/esm/swappers/RelaySwapper/constant.d.ts +1 -1
  130. package/dist/esm/swappers/RelaySwapper/constant.js +2 -1
  131. package/dist/esm/swappers/RelaySwapper/getTradeQuote/getTradeQuote.js +1 -2
  132. package/dist/esm/swappers/RelaySwapper/utils/getRelayAssetAddress.js +3 -2
  133. package/dist/esm/swappers/RelaySwapper/utils/getRelayStepData.d.ts +2 -3
  134. package/dist/esm/swappers/RelaySwapper/utils/getRelayStepData.js +46 -13
  135. package/dist/esm/swappers/RelaySwapper/utils/getRelayStepData.test.d.ts +1 -0
  136. package/dist/esm/swappers/RelaySwapper/utils/getRelayStepData.test.js +137 -0
  137. package/dist/esm/swappers/RelaySwapper/utils/helpers.js +1 -2
  138. package/dist/esm/swappers/RelaySwapper/utils/relayTokenToAssetId.js +3 -3
  139. package/dist/esm/swappers/RelaySwapper/utils/types.d.ts +1 -4
  140. package/dist/esm/swappers/SunioSwapper/endpoints.js +5 -65
  141. package/dist/esm/swappers/SunioSwapper/getSunioTradeQuote/getSunioTradeQuote.js +3 -4
  142. package/dist/esm/swappers/SunioSwapper/getSunioTradeRate/getSunioTradeRate.js +7 -1
  143. package/dist/esm/swappers/SunioSwapper/types.d.ts +0 -3
  144. package/dist/esm/swappers/SunioSwapper/utils/buildSwapContractCall.d.ts +11 -6
  145. package/dist/esm/swappers/SunioSwapper/utils/buildSwapContractCall.js +31 -28
  146. package/dist/esm/swappers/SunioSwapper/utils/constants.d.ts +3 -3
  147. package/dist/esm/swappers/SunioSwapper/utils/constants.js +4 -8
  148. package/dist/esm/swappers/SunioSwapper/utils/getSunioStepData.d.ts +8 -3
  149. package/dist/esm/swappers/SunioSwapper/utils/getSunioStepData.js +52 -18
  150. package/dist/esm/swappers/SunioSwapper/utils/getSunioStepData.test.d.ts +1 -0
  151. package/dist/esm/swappers/SunioSwapper/utils/getSunioStepData.test.js +175 -0
  152. package/dist/esm/swappers/SunioSwapper/utils/getSunioTradeContext.js +2 -1
  153. package/dist/esm/swappers/SunioSwapper/utils/helpers.js +3 -2
  154. package/dist/esm/swappers/ThorchainSwapper/endpoints.js +4 -5
  155. package/dist/esm/swappers/ThorchainSwapper/utils/addL1ToLongtailPartsToMemo/addL1ToLongtailPartsToMemo.js +6 -1
  156. package/dist/esm/swappers/ThorchainSwapper/utils/addL1ToLongtailPartsToMemo/addL1ToLongtailPartsToMemo.test.js +15 -0
  157. package/dist/esm/swappers/ThorchainSwapper/utils/assertValidLongtailTrade.js +7 -0
  158. package/dist/esm/swappers/ThorchainSwapper/utils/getL1ToLongtailQuote.js +0 -2
  159. package/dist/esm/swappers/ThorchainSwapper/utils/getL1ToLongtailRate.js +0 -2
  160. package/dist/esm/swappers/ThorchainSwapper/utils/getUniqueAddressSubstring/getUniqueAddressSubstring.d.ts +1 -1
  161. package/dist/esm/swappers/ThorchainSwapper/utils/getUniqueAddressSubstring/getUniqueAddressSubstring.js +17 -20
  162. package/dist/esm/swappers/ThorchainSwapper/utils/getUniqueAddressSubstring/getUniqueAddressSubstring.test.js +29 -1
  163. package/dist/esm/types.d.ts +9 -8
  164. package/dist/esm/utils/helpers.js +4 -1
  165. package/dist/esm/utils/helpers.test.js +3 -0
  166. package/dist/esm/utils/thorchain/getThorStepData.js +32 -49
  167. package/dist/esm/utils/thorchain/getThorStepData.tron.test.d.ts +1 -0
  168. package/dist/esm/utils/thorchain/getThorStepData.tron.test.js +91 -0
  169. package/dist/esm/utils/thorchain/index.d.ts +0 -1
  170. package/dist/esm/utils/thorchain/index.js +0 -1
  171. package/dist/esm/utils/tron/constants.d.ts +1 -0
  172. package/dist/esm/utils/tron/constants.js +2 -0
  173. package/dist/esm/utils/tron/getTronNetworkFeeCryptoBaseUnit.d.ts +27 -0
  174. package/dist/esm/utils/tron/getTronNetworkFeeCryptoBaseUnit.js +59 -0
  175. package/dist/esm/utils/tron/getTronNetworkFeeCryptoBaseUnit.test.d.ts +1 -0
  176. package/dist/esm/utils/tron/getTronNetworkFeeCryptoBaseUnit.test.js +155 -0
  177. package/dist/esm/utils/tron/getUnsignedTronTransaction.d.ts +2 -1
  178. package/dist/esm/utils/tron/getUnsignedTronTransaction.js +14 -48
  179. package/dist/esm/utils/tron/getUnsignedTronTransaction.test.d.ts +1 -0
  180. package/dist/esm/utils/tron/getUnsignedTronTransaction.test.js +74 -0
  181. package/dist/esm/utils/tron/index.d.ts +2 -0
  182. package/dist/esm/utils/tron/index.js +2 -0
  183. package/package.json +9 -9
  184. package/dist/cjs/swappers/ButterSwap/test-data/eth-btc.json +0 -461
  185. package/dist/cjs/swappers/SunioSwapper/utils/buildSwapRouteParameters.d.ts +0 -14
  186. package/dist/cjs/swappers/SunioSwapper/utils/buildSwapRouteParameters.js +0 -32
  187. package/dist/cjs/swappers/SunioSwapper/utils/estimateSunioNetworkFee.d.ts +0 -12
  188. package/dist/cjs/swappers/SunioSwapper/utils/estimateSunioNetworkFee.js +0 -78
  189. package/dist/cjs/swappers/SunioSwapper/utils/getSunioTransactionFees.d.ts +0 -2
  190. package/dist/cjs/swappers/SunioSwapper/utils/getSunioTransactionFees.js +0 -36
  191. package/dist/cjs/utils/thorchain/tron/getTronTransactionFees.d.ts +0 -2
  192. package/dist/cjs/utils/thorchain/tron/getTronTransactionFees.js +0 -68
  193. package/dist/cjs/utils/thorchain/tron/getUnsignedTronTransaction.d.ts +0 -3
  194. package/dist/cjs/utils/thorchain/tron/getUnsignedTronTransaction.js +0 -35
  195. package/dist/cjs/utils/thorchain/tron/index.d.ts +0 -2
  196. package/dist/cjs/utils/thorchain/tron/index.js +0 -18
  197. package/dist/esm/swappers/ButterSwap/test-data/eth-btc.json +0 -461
  198. package/dist/esm/swappers/SunioSwapper/utils/buildSwapRouteParameters.d.ts +0 -14
  199. package/dist/esm/swappers/SunioSwapper/utils/buildSwapRouteParameters.js +0 -28
  200. package/dist/esm/swappers/SunioSwapper/utils/estimateSunioNetworkFee.d.ts +0 -12
  201. package/dist/esm/swappers/SunioSwapper/utils/estimateSunioNetworkFee.js +0 -74
  202. package/dist/esm/swappers/SunioSwapper/utils/getSunioTransactionFees.d.ts +0 -2
  203. package/dist/esm/swappers/SunioSwapper/utils/getSunioTransactionFees.js +0 -32
  204. package/dist/esm/utils/thorchain/tron/getTronTransactionFees.d.ts +0 -2
  205. package/dist/esm/utils/thorchain/tron/getTronTransactionFees.js +0 -64
  206. package/dist/esm/utils/thorchain/tron/getUnsignedTronTransaction.d.ts +0 -3
  207. package/dist/esm/utils/thorchain/tron/getUnsignedTronTransaction.js +0 -31
  208. package/dist/esm/utils/thorchain/tron/index.d.ts +0 -2
  209. package/dist/esm/utils/thorchain/tron/index.js +0 -2
  210. /package/dist/cjs/swappers/SunioSwapper/utils/{fetchFromSunio.d.ts → fetchSunioQuote.d.ts} +0 -0
  211. /package/dist/cjs/swappers/SunioSwapper/utils/{fetchFromSunio.js → fetchSunioQuote.js} +0 -0
  212. /package/dist/esm/swappers/SunioSwapper/utils/{fetchFromSunio.d.ts → fetchSunioQuote.d.ts} +0 -0
  213. /package/dist/esm/swappers/SunioSwapper/utils/{fetchFromSunio.js → fetchSunioQuote.js} +0 -0
@@ -1,29 +1,32 @@
1
- import { TronWeb } from 'tronweb';
2
- export const SUNIO_SWAP_EXACT_INPUT_SELECTOR = 'swapExactInput(address[],string[],uint256[],uint24[],(uint256,uint256,address,uint256))';
3
- const convertAddressesToEvmFormat = (value) => {
4
- if (Array.isArray(value)) {
5
- return value.map(v => convertAddressesToEvmFormat(v));
6
- }
7
- if (typeof value === 'string' && value.startsWith('T') && TronWeb.isAddress(value)) {
8
- const hex = TronWeb.address.toHex(value);
9
- return hex.replace(/^41/, '0x');
10
- }
11
- return value;
1
+ import { tron } from '@shapeshiftoss/chain-adapters';
2
+ import { bn } from '@shapeshiftoss/utils';
3
+ import { encodeFunctionData, parseAbiItem } from 'viem';
4
+ const SUNIO_SWAP_EXACT_INPUT_ABI = parseAbiItem('function swapExactInput(address[], string[], uint256[], uint24[], (uint256,uint256,address,uint256))');
5
+ // SmartExchangeRouter swapExactInput calldata - the TVM ABI is EVM-compatible, addresses as 20-byte bodies
6
+ export const buildSunioSwapCalldata = ({ route, sellAmountCryptoBaseUnit, minBuyAmountCryptoBaseUnit, recipient, slippageTolerancePercentageDecimal, deadline, }) => {
7
+ const amountOutMin = bn(minBuyAmountCryptoBaseUnit)
8
+ .times(bn(1).minus(slippageTolerancePercentageDecimal))
9
+ .toFixed(0);
10
+ // The SmartExchangeRouter expects sum(versionLen) === path.length: the first pool segment consumes
11
+ // 2 tokens (input + output) and each subsequent pool reuses the previous output, consuming 1 new
12
+ // token. Relies on the Sun.io API returning poolVersions per-hop (poolVersions.length ===
13
+ // tokens.length - 1), which it does.
14
+ const versionLen = route.poolVersions.map((_, index) => (index === 0 ? 2n : 1n));
15
+ const swapData = [
16
+ BigInt(sellAmountCryptoBaseUnit),
17
+ BigInt(amountOutMin),
18
+ tron.toTronHex(recipient),
19
+ BigInt(Math.floor(deadline / 1000)),
20
+ ];
21
+ return encodeFunctionData({
22
+ abi: [SUNIO_SWAP_EXACT_INPUT_ABI],
23
+ functionName: 'swapExactInput',
24
+ args: [
25
+ route.tokens.map(tron.toTronHex),
26
+ route.poolVersions,
27
+ versionLen,
28
+ route.poolFees.map(Number),
29
+ swapData,
30
+ ],
31
+ });
12
32
  };
13
- // Parameter list for the SmartExchangeRouter swapExactInput call, shared between fee
14
- // estimation and execution so both encode the call identically.
15
- export const buildSwapExactInputParameters = (routeParams) => [
16
- { type: 'address[]', value: routeParams.path },
17
- { type: 'string[]', value: routeParams.poolVersion },
18
- { type: 'uint256[]', value: routeParams.versionLen },
19
- { type: 'uint24[]', value: routeParams.fees },
20
- {
21
- type: 'tuple(uint256,uint256,address,uint256)',
22
- value: convertAddressesToEvmFormat([
23
- routeParams.swapData.amountIn,
24
- routeParams.swapData.amountOutMin,
25
- routeParams.swapData.recipient,
26
- routeParams.swapData.deadline,
27
- ]),
28
- },
29
- ];
@@ -2,7 +2,7 @@ export declare const SUNIO_SUPPORTED_CHAIN_IDS: readonly [import("@shapeshiftoss
2
2
  export declare const SUNIO_API_BASE_URL = "https://rot.endjgfsv.link";
3
3
  export declare const SUNIO_SMART_ROUTER_CONTRACT: "TCFNp179Lg46D16zKoumd4Poa2WFFdtqYj";
4
4
  export declare const DEFAULT_SLIPPAGE_PERCENTAGE = "0.005";
5
- export declare const SUNIO_FALLBACK_SWAP_ENERGY_NATIVE = 215000;
6
- export declare const SUNIO_FALLBACK_SWAP_ENERGY_TRC20 = 375000;
5
+ export declare const SUNIO_SWAP_DEADLINE_MS: number;
6
+ export declare const SUNIO_FALLBACK_SWAP_ENERGY_NATIVE = "250000";
7
+ export declare const SUNIO_FALLBACK_SWAP_ENERGY_TRC20 = "480000";
7
8
  export declare const SUNIO_DEX_TYPES: "PSM,CURVE,CURVE_COMBINATION,WTRX,SUNSWAP_V1,SUNSWAP_V2,SUNSWAP_V3";
8
- export declare const SUNIO_TRON_NATIVE_ADDRESS: "T9yD14Nj9j7xAB4dbGeiX9h8unkKHxuWwb";
@@ -8,12 +8,8 @@ export const SUNIO_API_BASE_URL = 'https://rot.endjgfsv.link';
8
8
  // This is the current mainnet router that sun.io's frontend uses
9
9
  export const SUNIO_SMART_ROUTER_CONTRACT = 'TCFNp179Lg46D16zKoumd4Poa2WFFdtqYj';
10
10
  export const DEFAULT_SLIPPAGE_PERCENTAGE = '0.005';
11
- // Energy fallbacks for when we can't simulate a swap (no address, or the simulation reverts
12
- // pre-approval for TRC20 sells). Set to observed average energy so the 1.2x margin applied at
13
- // estimate time lifts them to cover the worst case (native ~245k, TRC20 ~415k due to the extra
14
- // transferFrom token pull) without double-counting safety.
15
- export const SUNIO_FALLBACK_SWAP_ENERGY_NATIVE = 215_000;
16
- export const SUNIO_FALLBACK_SWAP_ENERGY_TRC20 = 375_000;
11
+ export const SUNIO_SWAP_DEADLINE_MS = 20 * 60 * 1000;
12
+ // p90 router energy on mainnet, for rates that can't simulate and token quotes without their allowance
13
+ export const SUNIO_FALLBACK_SWAP_ENERGY_NATIVE = '250000';
14
+ export const SUNIO_FALLBACK_SWAP_ENERGY_TRC20 = '480000';
17
15
  export const SUNIO_DEX_TYPES = 'PSM,CURVE,CURVE_COMBINATION,WTRX,SUNSWAP_V1,SUNSWAP_V2,SUNSWAP_V3';
18
- // Native TRX token address (used when assetId is not a TRC-20 token)
19
- export const SUNIO_TRON_NATIVE_ADDRESS = 'T9yD14Nj9j7xAB4dbGeiX9h8unkKHxuWwb';
@@ -1,17 +1,22 @@
1
1
  import type { Result } from '@sniptt/monads';
2
- import type { StepDataArgs, SwapErrorRight } from '../../../types.js';
3
- import type { SunioRoute, SunioTransactionData } from '../types.js';
2
+ import type { StepDataArgs, SwapErrorRight, TxBuildData } from '../../../types.js';
3
+ import type { SunioRoute } from '../types.js';
4
4
  type BaseArgs = {
5
5
  route: SunioRoute;
6
6
  sellAmountCryptoBaseUnit: string;
7
+ buyAmountCryptoBaseUnit: string;
7
8
  };
8
9
  export type GetSunioStepDataArgs = StepDataArgs<BaseArgs>;
10
+ type TronTxBuildData = Extract<TxBuildData, {
11
+ type: 'tron';
12
+ }>;
9
13
  type SunioRateStepData = {
10
14
  networkFeeCryptoBaseUnit: string | undefined;
11
15
  };
12
16
  type SunioQuoteStepData = {
17
+ transactionData: TronTxBuildData;
13
18
  networkFeeCryptoBaseUnit: string;
14
- sunioTransactionData: SunioTransactionData;
19
+ deadline: number;
15
20
  };
16
21
  export declare function getSunioStepData(args: Extract<GetSunioStepDataArgs, {
17
22
  type: 'rate';
@@ -1,35 +1,69 @@
1
- import { contractAddressOrUndefined } from '@shapeshiftoss/utils';
1
+ import { tronAssetId } from '@shapeshiftoss/caip';
2
+ import { tron } from '@shapeshiftoss/chain-adapters';
2
3
  import { Err, Ok } from '@sniptt/monads';
3
4
  import { makeNetworkFeeEstimationFailedErr } from '../../../utils/index.js';
4
- import { estimateSunioNetworkFeeCryptoBaseUnit } from './estimateSunioNetworkFee.js';
5
+ import { getTronContractCallFallbackFeeCryptoBaseUnit, getTronContractCallNetworkFeeCryptoBaseUnit, TRON_PLACEHOLDER_ADDRESS, } from '../../../utils/tron/index.js';
6
+ import { buildSunioSwapCalldata } from './buildSwapContractCall.js';
7
+ import { DEFAULT_SLIPPAGE_PERCENTAGE, SUNIO_FALLBACK_SWAP_ENERGY_NATIVE, SUNIO_FALLBACK_SWAP_ENERGY_TRC20, SUNIO_SMART_ROUTER_CONTRACT, SUNIO_SWAP_DEADLINE_MS, } from './constants.js';
5
8
  export async function getSunioStepData(args) {
6
- const { type, route, sellAsset, sellAmountCryptoBaseUnit, from, input, deps } = args;
7
- const estimateArgs = {
8
- rpcUrl: deps.config.VITE_TRON_NODE_URL,
9
- apiKey: deps.config.VITE_TRON_GRID_API_KEY,
10
- route,
11
- sellAmountCryptoBaseUnit,
12
- isSellingNativeTrx: !contractAddressOrUndefined(sellAsset.assetId),
13
- address: from,
14
- slippageTolerancePercentageDecimal: input.slippageTolerancePercentageDecimal,
15
- };
9
+ const { type, route, sellAsset, sellAmountCryptoBaseUnit, buyAmountCryptoBaseUnit, from, input } = args;
10
+ const adapter = args.deps.assertGetTronChainAdapter(sellAsset.chainId);
11
+ const isNativeSell = sellAsset.assetId === tronAssetId;
12
+ const fallbackEnergy = isNativeSell
13
+ ? SUNIO_FALLBACK_SWAP_ENERGY_NATIVE
14
+ : SUNIO_FALLBACK_SWAP_ENERGY_TRC20;
15
+ // The router reverts past this, so the quote expires with it
16
+ const deadline = Date.now() + SUNIO_SWAP_DEADLINE_MS;
17
+ const buildCall = (recipient) => ({
18
+ to: SUNIO_SMART_ROUTER_CONTRACT,
19
+ value: isNativeSell ? sellAmountCryptoBaseUnit : '0',
20
+ data: buildSunioSwapCalldata({
21
+ route,
22
+ sellAmountCryptoBaseUnit,
23
+ minBuyAmountCryptoBaseUnit: buyAmountCryptoBaseUnit,
24
+ recipient,
25
+ slippageTolerancePercentageDecimal: input.slippageTolerancePercentageDecimal ?? DEFAULT_SLIPPAGE_PERCENTAGE,
26
+ deadline,
27
+ }),
28
+ });
16
29
  if (type === 'rate') {
17
30
  const networkFeeCryptoBaseUnit = await (async () => {
18
31
  try {
19
- return await estimateSunioNetworkFeeCryptoBaseUnit(estimateArgs);
32
+ if (from) {
33
+ const { to, value, data } = buildCall(from);
34
+ const { fast } = await adapter.getFeeData({ to, value, chainSpecific: { from, data } });
35
+ return fast.txFee;
36
+ }
20
37
  }
21
- catch {
22
- return undefined;
38
+ catch { }
39
+ try {
40
+ return await getTronContractCallFallbackFeeCryptoBaseUnit({
41
+ adapter,
42
+ energy: fallbackEnergy,
43
+ bandwidthBytes: tron.getTronContractCallBandwidthBytes(buildCall(from ?? TRON_PLACEHOLDER_ADDRESS).data),
44
+ contractAddress: SUNIO_SMART_ROUTER_CONTRACT,
45
+ fullEnergyOnShareLookupFailure: true,
46
+ });
23
47
  }
48
+ catch { }
24
49
  })();
25
50
  const stepData = { networkFeeCryptoBaseUnit };
26
51
  return Ok(stepData);
27
52
  }
53
+ const call = buildCall(input.receiveAddress);
28
54
  try {
29
- const networkFeeCryptoBaseUnit = await estimateSunioNetworkFeeCryptoBaseUnit(estimateArgs);
30
55
  const stepData = {
31
- networkFeeCryptoBaseUnit,
32
- sunioTransactionData: { route },
56
+ transactionData: { type: 'tron', ...call },
57
+ networkFeeCryptoBaseUnit: await getTronContractCallNetworkFeeCryptoBaseUnit({
58
+ adapter,
59
+ transactionData: call,
60
+ from,
61
+ sellAsset,
62
+ sellAmountCryptoBaseUnit,
63
+ spenderAddress: SUNIO_SMART_ROUTER_CONTRACT,
64
+ fallbackEnergy,
65
+ }),
66
+ deadline,
33
67
  };
34
68
  return Ok(stepData);
35
69
  }
@@ -0,0 +1,175 @@
1
+ import { tronChainId } from '@shapeshiftoss/caip';
2
+ import { tron } from '@shapeshiftoss/chain-adapters';
3
+ import { describe, expect, it, vi } from 'vitest';
4
+ import { ETH } from '../../../utils/test-data/assets.js';
5
+ import { buildSunioSwapCalldata } from './buildSwapContractCall.js';
6
+ import { SUNIO_FALLBACK_SWAP_ENERGY_NATIVE, SUNIO_FALLBACK_SWAP_ENERGY_TRC20, SUNIO_SMART_ROUTER_CONTRACT, } from './constants.js';
7
+ import { getSunioStepData } from './getSunioStepData.js';
8
+ const USDT = 'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t';
9
+ const TRX = { ...ETH, assetId: `${tronChainId}/slip44:195`, chainId: tronChainId };
10
+ const USDT_TRON = { ...ETH, assetId: `${tronChainId}/trc20:${USDT}`, chainId: tronChainId };
11
+ const FROM = 'TT2T17KZhoDu47i2E4FWxfG79zdkEWkU9N';
12
+ const route = {
13
+ tokens: ['T9yD14Nj9j7xAB4dbGeiX9h8unkKHxuWwb', USDT],
14
+ poolVersions: ['v2'],
15
+ poolFees: ['0'],
16
+ };
17
+ const tronAdapter = ({ txFee = '9000000', allowance = '0' } = {}) => ({
18
+ getFeeData: vi.fn().mockResolvedValue({ fast: { txFee } }),
19
+ httpProvider: {
20
+ getChainPrices: () => Promise.resolve({ energyPrice: 100, bandwidthPrice: 1000 }),
21
+ getTrc20Allowance: vi.fn().mockResolvedValue(allowance),
22
+ getTrc20Balance: vi.fn().mockResolvedValue('100000000'),
23
+ getContractEnergyShare: vi.fn().mockResolvedValue({
24
+ callerPercent: 100,
25
+ originEnergyLimit: 0,
26
+ originEnergyAvailable: 0,
27
+ }),
28
+ },
29
+ });
30
+ const makeDeps = (tron) => ({ assertGetTronChainAdapter: () => tron });
31
+ const baseArgs = {
32
+ route,
33
+ sellAmountCryptoBaseUnit: '100000000',
34
+ buyAmountCryptoBaseUnit: '30000000',
35
+ };
36
+ // The calldata is fixed-width ABI, so its size doesn't depend on the recipient or deadline
37
+ const calldataBandwidthBytes = tron.getTronContractCallBandwidthBytes(buildSunioSwapCalldata({
38
+ route,
39
+ sellAmountCryptoBaseUnit: '100000000',
40
+ minBuyAmountCryptoBaseUnit: '30000000',
41
+ recipient: FROM,
42
+ slippageTolerancePercentageDecimal: '0.005',
43
+ deadline: 0,
44
+ }));
45
+ const fallbackFee = (energy) => String(Number(energy) * 1.2 * 100 + calldataBandwidthBytes * 1000);
46
+ describe('getSunioStepData', () => {
47
+ describe('quote', () => {
48
+ it('carries the router call as transactionData and simulates it', async () => {
49
+ const adapter = tronAdapter();
50
+ const actual = await getSunioStepData({
51
+ ...baseArgs,
52
+ type: 'quote',
53
+ input: {
54
+ receiveAddress: FROM,
55
+ slippageTolerancePercentageDecimal: '0.01',
56
+ },
57
+ deps: makeDeps(adapter),
58
+ sellAsset: TRX,
59
+ from: FROM,
60
+ });
61
+ const { transactionData, networkFeeCryptoBaseUnit, deadline } = actual.unwrap();
62
+ expect(transactionData).toMatchObject({
63
+ type: 'tron',
64
+ to: SUNIO_SMART_ROUTER_CONTRACT,
65
+ value: '100000000',
66
+ });
67
+ // swapExactInput selector
68
+ expect(transactionData.data).toMatch(/^0x[0-9a-f]{8}/);
69
+ expect(networkFeeCryptoBaseUnit).toBe('9000000');
70
+ expect(deadline).toBeGreaterThan(Date.now());
71
+ expect(adapter.getFeeData).toHaveBeenCalledWith({
72
+ to: SUNIO_SMART_ROUTER_CONTRACT,
73
+ value: '100000000',
74
+ chainSpecific: { from: FROM, data: transactionData.data, requireEnergyShare: true },
75
+ });
76
+ });
77
+ it('sends no value for a token sell', async () => {
78
+ const actual = await getSunioStepData({
79
+ ...baseArgs,
80
+ type: 'quote',
81
+ input: { receiveAddress: FROM },
82
+ deps: makeDeps(tronAdapter()),
83
+ sellAsset: USDT_TRON,
84
+ from: FROM,
85
+ });
86
+ expect(actual.unwrap().transactionData.value).toBe('0');
87
+ });
88
+ it('fails a native quote when the simulation fails', async () => {
89
+ const adapter = tronAdapter();
90
+ adapter.getFeeData.mockRejectedValue(new Error('REVERT opcode executed'));
91
+ const actual = await getSunioStepData({
92
+ ...baseArgs,
93
+ type: 'quote',
94
+ input: { receiveAddress: FROM },
95
+ deps: makeDeps(adapter),
96
+ sellAsset: TRX,
97
+ from: FROM,
98
+ });
99
+ expect(actual.isErr()).toBe(true);
100
+ });
101
+ it('prices the token worst case when the allowance is not granted yet', async () => {
102
+ const adapter = tronAdapter({ allowance: '0' });
103
+ adapter.getFeeData.mockRejectedValue(new Error('REVERT opcode executed'));
104
+ const actual = await getSunioStepData({
105
+ ...baseArgs,
106
+ type: 'quote',
107
+ input: { receiveAddress: FROM },
108
+ deps: makeDeps(adapter),
109
+ sellAsset: USDT_TRON,
110
+ from: FROM,
111
+ });
112
+ const { transactionData, networkFeeCryptoBaseUnit } = actual.unwrap();
113
+ expect(transactionData.to).toBe(SUNIO_SMART_ROUTER_CONTRACT);
114
+ expect(networkFeeCryptoBaseUnit).toBe(fallbackFee(SUNIO_FALLBACK_SWAP_ENERGY_TRC20));
115
+ expect(adapter.httpProvider.getTrc20Allowance).toHaveBeenCalledWith({
116
+ contractAddress: USDT,
117
+ owner: FROM,
118
+ spender: SUNIO_SMART_ROUTER_CONTRACT,
119
+ });
120
+ });
121
+ it('fails a token quote that reverts with its allowance in place', async () => {
122
+ const adapter = tronAdapter({ allowance: '100000000' });
123
+ adapter.getFeeData.mockRejectedValue(new Error('REVERT opcode executed'));
124
+ const actual = await getSunioStepData({
125
+ ...baseArgs,
126
+ type: 'quote',
127
+ input: { receiveAddress: FROM },
128
+ deps: makeDeps(adapter),
129
+ sellAsset: USDT_TRON,
130
+ from: FROM,
131
+ });
132
+ expect(actual.isErr()).toBe(true);
133
+ });
134
+ });
135
+ describe('rate', () => {
136
+ it('simulates from the receive address when present', async () => {
137
+ const actual = await getSunioStepData({
138
+ ...baseArgs,
139
+ type: 'rate',
140
+ input: { receiveAddress: FROM },
141
+ deps: makeDeps(tronAdapter()),
142
+ sellAsset: TRX,
143
+ from: FROM,
144
+ });
145
+ expect(actual.unwrap()).toEqual({ networkFeeCryptoBaseUnit: '9000000' });
146
+ });
147
+ it('prices the measured worst case without an address to simulate from', async () => {
148
+ const actual = await getSunioStepData({
149
+ ...baseArgs,
150
+ type: 'rate',
151
+ input: {},
152
+ deps: makeDeps(tronAdapter()),
153
+ sellAsset: TRX,
154
+ });
155
+ expect(actual.unwrap()).toEqual({
156
+ networkFeeCryptoBaseUnit: fallbackFee(SUNIO_FALLBACK_SWAP_ENERGY_NATIVE),
157
+ });
158
+ });
159
+ it('prices the token worst case when a pre-approval simulation reverts', async () => {
160
+ const adapter = tronAdapter();
161
+ adapter.getFeeData.mockRejectedValue(new Error('REVERT opcode executed'));
162
+ const actual = await getSunioStepData({
163
+ ...baseArgs,
164
+ type: 'rate',
165
+ input: { receiveAddress: FROM },
166
+ deps: makeDeps(adapter),
167
+ sellAsset: USDT_TRON,
168
+ from: FROM,
169
+ });
170
+ expect(actual.unwrap()).toEqual({
171
+ networkFeeCryptoBaseUnit: fallbackFee(SUNIO_FALLBACK_SWAP_ENERGY_TRC20),
172
+ });
173
+ });
174
+ });
175
+ });
@@ -4,7 +4,7 @@ import { SwapperName, TradeQuoteError } from '../../../types.js';
4
4
  import { getInputOutputRate, makeSwapErrorRight } from '../../../utils/index.js';
5
5
  import { buildAffiliateFee } from '../../../utils/affiliateFee.js';
6
6
  import { DEFAULT_SLIPPAGE_PERCENTAGE, SUNIO_SMART_ROUTER_CONTRACT } from './constants.js';
7
- import { fetchSunioQuote } from './fetchFromSunio.js';
7
+ import { fetchSunioQuote } from './fetchSunioQuote.js';
8
8
  import { assertValidTrade } from './helpers.js';
9
9
  import { sunioServiceFactory } from './sunioService.js';
10
10
  export const getSunioTradeContext = async ({ input, deps, }) => {
@@ -84,6 +84,7 @@ export const getSunioTradeContext = async ({ input, deps, }) => {
84
84
  deps,
85
85
  sellAsset,
86
86
  sellAmountCryptoBaseUnit: sellAmountIncludingProtocolFeesCryptoBaseUnit,
87
+ buyAmountCryptoBaseUnit,
87
88
  route: bestRoute,
88
89
  },
89
90
  });
@@ -1,9 +1,10 @@
1
1
  import { fromAssetId, tronChainId } from '@shapeshiftoss/caip';
2
+ import { tron } from '@shapeshiftoss/chain-adapters';
2
3
  import { isToken } from '@shapeshiftoss/utils';
3
4
  import { Err, Ok } from '@sniptt/monads';
4
5
  import { SwapperName, TradeQuoteError } from '../../../types.js';
5
6
  import { makeSwapErrorRight } from '../../../utils/index.js';
6
- import { SUNIO_SUPPORTED_CHAIN_IDS, SUNIO_TRON_NATIVE_ADDRESS } from './constants.js';
7
+ import { SUNIO_SUPPORTED_CHAIN_IDS } from './constants.js';
7
8
  export const isSupportedChainId = (chainId) => {
8
9
  return SUNIO_SUPPORTED_CHAIN_IDS.includes(chainId);
9
10
  };
@@ -12,7 +13,7 @@ export const assetIdToTronToken = (assetId) => {
12
13
  const { assetReference } = fromAssetId(assetId);
13
14
  return assetReference;
14
15
  }
15
- return SUNIO_TRON_NATIVE_ADDRESS;
16
+ return tron.TRON_ZERO_ADDRESS;
16
17
  };
17
18
  export const assertValidTrade = ({ sellAsset, buyAsset, }) => {
18
19
  if (!isSupportedChainId(sellAsset.chainId)) {
@@ -1,12 +1,11 @@
1
- import { SwapperName } from '../../types.js';
2
1
  import { getCosmosSdkTransactionFees, getUnsignedCosmosSdkTransaction } from '../../utils/cosmossdk/index.js';
3
2
  import { getEvmTransactionFees, getUnsignedEvmTransaction } from '../../utils/evm/index.js';
4
3
  import { getSolanaTransactionFees, getUnsignedSolanaTransaction } from '../../utils/solana/index.js';
5
- import { checkTradeStatus, tron } from '../../utils/thorchain/index.js';
4
+ import { checkTradeStatus } from '../../utils/thorchain/index.js';
5
+ import { getTronTransactionFees, getUnsignedTronTransaction } from '../../utils/tron/index.js';
6
6
  import { getUnsignedUtxoTransaction, getUtxoTransactionFees } from '../../utils/utxo/index.js';
7
7
  import { getTradeQuote } from './getTradeQuote/getTradeQuote.js';
8
8
  import { getTradeRate } from './getTradeRate/getTradeRate.js';
9
- const swapperName = SwapperName.Thorchain;
10
9
  export const thorchainApi = {
11
10
  getTradeRate: (input, deps) => getTradeRate(input, deps),
12
11
  getTradeQuote: (input, deps) => getTradeQuote(input, deps),
@@ -18,8 +17,8 @@ export const thorchainApi = {
18
17
  getCosmosSdkTransactionFees,
19
18
  getUnsignedSolanaTransaction,
20
19
  getSolanaTransactionFees,
21
- getUnsignedTronTransaction: input => tron.getUnsignedTronTransaction(input, swapperName),
22
- getTronTransactionFees: input => tron.getTronTransactionFees(input, swapperName),
20
+ getUnsignedTronTransaction,
21
+ getTronTransactionFees,
23
22
  checkTradeStatus: input => {
24
23
  const { config } = input;
25
24
  const nodeUrl = `${config.VITE_THORCHAIN_NODE_URL}/thorchain`;
@@ -34,7 +34,12 @@ export const addL1ToLongtailPartsToMemo = ({ sellAssetChainId, quotedMemo, aggre
34
34
  finalAssetAddress: finalAssetContractAddressShortened,
35
35
  });
36
36
  const [prefix, nativeAssetName, address, nativeAssetLimitWithManualSlippage, affiliate, affiliateBps, aggregatorLastTwoChars, finalAssetContract,] = quotedMemoWithAggregatorAndFinalAssetContract.split(MEMO_PART_DELIMITER);
37
- const shortenedNativeAssetName = shortenedNativeAssetNameByNativeAssetName[nativeAssetName];
37
+ // THORNode quote memos may already use the shortened native asset name
38
+ const shortenedNativeAssetNames = Object.values(shortenedNativeAssetNameByNativeAssetName);
39
+ const isAlreadyShortened = shortenedNativeAssetNames.includes(nativeAssetName);
40
+ const shortenedNativeAssetName = isAlreadyShortened
41
+ ? nativeAssetName
42
+ : shortenedNativeAssetNameByNativeAssetName[nativeAssetName];
38
43
  assert(shortenedNativeAssetName, 'cannot find shortened native asset name');
39
44
  const memoWithoutFinalAssetLimit = [
40
45
  prefix,
@@ -35,6 +35,21 @@ describe('addL1ToLongtailPartsToMemo', () => {
35
35
  // The aggregator will turn the finalAssetAmountOut from 94136714201 to 9413671420 using the last 2 bytes as exponents
36
36
  `=:e:0x32DBc9Cf9E8FbCebE1e0a2ecF05Ed86Ca3096Cb6:42:ss:100:d2:a6df4741:94136714201`);
37
37
  });
38
+ it('should accept a quoted memo with an already shortened native asset name', () => {
39
+ const finalAssetAmountOut = '9508759019';
40
+ const quotedMemo = `=:e:0x32DBc9Cf9E8FbCebE1e0a2ecF05Ed86Ca3096Cb6:42:ss:100`;
41
+ const modifiedMemo = addL1ToLongtailPartsToMemo({
42
+ sellAssetChainId: ethChainId,
43
+ quotedMemo,
44
+ aggregator: AGGREGATOR_ADDRESS,
45
+ finalAssetAssetId: FINAL_ASSET_ASSETID,
46
+ finalAssetAmountOut,
47
+ slippageBps,
48
+ longtailTokens: THORCHAIN_ASSETIDS_ONE_COLLISION,
49
+ affiliate: THORCHAIN_AFFILIATE_NAME,
50
+ });
51
+ expect(modifiedMemo).toBe(`=:e:0x32DBc9Cf9E8FbCebE1e0a2ecF05Ed86Ca3096Cb6:42:ss:100:d2:a6df4741:94136714201`);
52
+ });
38
53
  it('should throw if chainId is BCH and initial memo length is > 220', () => {
39
54
  const finalAssetAmountOut = '2083854765519275828179229';
40
55
  const memoOver220Bytes = `=:ETH.ETH:${REALLY_BIG_ADDRESS}:42:ss:100`;
@@ -67,5 +67,12 @@ export const assertValidL1ToLongtailTrade = async ({ sellAsset, buyAsset, deps,
67
67
  details: { sellAssetChainId: sellAsset.chainId },
68
68
  }));
69
69
  }
70
+ if (sellAsset.assetId === buyAssetFeeAsset.assetId) {
71
+ return Err(makeSwapErrorRight({
72
+ message: `[getThorTradeQuote] - Cannot swap ${sellAsset.assetId} to itself before the aggregator.`,
73
+ code: TradeQuoteError.UnsupportedTradePair,
74
+ details: { buyAsset, sellAsset },
75
+ }));
76
+ }
70
77
  return Ok({ buyAssetFeeAsset, longtailTokens });
71
78
  };
@@ -1,4 +1,3 @@
1
- import { TS_AGGREGATOR_TOKEN_TRANSFER_PROXY_CONTRACT_MAINNET } from '@shapeshiftoss/contracts';
2
1
  import { convertDecimalPercentageToBasisPoints } from '@shapeshiftoss/utils';
3
2
  import { Err, Ok } from '@sniptt/monads';
4
3
  import { getDefaultSlippageDecimalPercentageForSwapper } from '../../../constants.js';
@@ -82,7 +81,6 @@ export const getL1ToLongtailQuote = async (input, deps, streamingInterval, swapp
82
81
  buyAmountAfterFeesCryptoBaseUnit: quotedAmountOut.toString(),
83
82
  // This is wrong, we should get the get the value before fees or display ETH value received after the thorchain bridge
84
83
  buyAmountBeforeFeesCryptoBaseUnit: quotedAmountOut.toString(),
85
- allowanceContract: TS_AGGREGATOR_TOKEN_TRANSFER_PROXY_CONTRACT_MAINNET,
86
84
  transactionData,
87
85
  feeData: { ...s.feeData, networkFeeCryptoBaseUnit },
88
86
  })),
@@ -1,4 +1,3 @@
1
- import { TS_AGGREGATOR_TOKEN_TRANSFER_PROXY_CONTRACT_MAINNET } from '@shapeshiftoss/contracts';
2
1
  import { Err, Ok } from '@sniptt/monads';
3
2
  import { getSuccessfulTrades, getThorL1TradeRate, TradeType } from '../../../utils/thorchain/index.js';
4
3
  import { assertValidL1ToLongtailTrade } from './assertValidLongtailTrade.js';
@@ -35,7 +34,6 @@ export const getL1ToLongtailRate = async (input, deps, streamingInterval, swappe
35
34
  buyAmountAfterFeesCryptoBaseUnit: quotedAmountOut.toString(),
36
35
  // This is wrong, we should get the get the value before fees or display ETH value received after the thorchain bridge
37
36
  buyAmountBeforeFeesCryptoBaseUnit: quotedAmountOut.toString(),
38
- allowanceContract: TS_AGGREGATOR_TOKEN_TRANSFER_PROXY_CONTRACT_MAINNET,
39
37
  })),
40
38
  isLongtail: true,
41
39
  });
@@ -1,2 +1,2 @@
1
1
  import type { AssetId } from '@shapeshiftoss/caip';
2
- export declare const getUniqueAddressSubstring: (destinationAssetId: AssetId, longTailAssetIds: AssetId[]) => AssetId;
2
+ export declare const getUniqueAddressSubstring: (destinationAssetId: AssetId, longTailAssetIds: AssetId[]) => string;
@@ -1,23 +1,20 @@
1
+ import { fromAssetId } from '@shapeshiftoss/caip';
2
+ const MINIMUM_UNIQUE_SUBSTRING = 2;
3
+ // Mirrors THORNode's externalAssetMatch: a case-insensitive suffix match against the target chain's token list only
1
4
  export const getUniqueAddressSubstring = (destinationAssetId, longTailAssetIds) => {
2
- const MINIMUM_UNIQUE_SUBSTRING = 2;
3
- let maybeShortenedDestinationAddress = destinationAssetId;
4
- const substringsCount = {};
5
- for (let length = MINIMUM_UNIQUE_SUBSTRING; length <= destinationAssetId.length - 2; length++) {
6
- const currentSubstring = destinationAssetId.slice(-length);
7
- substringsCount[currentSubstring] = 0;
5
+ const { chainId, assetReference } = fromAssetId(destinationAssetId);
6
+ const address = assetReference.toLowerCase();
7
+ const sameChainAddresses = longTailAssetIds
8
+ .map(assetId => fromAssetId(assetId))
9
+ .filter(asset => asset.chainId === chainId)
10
+ .map(asset => asset.assetReference.toLowerCase());
11
+ if (!sameChainAddresses.includes(address))
12
+ return address;
13
+ for (let length = MINIMUM_UNIQUE_SUBSTRING; length < address.length; length++) {
14
+ const suffix = address.slice(-length);
15
+ const matchCount = sameChainAddresses.filter(sameChainAddress => sameChainAddress.endsWith(suffix)).length;
16
+ if (matchCount === 1)
17
+ return suffix;
8
18
  }
9
- longTailAssetIds.forEach(assetId => {
10
- Object.keys(substringsCount).forEach(substring => {
11
- if (assetId.includes(substring)) {
12
- substringsCount[substring] += 1;
13
- }
14
- });
15
- });
16
- for (const [substring, count] of Object.entries(substringsCount)) {
17
- if (count === 1) {
18
- maybeShortenedDestinationAddress = substring;
19
- break;
20
- }
21
- }
22
- return maybeShortenedDestinationAddress;
19
+ return address;
23
20
  };
@@ -1,5 +1,6 @@
1
- import { ethChainId, toAssetId } from '@shapeshiftoss/caip';
1
+ import { bscChainId, ethChainId, toAssetId } from '@shapeshiftoss/caip';
2
2
  import { describe, expect, it } from 'vitest';
3
+ import longtailTokens from '../../generated/generatedThorLongtailTokens.json';
3
4
  import { getUniqueAddressSubstring } from './getUniqueAddressSubstring.js';
4
5
  const FINAL_ASSET_ASSETID = toAssetId({
5
6
  chainId: ethChainId,
@@ -16,6 +17,16 @@ const BIGGER_COLLIDING_FINAL_ASSETID = toAssetId({
16
17
  assetReference: '0xa0b86991c6218b36c1d19d4a2e9eb032a6dF4741',
17
18
  assetNamespace: 'erc20',
18
19
  });
20
+ const SAME_ADDRESS_OTHER_CHAIN_ASSETID = toAssetId({
21
+ chainId: bscChainId,
22
+ assetReference: '0x8a65ac0E23F31979db06Ec62Af62b432a6dF4741',
23
+ assetNamespace: 'erc20',
24
+ });
25
+ const ONE_INCH_ASSETID = toAssetId({
26
+ chainId: ethChainId,
27
+ assetReference: '0x111111111117dc0aa78b770fa6a738034120c302',
28
+ assetNamespace: 'erc20',
29
+ });
19
30
  const SHORTENED_FINAL_ASSET_ADDRESS = 'a6df4741';
20
31
  const BIGGER_SHORTENED_FINAL_ASSET_ADDRESS = '432a6df4741';
21
32
  const THORCHAIN_ASSETIDS_ONE_COLLISION = [FINAL_ASSET_ASSETID, COLLIDING_FINAL_ASSETID];
@@ -33,4 +44,21 @@ describe('getUniqueAddressSubstring', () => {
33
44
  const substring = getUniqueAddressSubstring(FINAL_ASSET_ASSETID, THORCHAIN_ASSETIDS_TWO_COLLISION);
34
45
  expect(substring).toBe(BIGGER_SHORTENED_FINAL_ASSET_ADDRESS);
35
46
  });
47
+ it('should ignore the same address on other chains', () => {
48
+ const substring = getUniqueAddressSubstring(FINAL_ASSET_ASSETID, [
49
+ ...THORCHAIN_ASSETIDS_ONE_COLLISION,
50
+ SAME_ADDRESS_OTHER_CHAIN_ASSETID,
51
+ ]);
52
+ expect(substring).toBe(SHORTENED_FINAL_ASSET_ADDRESS);
53
+ });
54
+ it('should return the full address when the asset is not in the list', () => {
55
+ const substring = getUniqueAddressSubstring(FINAL_ASSET_ASSETID, [COLLIDING_FINAL_ASSETID]);
56
+ expect(substring).toBe('0x8a65ac0e23f31979db06ec62af62b432a6df4741');
57
+ });
58
+ it('should return a hex suffix for an address listed on multiple chains', () => {
59
+ expect(longtailTokens).toContain(ONE_INCH_ASSETID);
60
+ const substring = getUniqueAddressSubstring(ONE_INCH_ASSETID, longtailTokens);
61
+ expect(substring).toMatch(/^[0-9a-f]+$/);
62
+ expect('0x111111111117dc0aa78b770fa6a738034120c302'.endsWith(substring)).toBe(true);
63
+ });
36
64
  });