@shapeshiftoss/swapper 20.4.0 → 20.5.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 (169) hide show
  1. package/dist/cjs/.tsbuildinfo +1 -1
  2. package/dist/cjs/constants.js +6 -0
  3. package/dist/cjs/index.d.ts +1 -0
  4. package/dist/cjs/index.js +1 -0
  5. package/dist/cjs/swappers/AcrossSwapper/utils/getAcrossStepData.js +7 -15
  6. package/dist/cjs/swappers/AvnuSwapper/endpoints.js +17 -12
  7. package/dist/cjs/swappers/BebopSwapper/utils/getBebopStepData.js +17 -22
  8. package/dist/cjs/swappers/ButterSwap/swapperApi/getTradeQuote.test.js +1 -0
  9. package/dist/cjs/swappers/ButterSwap/swapperApi/getTradeRate.test.js +1 -0
  10. package/dist/cjs/swappers/ButterSwap/utils/getButterSwapStepData.js +3 -4
  11. package/dist/cjs/swappers/ButterSwap/utils/getButterSwapStepData.test.js +2 -2
  12. package/dist/cjs/swappers/CetusSwapper/endpoints.js +2 -3
  13. package/dist/cjs/swappers/CetusSwapper/swapperApi/getCetusStepData.js +13 -8
  14. package/dist/cjs/swappers/CetusSwapper/swapperApi/getCetusTradeContext.js +1 -2
  15. package/dist/cjs/swappers/CetusSwapper/utils/constants.d.ts +0 -1
  16. package/dist/cjs/swappers/CetusSwapper/utils/constants.js +1 -2
  17. package/dist/cjs/swappers/CetusSwapper/utils/helpers.d.ts +3 -3
  18. package/dist/cjs/swappers/CetusSwapper/utils/helpers.js +6 -17
  19. package/dist/cjs/swappers/DebridgeSwapper/utils/getDebridgeStepData.d.ts +0 -1
  20. package/dist/cjs/swappers/DebridgeSwapper/utils/getDebridgeStepData.js +9 -16
  21. package/dist/cjs/swappers/DebridgeSwapper/utils/getDebridgeTradeContext.js +0 -3
  22. package/dist/cjs/swappers/FyndSwapper/utils/getFyndStepData.js +5 -7
  23. package/dist/cjs/swappers/KyberSwapper/KyberSwapper.d.ts +2 -0
  24. package/dist/cjs/swappers/KyberSwapper/KyberSwapper.js +5 -0
  25. package/dist/cjs/swappers/KyberSwapper/endpoints.d.ts +2 -0
  26. package/dist/cjs/swappers/KyberSwapper/endpoints.js +14 -0
  27. package/dist/cjs/swappers/KyberSwapper/index.d.ts +2 -0
  28. package/dist/cjs/swappers/KyberSwapper/index.js +7 -0
  29. package/dist/cjs/swappers/KyberSwapper/swapperApi/getKyberTradeQuote.d.ts +4 -0
  30. package/dist/cjs/swappers/KyberSwapper/swapperApi/getKyberTradeQuote.js +64 -0
  31. package/dist/cjs/swappers/KyberSwapper/swapperApi/getKyberTradeRate.d.ts +4 -0
  32. package/dist/cjs/swappers/KyberSwapper/swapperApi/getKyberTradeRate.js +31 -0
  33. package/dist/cjs/swappers/KyberSwapper/types.d.ts +62 -0
  34. package/dist/cjs/swappers/KyberSwapper/types.js +2 -0
  35. package/dist/cjs/swappers/KyberSwapper/utils/constants.d.ts +21 -0
  36. package/dist/cjs/swappers/KyberSwapper/utils/constants.js +24 -0
  37. package/dist/cjs/swappers/KyberSwapper/utils/fetchFromKyber.d.ts +23 -0
  38. package/dist/cjs/swappers/KyberSwapper/utils/fetchFromKyber.js +38 -0
  39. package/dist/cjs/swappers/KyberSwapper/utils/getKyberStepData.d.ts +27 -0
  40. package/dist/cjs/swappers/KyberSwapper/utils/getKyberStepData.js +47 -0
  41. package/dist/cjs/swappers/KyberSwapper/utils/getKyberStepData.test.d.ts +1 -0
  42. package/dist/cjs/swappers/KyberSwapper/utils/getKyberStepData.test.js +92 -0
  43. package/dist/cjs/swappers/KyberSwapper/utils/getKyberTradeContext.d.ts +20 -0
  44. package/dist/cjs/swappers/KyberSwapper/utils/getKyberTradeContext.js +63 -0
  45. package/dist/cjs/swappers/KyberSwapper/utils/helpers.d.ts +27 -0
  46. package/dist/cjs/swappers/KyberSwapper/utils/helpers.js +172 -0
  47. package/dist/cjs/swappers/KyberSwapper/utils/helpers.test.d.ts +1 -0
  48. package/dist/cjs/swappers/KyberSwapper/utils/helpers.test.js +110 -0
  49. package/dist/cjs/swappers/KyberSwapper/utils/kyberService.d.ts +5 -0
  50. package/dist/cjs/swappers/KyberSwapper/utils/kyberService.js +9 -0
  51. package/dist/cjs/swappers/NearIntentsSwapper/NearIntentsSwapper.js +1 -0
  52. package/dist/cjs/swappers/NearIntentsSwapper/endpoints.js +13 -14
  53. package/dist/cjs/swappers/NearIntentsSwapper/swapperApi/getTradeRate.js +1 -1
  54. package/dist/cjs/swappers/NearIntentsSwapper/types.d.ts +4 -4
  55. package/dist/cjs/swappers/NearIntentsSwapper/types.js +2 -0
  56. package/dist/cjs/swappers/NearIntentsSwapper/utils/getNearIntentsStepData.js +28 -0
  57. package/dist/cjs/swappers/NearIntentsSwapper/utils/helpers.js +2 -2
  58. package/dist/cjs/swappers/PortalsSwapper/utils/getPortalsStepData.js +36 -55
  59. package/dist/cjs/swappers/PortalsSwapper/utils/getPortalsStepData.test.js +2 -2
  60. package/dist/cjs/swappers/RelaySwapper/utils/getRelayStepData.js +7 -15
  61. package/dist/cjs/swappers/ThorchainSwapper/getTradeQuote/getTradeQuote.test.js +2 -2
  62. package/dist/cjs/swappers/ZrxSwapper/getZrxTradeQuote/getZrxTradeQuote.js +3 -1
  63. package/dist/cjs/swappers/ZrxSwapper/utils/getZrxStepData.d.ts +3 -1
  64. package/dist/cjs/swappers/ZrxSwapper/utils/getZrxStepData.js +29 -10
  65. package/dist/cjs/types.d.ts +36 -8
  66. package/dist/cjs/types.js +1 -0
  67. package/dist/cjs/utils/aptos/constants.d.ts +2 -0
  68. package/dist/cjs/utils/aptos/constants.js +7 -0
  69. package/dist/cjs/utils/aptos/getAptosTransactionFees.d.ts +2 -0
  70. package/dist/cjs/utils/aptos/getAptosTransactionFees.js +13 -0
  71. package/dist/cjs/utils/aptos/getUnsignedAptosTransaction.d.ts +2 -0
  72. package/dist/cjs/utils/aptos/getUnsignedAptosTransaction.js +16 -0
  73. package/dist/cjs/utils/aptos/index.d.ts +3 -0
  74. package/dist/cjs/utils/aptos/index.js +19 -0
  75. package/dist/cjs/utils/evm/getEvmNetworkFeeCryptoBaseUnit.d.ts +19 -6
  76. package/dist/cjs/utils/evm/getEvmNetworkFeeCryptoBaseUnit.js +45 -35
  77. package/dist/cjs/utils/evm/getEvmNetworkFeeCryptoBaseUnit.test.d.ts +1 -0
  78. package/dist/cjs/utils/evm/getEvmNetworkFeeCryptoBaseUnit.test.js +103 -0
  79. package/dist/cjs/utils/evm/stateOverride.d.ts +3 -0
  80. package/dist/cjs/utils/evm/stateOverride.js +10 -4
  81. package/dist/cjs/utils/helpers.js +1 -0
  82. package/dist/cjs/utils/helpers.test.js +1 -0
  83. package/dist/cjs/utils/index.d.ts +3 -2
  84. package/dist/cjs/utils/index.js +11 -27
  85. package/dist/esm/.tsbuildinfo +1 -1
  86. package/dist/esm/constants.js +6 -0
  87. package/dist/esm/index.d.ts +1 -0
  88. package/dist/esm/index.js +1 -0
  89. package/dist/esm/swappers/AcrossSwapper/utils/getAcrossStepData.js +8 -16
  90. package/dist/esm/swappers/AvnuSwapper/endpoints.js +18 -13
  91. package/dist/esm/swappers/BebopSwapper/utils/getBebopStepData.js +18 -23
  92. package/dist/esm/swappers/ButterSwap/swapperApi/getTradeQuote.test.js +1 -0
  93. package/dist/esm/swappers/ButterSwap/swapperApi/getTradeRate.test.js +1 -0
  94. package/dist/esm/swappers/ButterSwap/utils/getButterSwapStepData.js +4 -5
  95. package/dist/esm/swappers/ButterSwap/utils/getButterSwapStepData.test.js +2 -2
  96. package/dist/esm/swappers/CetusSwapper/endpoints.js +3 -4
  97. package/dist/esm/swappers/CetusSwapper/swapperApi/getCetusStepData.js +13 -8
  98. package/dist/esm/swappers/CetusSwapper/swapperApi/getCetusTradeContext.js +2 -3
  99. package/dist/esm/swappers/CetusSwapper/utils/constants.d.ts +0 -1
  100. package/dist/esm/swappers/CetusSwapper/utils/constants.js +0 -1
  101. package/dist/esm/swappers/CetusSwapper/utils/helpers.d.ts +3 -3
  102. package/dist/esm/swappers/CetusSwapper/utils/helpers.js +4 -15
  103. package/dist/esm/swappers/DebridgeSwapper/utils/getDebridgeStepData.d.ts +0 -1
  104. package/dist/esm/swappers/DebridgeSwapper/utils/getDebridgeStepData.js +9 -16
  105. package/dist/esm/swappers/DebridgeSwapper/utils/getDebridgeTradeContext.js +0 -3
  106. package/dist/esm/swappers/FyndSwapper/utils/getFyndStepData.js +6 -8
  107. package/dist/esm/swappers/KyberSwapper/KyberSwapper.d.ts +2 -0
  108. package/dist/esm/swappers/KyberSwapper/KyberSwapper.js +2 -0
  109. package/dist/esm/swappers/KyberSwapper/endpoints.d.ts +2 -0
  110. package/dist/esm/swappers/KyberSwapper/endpoints.js +11 -0
  111. package/dist/esm/swappers/KyberSwapper/index.d.ts +2 -0
  112. package/dist/esm/swappers/KyberSwapper/index.js +2 -0
  113. package/dist/esm/swappers/KyberSwapper/swapperApi/getKyberTradeQuote.d.ts +4 -0
  114. package/dist/esm/swappers/KyberSwapper/swapperApi/getKyberTradeQuote.js +60 -0
  115. package/dist/esm/swappers/KyberSwapper/swapperApi/getKyberTradeRate.d.ts +4 -0
  116. package/dist/esm/swappers/KyberSwapper/swapperApi/getKyberTradeRate.js +27 -0
  117. package/dist/esm/swappers/KyberSwapper/types.d.ts +62 -0
  118. package/dist/esm/swappers/KyberSwapper/types.js +1 -0
  119. package/dist/esm/swappers/KyberSwapper/utils/constants.d.ts +21 -0
  120. package/dist/esm/swappers/KyberSwapper/utils/constants.js +21 -0
  121. package/dist/esm/swappers/KyberSwapper/utils/fetchFromKyber.d.ts +23 -0
  122. package/dist/esm/swappers/KyberSwapper/utils/fetchFromKyber.js +33 -0
  123. package/dist/esm/swappers/KyberSwapper/utils/getKyberStepData.d.ts +27 -0
  124. package/dist/esm/swappers/KyberSwapper/utils/getKyberStepData.js +43 -0
  125. package/dist/esm/swappers/KyberSwapper/utils/getKyberStepData.test.d.ts +1 -0
  126. package/dist/esm/swappers/KyberSwapper/utils/getKyberStepData.test.js +90 -0
  127. package/dist/esm/swappers/KyberSwapper/utils/getKyberTradeContext.d.ts +20 -0
  128. package/dist/esm/swappers/KyberSwapper/utils/getKyberTradeContext.js +59 -0
  129. package/dist/esm/swappers/KyberSwapper/utils/helpers.d.ts +27 -0
  130. package/dist/esm/swappers/KyberSwapper/utils/helpers.js +158 -0
  131. package/dist/esm/swappers/KyberSwapper/utils/helpers.test.d.ts +1 -0
  132. package/dist/esm/swappers/KyberSwapper/utils/helpers.test.js +108 -0
  133. package/dist/esm/swappers/KyberSwapper/utils/kyberService.d.ts +5 -0
  134. package/dist/esm/swappers/KyberSwapper/utils/kyberService.js +3 -0
  135. package/dist/esm/swappers/NearIntentsSwapper/NearIntentsSwapper.js +2 -1
  136. package/dist/esm/swappers/NearIntentsSwapper/endpoints.js +13 -14
  137. package/dist/esm/swappers/NearIntentsSwapper/swapperApi/getTradeRate.js +1 -1
  138. package/dist/esm/swappers/NearIntentsSwapper/types.d.ts +4 -4
  139. package/dist/esm/swappers/NearIntentsSwapper/types.js +2 -0
  140. package/dist/esm/swappers/NearIntentsSwapper/utils/getNearIntentsStepData.js +29 -1
  141. package/dist/esm/swappers/NearIntentsSwapper/utils/helpers.js +2 -2
  142. package/dist/esm/swappers/PortalsSwapper/utils/getPortalsStepData.js +34 -53
  143. package/dist/esm/swappers/PortalsSwapper/utils/getPortalsStepData.test.js +2 -2
  144. package/dist/esm/swappers/RelaySwapper/utils/getRelayStepData.js +9 -17
  145. package/dist/esm/swappers/ThorchainSwapper/getTradeQuote/getTradeQuote.test.js +2 -2
  146. package/dist/esm/swappers/ZrxSwapper/getZrxTradeQuote/getZrxTradeQuote.js +3 -1
  147. package/dist/esm/swappers/ZrxSwapper/utils/getZrxStepData.d.ts +3 -1
  148. package/dist/esm/swappers/ZrxSwapper/utils/getZrxStepData.js +31 -12
  149. package/dist/esm/types.d.ts +36 -8
  150. package/dist/esm/types.js +1 -0
  151. package/dist/esm/utils/aptos/constants.d.ts +2 -0
  152. package/dist/esm/utils/aptos/constants.js +4 -0
  153. package/dist/esm/utils/aptos/getAptosTransactionFees.d.ts +2 -0
  154. package/dist/esm/utils/aptos/getAptosTransactionFees.js +9 -0
  155. package/dist/esm/utils/aptos/getUnsignedAptosTransaction.d.ts +2 -0
  156. package/dist/esm/utils/aptos/getUnsignedAptosTransaction.js +12 -0
  157. package/dist/esm/utils/aptos/index.d.ts +3 -0
  158. package/dist/esm/utils/aptos/index.js +3 -0
  159. package/dist/esm/utils/evm/getEvmNetworkFeeCryptoBaseUnit.d.ts +19 -6
  160. package/dist/esm/utils/evm/getEvmNetworkFeeCryptoBaseUnit.js +42 -35
  161. package/dist/esm/utils/evm/getEvmNetworkFeeCryptoBaseUnit.test.d.ts +1 -0
  162. package/dist/esm/utils/evm/getEvmNetworkFeeCryptoBaseUnit.test.js +101 -0
  163. package/dist/esm/utils/evm/stateOverride.d.ts +3 -0
  164. package/dist/esm/utils/evm/stateOverride.js +8 -3
  165. package/dist/esm/utils/helpers.js +2 -1
  166. package/dist/esm/utils/helpers.test.js +1 -0
  167. package/dist/esm/utils/index.d.ts +3 -2
  168. package/dist/esm/utils/index.js +9 -26
  169. package/package.json +10 -11
@@ -0,0 +1,158 @@
1
+ import { fromAssetId } from '@shapeshiftoss/caip';
2
+ import { BigNumber, bn, bnOrZero } from '@shapeshiftoss/utils';
3
+ import { Err, Ok } from '@sniptt/monads';
4
+ import axios from 'axios';
5
+ import { getAddress, isAddress, isAddressEqual } from 'viem';
6
+ import { TradeQuoteError } from '../../../types.js';
7
+ import { getInputOutputRate, makeSwapErrorRight } from '../../../utils/index.js';
8
+ import { buildAffiliateFee } from '../../../utils/affiliateFee.js';
9
+ import { getTreasuryAddressFromChainId, isNativeEvmAsset } from '../../../utils/helpers.js';
10
+ import { KYBER_CHAINS, KYBER_NATIVE_TOKEN, KYBER_ROUTER_ADDRESS } from './constants.js';
11
+ const isKyberSupportedChainId = (chainId) => chainId in KYBER_CHAINS;
12
+ const invalidResponse = (message, details) => makeSwapErrorRight({ message, details, code: TradeQuoteError.InvalidResponse });
13
+ export const assertValidTrade = ({ sellAsset, buyAsset, }) => {
14
+ if (sellAsset.chainId !== buyAsset.chainId) {
15
+ return Err(makeSwapErrorRight({
16
+ message: 'KyberSwap does not support cross-chain trades',
17
+ code: TradeQuoteError.CrossChainNotSupported,
18
+ }));
19
+ }
20
+ if (!isKyberSupportedChainId(sellAsset.chainId)) {
21
+ return Err(makeSwapErrorRight({
22
+ message: 'KyberSwap only supports configured EVM chains',
23
+ code: TradeQuoteError.UnsupportedChain,
24
+ }));
25
+ }
26
+ return Ok(sellAsset.chainId);
27
+ };
28
+ export const assetIdToKyberToken = (assetId) => isNativeEvmAsset(assetId) ? KYBER_NATIVE_TOKEN : getAddress(fromAssetId(assetId).assetReference);
29
+ export const getKyberFeeParams = ({ chainId, affiliateBps, }) => {
30
+ if (bnOrZero(affiliateBps).lte(0))
31
+ return undefined;
32
+ return {
33
+ feeAmount: affiliateBps,
34
+ chargeFeeBy: 'currency_out',
35
+ isInBps: true,
36
+ feeReceiver: getAddress(getTreasuryAddressFromChainId(chainId)),
37
+ };
38
+ };
39
+ // Kyber only returns the post-fee amountOut; the inverse is at most one base unit off
40
+ export const getKyberBuyAmountBeforeFees = ({ buyAmountAfterFeesCryptoBaseUnit, affiliateBps, }) => {
41
+ if (bnOrZero(affiliateBps).lte(0))
42
+ return buyAmountAfterFeesCryptoBaseUnit;
43
+ return bn(buyAmountAfterFeesCryptoBaseUnit)
44
+ .times(10_000)
45
+ .div(bn(10_000).minus(affiliateBps))
46
+ .integerValue(BigNumber.ROUND_DOWN)
47
+ .toFixed();
48
+ };
49
+ export const getKyberTradeAmounts = ({ input, amountOut, }) => {
50
+ const { sellAsset, buyAsset, sellAmountIncludingProtocolFeesCryptoBaseUnit, affiliateBps } = input;
51
+ const buyAmountAfterFeesCryptoBaseUnit = amountOut;
52
+ const buyAmountBeforeFeesCryptoBaseUnit = getKyberBuyAmountBeforeFees({
53
+ buyAmountAfterFeesCryptoBaseUnit,
54
+ affiliateBps,
55
+ });
56
+ return {
57
+ rate: getInputOutputRate({
58
+ sellAmountCryptoBaseUnit: sellAmountIncludingProtocolFeesCryptoBaseUnit,
59
+ buyAmountCryptoBaseUnit: buyAmountAfterFeesCryptoBaseUnit,
60
+ sellAsset,
61
+ buyAsset,
62
+ }),
63
+ buyAmountBeforeFeesCryptoBaseUnit,
64
+ buyAmountAfterFeesCryptoBaseUnit,
65
+ affiliateFee: buildAffiliateFee({
66
+ strategy: 'buy_asset',
67
+ affiliateBps,
68
+ sellAsset,
69
+ buyAsset,
70
+ sellAmountCryptoBaseUnit: sellAmountIncludingProtocolFeesCryptoBaseUnit,
71
+ buyAmountCryptoBaseUnit: buyAmountBeforeFeesCryptoBaseUnit,
72
+ }),
73
+ };
74
+ };
75
+ const getKyberCodeError = ({ code, message, requestId }) => {
76
+ const tradeQuoteError = (() => {
77
+ switch (code) {
78
+ case 4008:
79
+ case 4009:
80
+ case 4010:
81
+ return TradeQuoteError.NoRouteFound;
82
+ case 4011:
83
+ case 4221:
84
+ return TradeQuoteError.UnsupportedTradePair;
85
+ case 4005:
86
+ case 4007:
87
+ return TradeQuoteError.SellAmountBelowTradeFee;
88
+ default:
89
+ return TradeQuoteError.QueryFailed;
90
+ }
91
+ })();
92
+ return makeSwapErrorRight({
93
+ message: `KyberSwap request failed: ${message}`,
94
+ code: tradeQuoteError,
95
+ details: { code, requestId },
96
+ });
97
+ };
98
+ const isKyberErrorResponse = (value) => typeof value === 'object' &&
99
+ value !== null &&
100
+ 'code' in value &&
101
+ typeof value.code === 'number' &&
102
+ 'message' in value &&
103
+ typeof value.message === 'string';
104
+ export const getKyberRequestError = (error) => {
105
+ const { cause } = error;
106
+ if (!axios.isAxiosError(cause))
107
+ return error;
108
+ const status = cause.response?.status;
109
+ if (status === 429) {
110
+ return makeSwapErrorRight({
111
+ message: 'KyberSwap rate limit exceeded',
112
+ code: TradeQuoteError.RateLimitExceeded,
113
+ });
114
+ }
115
+ if (status === 404) {
116
+ return makeSwapErrorRight({
117
+ message: 'KyberSwap does not serve this chain',
118
+ code: TradeQuoteError.UnsupportedChain,
119
+ });
120
+ }
121
+ const body = cause.response?.data;
122
+ if (isKyberErrorResponse(body))
123
+ return getKyberCodeError(body);
124
+ return makeSwapErrorRight({
125
+ message: `KyberSwap request failed with status ${status}`,
126
+ code: TradeQuoteError.QueryFailed,
127
+ cause,
128
+ });
129
+ };
130
+ const isPinnedRouter = (routerAddress) => isAddress(routerAddress) && isAddressEqual(routerAddress, KYBER_ROUTER_ADDRESS);
131
+ const unpinnedRouterError = (routerAddress) => invalidResponse(`KyberSwap router ${routerAddress} is not the pinned router`);
132
+ export const validateKyberRoute = (response, feeParams) => {
133
+ if (response.code !== 0)
134
+ return Err(getKyberCodeError(response));
135
+ if (!response.data)
136
+ return Err(invalidResponse('KyberSwap returned no route'));
137
+ const { routeSummary, routerAddress } = response.data;
138
+ if (!isPinnedRouter(routerAddress))
139
+ return Err(unpinnedRouterError(routerAddress));
140
+ // Kyber skips the integrator fee on wrap and unwrap routes, so reject them rather than swap fee-free
141
+ if (feeParams && routeSummary.extraFee.feeAmount === '') {
142
+ return Err(makeSwapErrorRight({
143
+ message: 'Wrapping or unwrapping the native asset is not supported through KyberSwap',
144
+ code: TradeQuoteError.UnsupportedTradePair,
145
+ }));
146
+ }
147
+ return Ok(routeSummary);
148
+ };
149
+ export const validateKyberBuild = (response) => {
150
+ if (response.code !== 0)
151
+ return Err(getKyberCodeError(response));
152
+ if (!response.data)
153
+ return Err(invalidResponse('KyberSwap returned no transaction'));
154
+ const { routerAddress } = response.data;
155
+ if (!isPinnedRouter(routerAddress))
156
+ return Err(unpinnedRouterError(routerAddress));
157
+ return Ok(response.data);
158
+ };
@@ -0,0 +1,108 @@
1
+ import { KnownChainIds } from '@shapeshiftoss/types';
2
+ import { describe, expect, it } from 'vitest';
3
+ import { TradeQuoteError } from '../../../types.js';
4
+ import { KYBER_ROUTER_ADDRESS } from './constants.js';
5
+ import { getKyberBuyAmountBeforeFees, getKyberFeeParams, validateKyberBuild, validateKyberRoute, } from './helpers.js';
6
+ const TREASURY = '0xF5AA59151bE6515C4Ca68A0282CF68B3eA4846fC';
7
+ const UNPINNED_ROUTER = '0x1111111111111111111111111111111111111111';
8
+ const EMPTY_EXTRA_FEE = {
9
+ feeAmount: '',
10
+ chargeFeeBy: '',
11
+ isInBps: false,
12
+ feeReceiver: '',
13
+ };
14
+ const hyperEvmFeeParams = getKyberFeeParams({
15
+ chainId: KnownChainIds.HyperEvmMainnet,
16
+ affiliateBps: '60',
17
+ });
18
+ const ROUTE = {
19
+ amountOut: '255332541',
20
+ gas: '679101',
21
+ gasPrice: '100000000',
22
+ extraFee: {
23
+ feeAmount: '60',
24
+ chargeFeeBy: 'currency_out',
25
+ isInBps: true,
26
+ feeReceiver: TREASURY.toLowerCase(),
27
+ },
28
+ };
29
+ const ROUTES_RESPONSE = {
30
+ code: 0,
31
+ message: 'successfully',
32
+ data: { routeSummary: ROUTE, routerAddress: KYBER_ROUTER_ADDRESS },
33
+ requestId: 'route-request',
34
+ };
35
+ const BUILD_RESPONSE = {
36
+ code: 0,
37
+ message: 'successfully',
38
+ data: {
39
+ amountOut: '255332539',
40
+ gas: '679101',
41
+ data: '0xe21fd0e9',
42
+ routerAddress: KYBER_ROUTER_ADDRESS,
43
+ transactionValue: '3000000000000000000',
44
+ },
45
+ requestId: 'build-request',
46
+ };
47
+ describe('getKyberFeeParams', () => {
48
+ it('sends no fee for a fee-free swap', () => {
49
+ expect(getKyberFeeParams({ chainId: KnownChainIds.HyperEvmMainnet, affiliateBps: '0' })).toBeUndefined();
50
+ });
51
+ it('charges the output in bps to the chain treasury', () => {
52
+ expect(hyperEvmFeeParams).toEqual({
53
+ feeAmount: '60',
54
+ chargeFeeBy: 'currency_out',
55
+ isInBps: true,
56
+ feeReceiver: TREASURY,
57
+ });
58
+ });
59
+ });
60
+ describe('getKyberBuyAmountBeforeFees', () => {
61
+ it.each([
62
+ ['255332541', '60', '256873783'],
63
+ ['54334339666759063267443', '60', '54662313548047347351552'],
64
+ ['123', '0', '123'],
65
+ ])('grosses up %s at %s bps to %s', (buyAmountAfterFeesCryptoBaseUnit, affiliateBps, gross) => {
66
+ expect(getKyberBuyAmountBeforeFees({ buyAmountAfterFeesCryptoBaseUnit, affiliateBps })).toBe(gross);
67
+ });
68
+ });
69
+ describe('validateKyberRoute', () => {
70
+ const validate = (summaryOverrides, dataOverrides = {}, feeParams = hyperEvmFeeParams) => validateKyberRoute({
71
+ ...ROUTES_RESPONSE,
72
+ data: {
73
+ ...ROUTES_RESPONSE.data,
74
+ routeSummary: { ...ROUTE, ...summaryOverrides },
75
+ ...dataOverrides,
76
+ },
77
+ }, feeParams);
78
+ it('returns the route summary', () => {
79
+ expect(validateKyberRoute(ROUTES_RESPONSE, hyperEvmFeeParams).unwrap()).toBe(ROUTE);
80
+ });
81
+ it('rejects an unpinned router', () => {
82
+ expect(validate({}, { routerAddress: UNPINNED_ROUTER }).unwrapErr().code).toBe(TradeQuoteError.InvalidResponse);
83
+ });
84
+ it('rejects a route that dropped the requested fee', () => {
85
+ expect(validate({ extraFee: EMPTY_EXTRA_FEE }).unwrapErr().code).toBe(TradeQuoteError.UnsupportedTradePair);
86
+ });
87
+ it('accepts a fee-free route when no fee was requested', () => {
88
+ expect(validateKyberRoute({
89
+ ...ROUTES_RESPONSE,
90
+ data: {
91
+ ...ROUTES_RESPONSE.data,
92
+ routeSummary: { ...ROUTE, extraFee: EMPTY_EXTRA_FEE },
93
+ },
94
+ }, undefined).isOk()).toBe(true);
95
+ });
96
+ });
97
+ describe('validateKyberBuild', () => {
98
+ it('returns the build data', () => {
99
+ expect(validateKyberBuild(BUILD_RESPONSE).unwrap()).toBe(BUILD_RESPONSE.data);
100
+ });
101
+ it('rejects an unpinned router', () => {
102
+ const result = validateKyberBuild({
103
+ ...BUILD_RESPONSE,
104
+ data: { ...BUILD_RESPONSE.data, routerAddress: UNPINNED_ROUTER },
105
+ });
106
+ expect(result.unwrapErr().code).toBe(TradeQuoteError.InvalidResponse);
107
+ });
108
+ });
@@ -0,0 +1,5 @@
1
+ export declare const kyberService: {
2
+ get: <T = any>(url: string, config?: import("axios").AxiosRequestConfig<any> | undefined) => Promise<import("@sniptt/monads").Result<import("axios").AxiosResponse<T, any, {}>, import("../../../index.js").SwapErrorRight>>;
3
+ post: <T_1 = any>(url: string, data: any, config?: import("axios").AxiosRequestConfig<any> | undefined) => Promise<import("@sniptt/monads").Result<import("axios").AxiosResponse<T_1, any, {}>, import("../../../index.js").SwapErrorRight>>;
4
+ delete: <T_2 = any>(url: string, data: any, config?: import("axios").AxiosRequestConfig<any> | undefined) => Promise<import("@sniptt/monads").Result<import("axios").AxiosResponse<T_2, any, {}>, import("../../../index.js").SwapErrorRight>>;
5
+ };
@@ -0,0 +1,3 @@
1
+ import axios from 'axios';
2
+ import { makeSwapperAxiosServiceMonadic } from '../../../utils/index.js';
3
+ export const kyberService = makeSwapperAxiosServiceMonadic(axios.create({ timeout: 10_000 }));
@@ -1,4 +1,4 @@
1
- import { executeEvmTransaction, executeNearTransaction, executeSolanaTransaction, executeStarknetTransaction, executeSuiTransaction, executeTonTransaction, executeTronTransaction, } from '../../utils/index.js';
1
+ import { executeAptosTransaction, executeEvmTransaction, executeNearTransaction, executeSolanaTransaction, executeStarknetTransaction, executeSuiTransaction, executeTonTransaction, executeTronTransaction, } from '../../utils/index.js';
2
2
  export const nearIntentsSwapper = {
3
3
  supportsExternalPayment: true,
4
4
  executeEvmTransaction,
@@ -8,6 +8,7 @@ export const nearIntentsSwapper = {
8
8
  executeSuiTransaction,
9
9
  executeNearTransaction,
10
10
  executeTonTransaction,
11
+ executeAptosTransaction,
11
12
  executeUtxoTransaction: (txToSign, { signAndBroadcastTransaction }) => {
12
13
  return signAndBroadcastTransaction(txToSign);
13
14
  },
@@ -1,5 +1,6 @@
1
1
  import { contractAddressOrUndefined } from '@shapeshiftoss/utils';
2
2
  import { createDefaultStatusResponse, getExecutableTradeStep, getSwapMetadata, isExecutableTradeQuote, } from '../../utils/index.js';
3
+ import { getAptosTransactionFees, getUnsignedAptosTransaction } from '../../utils/aptos/index.js';
3
4
  import { getEvmTransactionFees, getUnsignedEvmTransaction } from '../../utils/evm/index.js';
4
5
  import { getSolanaTransactionFees, getUnsignedSolanaTransaction } from '../../utils/solana/index.js';
5
6
  import { getTronTransactionFees, getUnsignedTronTransaction } from '../../utils/tron/index.js';
@@ -84,7 +85,7 @@ export const nearIntentsApi = {
84
85
  }
85
86
  return Promise.resolve(step.feeData.networkFeeCryptoBaseUnit);
86
87
  },
87
- getUnsignedStarknetTransaction: async ({ stepIndex, tradeQuote, from, assertGetStarknetChainAdapter, }) => {
88
+ getUnsignedStarknetTransaction: async ({ stepIndex, tradeQuote, from, callsOnly, assertGetStarknetChainAdapter, }) => {
88
89
  if (!isExecutableTradeQuote(tradeQuote))
89
90
  throw new Error('Unable to execute a trade rate quote');
90
91
  const step = getExecutableTradeStep(tradeQuote, stepIndex);
@@ -94,24 +95,20 @@ export const nearIntentsApi = {
94
95
  const to = depositAddress;
95
96
  const value = step.sellAmountIncludingProtocolFeesCryptoBaseUnit;
96
97
  const tokenContractAddress = contractAddressOrUndefined(sellAsset.assetId);
97
- const { fast } = await adapter.getFeeData({
98
- to,
99
- value,
100
- chainSpecific: {
101
- from,
102
- tokenContractAddress,
103
- },
104
- sendMax: false,
105
- });
98
+ const maxFee = callsOnly
99
+ ? undefined
100
+ : (await adapter.getFeeData({
101
+ to,
102
+ value,
103
+ chainSpecific: { from, tokenContractAddress },
104
+ sendMax: false,
105
+ })).fast.chainSpecific.maxFee;
106
106
  return adapter.buildSendApiTransaction({
107
107
  from,
108
108
  to,
109
109
  value,
110
110
  accountNumber,
111
- chainSpecific: {
112
- tokenContractAddress,
113
- maxFee: fast.chainSpecific.maxFee,
114
- },
111
+ chainSpecific: { tokenContractAddress, maxFee, callsOnly },
115
112
  });
116
113
  },
117
114
  getStarknetTransactionFees: ({ tradeQuote, stepIndex }) => {
@@ -153,6 +150,8 @@ export const nearIntentsApi = {
153
150
  }
154
151
  return Promise.resolve(step.feeData.networkFeeCryptoBaseUnit);
155
152
  },
153
+ getUnsignedAptosTransaction,
154
+ getAptosTransactionFees,
156
155
  checkTradeStatus: async ({ config, swap }) => {
157
156
  if (!swap)
158
157
  throw new Error('Missing swap');
@@ -54,7 +54,7 @@ const getRate = async (input, deps) => {
54
54
  {
55
55
  ...stepCommon,
56
56
  accountNumber,
57
- feeData: { protocolFees, networkFeeCryptoBaseUnit: networkFeeCryptoBaseUnit ?? '0' },
57
+ feeData: { protocolFees, networkFeeCryptoBaseUnit },
58
58
  },
59
59
  ],
60
60
  };
@@ -1,7 +1,7 @@
1
1
  import { KnownChainIds } from '@shapeshiftoss/types';
2
- import type { GetEvmTradeQuoteInput, GetEvmTradeRateInput, GetNearTradeQuoteInput, GetNearTradeRateInput, GetSolanaTradeQuoteInput, GetSolanaTradeRateInput, GetStarknetTradeQuoteInput, GetStarknetTradeRateInput, GetSuiTradeQuoteInput, GetSuiTradeRateInput, GetTonTradeQuoteInput, GetTonTradeRateInput, GetTronTradeQuoteInput, GetTronTradeRateInput, GetUtxoTradeQuoteInput, GetUtxoTradeRateInput, WithExactBuyAmount } from '../../types.js';
3
- export type NearIntentsTradeQuoteInput = GetEvmTradeQuoteInput | GetUtxoTradeQuoteInput | GetSolanaTradeQuoteInput | GetTronTradeQuoteInput | GetSuiTradeQuoteInput | GetStarknetTradeQuoteInput | GetNearTradeQuoteInput | GetTonTradeQuoteInput;
4
- export type NearIntentsTradeRateInput = GetEvmTradeRateInput | GetUtxoTradeRateInput | GetSolanaTradeRateInput | GetTronTradeRateInput | GetSuiTradeRateInput | GetStarknetTradeRateInput | GetNearTradeRateInput | GetTonTradeRateInput;
2
+ import type { GetAptosTradeQuoteInput, GetAptosTradeRateInput, GetEvmTradeQuoteInput, GetEvmTradeRateInput, GetNearTradeQuoteInput, GetNearTradeRateInput, GetSolanaTradeQuoteInput, GetSolanaTradeRateInput, GetStarknetTradeQuoteInput, GetStarknetTradeRateInput, GetSuiTradeQuoteInput, GetSuiTradeRateInput, GetTonTradeQuoteInput, GetTonTradeRateInput, GetTronTradeQuoteInput, GetTronTradeRateInput, GetUtxoTradeQuoteInput, GetUtxoTradeRateInput, WithExactBuyAmount } from '../../types.js';
3
+ export type NearIntentsTradeQuoteInput = GetEvmTradeQuoteInput | GetUtxoTradeQuoteInput | GetSolanaTradeQuoteInput | GetTronTradeQuoteInput | GetSuiTradeQuoteInput | GetStarknetTradeQuoteInput | GetNearTradeQuoteInput | GetTonTradeQuoteInput | GetAptosTradeQuoteInput;
4
+ export type NearIntentsTradeRateInput = GetEvmTradeRateInput | GetUtxoTradeRateInput | GetSolanaTradeRateInput | GetTronTradeRateInput | GetSuiTradeRateInput | GetStarknetTradeRateInput | GetNearTradeRateInput | GetTonTradeRateInput | GetAptosTradeRateInput;
5
5
  export type NearIntentsExactOutputTradeQuoteInput = WithExactBuyAmount<NearIntentsTradeQuoteInput>;
6
6
  export type NearIntentsExactOutputTradeRateInput = WithExactBuyAmount<NearIntentsTradeRateInput>;
7
7
  export type NearIntentsMetadata = {
@@ -11,6 +11,6 @@ export type NearIntentsMetadata = {
11
11
  };
12
12
  export { QuoteRequest } from '@defuse-protocol/one-click-sdk-typescript';
13
13
  export type { GetExecutionStatusResponse, QuoteResponse, TokenResponse, } from '@defuse-protocol/one-click-sdk-typescript';
14
- export declare const nearIntentsSupportedChainIds: readonly [KnownChainIds.EthereumMainnet, KnownChainIds.ArbitrumMainnet, KnownChainIds.BaseMainnet, KnownChainIds.GnosisMainnet, KnownChainIds.BnbSmartChainMainnet, KnownChainIds.PolygonMainnet, KnownChainIds.AvalancheMainnet, KnownChainIds.OptimismMainnet, KnownChainIds.BitcoinMainnet, KnownChainIds.BitcoinCashMainnet, KnownChainIds.DogecoinMainnet, KnownChainIds.ZcashMainnet, KnownChainIds.SolanaMainnet, KnownChainIds.TronMainnet, KnownChainIds.SuiMainnet, KnownChainIds.StarknetMainnet, KnownChainIds.MonadMainnet, KnownChainIds.NearMainnet, KnownChainIds.PlasmaMainnet, KnownChainIds.TonMainnet];
14
+ export declare const nearIntentsSupportedChainIds: readonly [KnownChainIds.EthereumMainnet, KnownChainIds.ArbitrumMainnet, KnownChainIds.BaseMainnet, KnownChainIds.GnosisMainnet, KnownChainIds.BnbSmartChainMainnet, KnownChainIds.PolygonMainnet, KnownChainIds.AvalancheMainnet, KnownChainIds.OptimismMainnet, KnownChainIds.BitcoinMainnet, KnownChainIds.BitcoinCashMainnet, KnownChainIds.DogecoinMainnet, KnownChainIds.ZcashMainnet, KnownChainIds.SolanaMainnet, KnownChainIds.TronMainnet, KnownChainIds.SuiMainnet, KnownChainIds.StarknetMainnet, KnownChainIds.MonadMainnet, KnownChainIds.NearMainnet, KnownChainIds.PlasmaMainnet, KnownChainIds.TonMainnet, KnownChainIds.AptosMainnet];
15
15
  export type NearIntentsSupportedChainId = (typeof nearIntentsSupportedChainIds)[number];
16
16
  export declare const chainIdToNearIntentsChain: Record<NearIntentsSupportedChainId, string>;
@@ -21,6 +21,7 @@ export const nearIntentsSupportedChainIds = [
21
21
  KnownChainIds.NearMainnet,
22
22
  KnownChainIds.PlasmaMainnet,
23
23
  KnownChainIds.TonMainnet,
24
+ KnownChainIds.AptosMainnet,
24
25
  ];
25
26
  export const chainIdToNearIntentsChain = {
26
27
  [KnownChainIds.EthereumMainnet]: 'eth',
@@ -43,4 +44,5 @@ export const chainIdToNearIntentsChain = {
43
44
  [KnownChainIds.MonadMainnet]: 'monad',
44
45
  [KnownChainIds.NearMainnet]: 'near',
45
46
  [KnownChainIds.TonMainnet]: 'ton',
47
+ [KnownChainIds.AptosMainnet]: 'aptos',
46
48
  };
@@ -1,9 +1,10 @@
1
1
  import { CHAIN_NAMESPACE, fromAssetId, fromChainId } from '@shapeshiftoss/caip';
2
- import { evm } from '@shapeshiftoss/chain-adapters';
2
+ import { aptos, evm } from '@shapeshiftoss/chain-adapters';
3
3
  import { bn, contractAddressOrUndefined } from '@shapeshiftoss/utils';
4
4
  import { Err, Ok } from '@sniptt/monads';
5
5
  import { TradeQuoteError } from '../../../types.js';
6
6
  import { makeNetworkFeeEstimationFailedErr, makeSwapErrorRight } from '../../../utils/index.js';
7
+ import { APTOS_PLACEHOLDER_ADDRESS, APTOS_RATE_SIMULATION_VALUE } from '../../../utils/aptos/index.js';
7
8
  import { EVM_PLACEHOLDER_ADDRESS, getEvmNetworkFeeCryptoBaseUnit } from '../../../utils/evm/index.js';
8
9
  import { isNativeEvmAsset } from '../../../utils/helpers.js';
9
10
  import { ATA_RENT_LAMPORTS, getSolanaNetworkFeeCryptoBaseUnit, SOLANA_PLACEHOLDER_ADDRESS, withComputeUnitLimit, } from '../../../utils/solana/index.js';
@@ -218,6 +219,33 @@ export async function getNearIntentsStepData(args) {
218
219
  const stepData = { networkFeeCryptoBaseUnit: fast.txFee };
219
220
  return Ok(stepData);
220
221
  }
222
+ case CHAIN_NAMESPACE.Aptos: {
223
+ const adapter = deps.assertGetAptosChainAdapter(sellAsset.chainId);
224
+ if (type === 'rate') {
225
+ const { fast } = await adapter.getFeeData({
226
+ to: depositAddress,
227
+ value: APTOS_RATE_SIMULATION_VALUE,
228
+ chainSpecific: { from: from ?? APTOS_PLACEHOLDER_ADDRESS, contractAddress },
229
+ });
230
+ const stepData = { networkFeeCryptoBaseUnit: fast.txFee };
231
+ return Ok(stepData);
232
+ }
233
+ const { fast } = await adapter.getFeeData({
234
+ to: depositAddress,
235
+ value: sellAmountCryptoBaseUnit,
236
+ chainSpecific: { from, contractAddress },
237
+ });
238
+ const stepData = {
239
+ transactionData: {
240
+ type: 'aptos',
241
+ payload: aptos.getSerializedTransferPayload(depositAddress, sellAmountCryptoBaseUnit, contractAddress),
242
+ gasUnitPrice: fast.chainSpecific.gasUnitPrice,
243
+ maxGasAmount: fast.chainSpecific.maxGasAmount,
244
+ },
245
+ networkFeeCryptoBaseUnit: fast.txFee,
246
+ };
247
+ return Ok(stepData);
248
+ }
221
249
  default:
222
250
  return Err(makeSwapErrorRight({
223
251
  message: `[getNearIntentsStepData] unsupported chain namespace: ${chainNamespace}`,
@@ -36,7 +36,7 @@ export const getNearIntentsAsset = ({ nearNetwork, contractAddress, }) => {
36
36
  return `nep141:${nearNetwork}-${contractAddress.toLowerCase()}.omft.near`;
37
37
  };
38
38
  const NEP245_CHAINS = ['bsc', 'pol', 'avax', 'op', 'tron', 'monad', 'plasma'];
39
- const TOKEN_LOOKUP_CHAINS = ['sui', 'starknet', 'ton'];
39
+ const TOKEN_LOOKUP_CHAINS = ['sui', 'starknet', 'ton', 'aptos'];
40
40
  const NEAR_CHAIN = 'near';
41
41
  const BTC_CHAIN = 'btc';
42
42
  const WNEAR_CONTRACT_ADDRESS = 'wrap.near';
@@ -68,7 +68,7 @@ export const assetToNearIntentsAsset = async (asset) => {
68
68
  });
69
69
  return match?.assetId ?? null;
70
70
  }
71
- // NEP-245 chains (BSC, Polygon, Avalanche, Optimism, TRON, Monad), Token lookup chains (Sui, Starknet), and Solana require token lookup
71
+ // NEP-245 chains (BSC, Polygon, Avalanche, Optimism, TRON, Monad), Token lookup chains (Sui, Starknet, TON, Aptos), and Solana require token lookup
72
72
  // Asset IDs use hashed format that can't be generated from contract addresses
73
73
  const requiresLookup = isNep245Chain(nearNetwork) || isTokenLookupChain(nearNetwork) || asset.chainId === solanaChainId;
74
74
  if (requiresLookup) {
@@ -1,53 +1,47 @@
1
1
  import { fromChainId } from '@shapeshiftoss/caip';
2
- import { bnOrZero } from '@shapeshiftoss/utils';
3
2
  import { Err, Ok } from '@sniptt/monads';
4
3
  import { makeNetworkFeeEstimationFailedErr } from '../../../utils/index.js';
5
- import { estimateGasWithStateOverride, getEvmNetworkFeeCryptoBaseUnit } from '../../../utils/evm/index.js';
4
+ import { getEvmNetworkFeeCryptoBaseUnit, getEvmRateNetworkFeeCryptoBaseUnit, } from '../../../utils/evm/index.js';
6
5
  import { fetchPortalsTradeEstimate } from './fetchPortalsTradeOrder.js';
7
6
  export async function getPortalsStepData(args) {
8
7
  const { tx, sellAsset, sellAmountCryptoBaseUnit, spenderAddress, input, deps } = args;
9
8
  const adapter = deps.assertGetEvmChainAdapter(sellAsset.chainId);
10
9
  const supportsEIP1559 = 'supportsEIP1559' in input ? input.supportsEIP1559 : false;
10
+ const transactionData = {
11
+ type: 'evm',
12
+ chainId: Number(fromChainId(sellAsset.chainId).chainReference),
13
+ to: tx.to,
14
+ data: tx.data,
15
+ value: tx.value,
16
+ };
17
+ const stateOverride = {
18
+ sellAsset,
19
+ sellAmountCryptoBaseUnit,
20
+ spenderAddress,
21
+ };
11
22
  if (args.type === 'rate') {
23
+ const getEstimateEndpointGasLimit = async () => {
24
+ const quoteEstimateResponse = await fetchPortalsTradeEstimate({
25
+ inputToken: args.inputToken,
26
+ outputToken: args.outputToken,
27
+ inputAmount: args.inputAmount,
28
+ slippageTolerancePercentage: args.slippageTolerancePercentage,
29
+ swapperConfig: deps.config,
30
+ });
31
+ return quoteEstimateResponse.context.gasLimit.toString();
32
+ };
12
33
  try {
13
- // No placeholder estimation for provider built routes - overridden estimation (approval
14
- // state need not exist yet) with the Portals order and estimate endpoint as fallbacks
15
- const gasLimit = await (async () => {
16
- try {
17
- const gasLimit = await estimateGasWithStateOverride({
18
- sellAsset,
19
- sellAmountCryptoBaseUnit,
20
- from: tx.from,
21
- spenderAddress,
22
- to: tx.to,
23
- data: tx.data,
24
- value: tx.value,
25
- });
26
- return gasLimit;
27
- }
28
- catch {
29
- // Portals only carry a tx gas limit on the bridge routes their estimate endpoint zeroes
30
- const { gasLimit: txGasLimit } = tx;
31
- if (txGasLimit && bnOrZero(txGasLimit).gt(0))
32
- return txGasLimit;
33
- const quoteEstimateResponse = await fetchPortalsTradeEstimate({
34
- inputToken: args.inputToken,
35
- outputToken: args.outputToken,
36
- inputAmount: args.inputAmount,
37
- slippageTolerancePercentage: args.slippageTolerancePercentage,
38
- swapperConfig: deps.config,
39
- });
40
- const estimatedGasLimit = quoteEstimateResponse.context.gasLimit.toString();
41
- if (bnOrZero(estimatedGasLimit).lte(0))
42
- throw new Error('no Portals gas limit');
43
- return estimatedGasLimit;
44
- }
45
- })();
46
- const networkFeeCryptoBaseUnit = await getEvmNetworkFeeCryptoBaseUnit({
34
+ // Portals only set a tx gas limit on bridge routes, where their estimate endpoint is zero
35
+ const networkFeeCryptoBaseUnit = await getEvmRateNetworkFeeCryptoBaseUnit({
47
36
  adapter,
48
37
  supportsEIP1559,
49
- gasLimit,
50
- });
38
+ providerGasLimit: tx.gasLimit,
39
+ simulation: { transactionData, from: tx.from, stateOverride },
40
+ }).catch(async () => getEvmRateNetworkFeeCryptoBaseUnit({
41
+ adapter,
42
+ supportsEIP1559,
43
+ providerGasLimit: await getEstimateEndpointGasLimit(),
44
+ }));
51
45
  const stepData = { networkFeeCryptoBaseUnit };
52
46
  return Ok(stepData);
53
47
  }
@@ -55,27 +49,14 @@ export async function getPortalsStepData(args) {
55
49
  return Err(makeNetworkFeeEstimationFailedErr('getPortalsStepData', error));
56
50
  }
57
51
  }
58
- const transactionData = {
59
- type: 'evm',
60
- chainId: Number(fromChainId(sellAsset.chainId).chainReference),
61
- to: tx.to,
62
- data: tx.data,
63
- value: tx.value,
64
- // Portals simulate and pad their gas limit when the order was validated, so no additional
65
- // buffer - an unvalidated order carries no gas limit and estimates below instead
66
- gasLimit: tx.gasLimit,
67
- };
68
52
  try {
69
53
  const networkFeeCryptoBaseUnit = await getEvmNetworkFeeCryptoBaseUnit({
70
54
  adapter,
71
55
  transactionData,
72
56
  from: args.from,
73
57
  supportsEIP1559,
74
- stateOverride: {
75
- sellAsset,
76
- sellAmountCryptoBaseUnit,
77
- spenderAddress,
78
- },
58
+ stateOverride,
59
+ providerGasLimit: tx.gasLimit,
79
60
  });
80
61
  const stepData = { transactionData, networkFeeCryptoBaseUnit };
81
62
  return Ok(stepData);
@@ -45,11 +45,11 @@ const estimateEndpointGasLimit = (gasLimit) => vi.mocked(fetchPortalsTradeEstima
45
45
  });
46
46
  describe('getPortalsStepData rate gas limit', () => {
47
47
  beforeEach(() => vi.clearAllMocks());
48
- it('falls back to the order gas limit on bridge routes the estimate endpoint zeroes', async () => {
49
- vi.mocked(estimateGasWithStateOverride).mockRejectedValue(new Error('execution reverted'));
48
+ it('prices the order gas limit on bridge routes without simulating', async () => {
50
49
  estimateEndpointGasLimit(0);
51
50
  const actual = await rate(tx('76384'));
52
51
  expect(actual.unwrap()).toEqual({ networkFeeCryptoBaseUnit: '76384000000000' });
52
+ expect(estimateGasWithStateOverride).not.toHaveBeenCalled();
53
53
  expect(fetchPortalsTradeEstimate).not.toHaveBeenCalled();
54
54
  });
55
55
  it('falls back to the estimate endpoint when the order carries no gas limit', async () => {
@@ -1,9 +1,9 @@
1
1
  import { fromChainId } from '@shapeshiftoss/caip';
2
2
  import { tron } from '@shapeshiftoss/chain-adapters';
3
- import { bnOrZero, contractAddressOrUndefined, isToken } from '@shapeshiftoss/utils';
3
+ import { contractAddressOrUndefined, isToken } from '@shapeshiftoss/utils';
4
4
  import { Err, Ok } from '@sniptt/monads';
5
5
  import { makeNetworkFeeEstimationFailedErr, makeTradeStepBuildFailedErr } from '../../../utils/index.js';
6
- import { getEvmNetworkFeeCryptoBaseUnit } from '../../../utils/evm/index.js';
6
+ import { getEvmNetworkFeeCryptoBaseUnit, getEvmRateNetworkFeeCryptoBaseUnit, } from '../../../utils/evm/index.js';
7
7
  import { getSolanaNetworkFeeCryptoBaseUnit, omitComputeBudgetInstructions, withComputeUnitLimit, } from '../../../utils/solana/index.js';
8
8
  import { getTronContractCallFallbackFeeCryptoBaseUnit, getTronContractCallNetworkFeeCryptoBaseUnit, } from '../../../utils/tron/index.js';
9
9
  import { getUtxoNetworkFeeCryptoBaseUnit } from '../../../utils/utxo/index.js';
@@ -34,7 +34,6 @@ export async function getRelayStepData({ data, sellAsset, sellAmountCryptoBaseUn
34
34
  to,
35
35
  value,
36
36
  data: callData,
37
- gasLimit: bnOrZero(relayGasLimit).gt(0) ? relayGasLimit : undefined,
38
37
  };
39
38
  const adapter = deps.assertGetEvmChainAdapter(sellAsset.chainId);
40
39
  const stateOverride = {
@@ -43,20 +42,12 @@ export async function getRelayStepData({ data, sellAsset, sellAmountCryptoBaseUn
43
42
  spenderAddress,
44
43
  };
45
44
  if (type === 'rate') {
46
- const networkFeeCryptoBaseUnit = await (async () => {
47
- try {
48
- return await getEvmNetworkFeeCryptoBaseUnit({
49
- adapter,
50
- transactionData,
51
- from,
52
- supportsEIP1559,
53
- stateOverride,
54
- });
55
- }
56
- catch {
57
- return fallbackNetworkFeeCryptoBaseUnit;
58
- }
59
- })();
45
+ const networkFeeCryptoBaseUnit = await getEvmRateNetworkFeeCryptoBaseUnit({
46
+ adapter,
47
+ supportsEIP1559,
48
+ providerGasLimit: relayGasLimit,
49
+ simulation: { transactionData, from, stateOverride },
50
+ }).catch(() => fallbackNetworkFeeCryptoBaseUnit);
60
51
  const stepData = { networkFeeCryptoBaseUnit };
61
52
  return Ok(stepData);
62
53
  }
@@ -68,6 +59,7 @@ export async function getRelayStepData({ data, sellAsset, sellAmountCryptoBaseUn
68
59
  from,
69
60
  supportsEIP1559,
70
61
  stateOverride,
62
+ providerGasLimit: relayGasLimit,
71
63
  });
72
64
  const stepData = { transactionData, networkFeeCryptoBaseUnit };
73
65
  return Ok(stepData);