@rango-dev/widget-embedded 0.1.10-next.80 → 0.1.10-next.82

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 (105) hide show
  1. package/dist/components/AppRouter.d.ts.map +1 -1
  2. package/dist/components/AppRoutes.d.ts.map +1 -1
  3. package/dist/components/ChangeSlippageButton.d.ts +2 -0
  4. package/dist/components/ChangeSlippageButton.d.ts.map +1 -0
  5. package/dist/components/ConfirmSwapErrors.d.ts +3 -0
  6. package/dist/components/ConfirmSwapErrors.d.ts.map +1 -0
  7. package/dist/components/ConfirmSwapWarnings.d.ts +3 -0
  8. package/dist/components/ConfirmSwapWarnings.d.ts.map +1 -0
  9. package/dist/components/Layout.d.ts.map +1 -1
  10. package/dist/components/UpdateUrl.d.ts.map +1 -1
  11. package/dist/components/warnings/BalanceWarnings.d.ts +6 -0
  12. package/dist/components/warnings/BalanceWarnings.d.ts.map +1 -0
  13. package/dist/components/warnings/ConfirmSwapExtraMessages.d.ts +6 -0
  14. package/dist/components/warnings/ConfirmSwapExtraMessages.d.ts.map +1 -0
  15. package/dist/components/warnings/HighSlippageWarning.d.ts +6 -0
  16. package/dist/components/warnings/HighSlippageWarning.d.ts.map +1 -0
  17. package/dist/components/warnings/MinRequiredSlippage.d.ts +6 -0
  18. package/dist/components/warnings/MinRequiredSlippage.d.ts.map +1 -0
  19. package/dist/constants/swapSettings.d.ts +6 -0
  20. package/dist/constants/swapSettings.d.ts.map +1 -0
  21. package/dist/hooks/useNavigateBack.d.ts +4 -0
  22. package/dist/hooks/useNavigateBack.d.ts.map +1 -0
  23. package/dist/pages/ConfirmSwapPage.d.ts.map +1 -1
  24. package/dist/pages/ConfirmWalletsPage.d.ts +0 -5
  25. package/dist/pages/ConfirmWalletsPage.d.ts.map +1 -1
  26. package/dist/pages/HistoryPage.d.ts.map +1 -1
  27. package/dist/pages/Home.d.ts.map +1 -1
  28. package/dist/pages/LiquiditySourcesPage.d.ts.map +1 -1
  29. package/dist/pages/SelectChainPage.d.ts.map +1 -1
  30. package/dist/pages/SelectTokenPage.d.ts.map +1 -1
  31. package/dist/pages/SettingsPage.d.ts.map +1 -1
  32. package/dist/pages/SwapDetailsPage.d.ts.map +1 -1
  33. package/dist/pages/WalletsPage.d.ts.map +1 -1
  34. package/dist/store/bestRoute.d.ts +1 -0
  35. package/dist/store/bestRoute.d.ts.map +1 -1
  36. package/dist/store/confirmSwap.d.ts +35 -0
  37. package/dist/store/confirmSwap.d.ts.map +1 -0
  38. package/dist/store/settings.d.ts.map +1 -1
  39. package/dist/store/ui.d.ts +2 -0
  40. package/dist/store/ui.d.ts.map +1 -0
  41. package/dist/store/wallets.d.ts.map +1 -1
  42. package/dist/types/index.d.ts +2 -0
  43. package/dist/types/index.d.ts.map +1 -0
  44. package/dist/types/swap.d.ts +11 -0
  45. package/dist/types/swap.d.ts.map +1 -0
  46. package/dist/utils/common.d.ts +1 -0
  47. package/dist/utils/common.d.ts.map +1 -1
  48. package/dist/utils/numbers.d.ts +5 -0
  49. package/dist/utils/numbers.d.ts.map +1 -1
  50. package/dist/utils/routing.d.ts +5 -7
  51. package/dist/utils/routing.d.ts.map +1 -1
  52. package/dist/utils/swap.d.ts +31 -3
  53. package/dist/utils/swap.d.ts.map +1 -1
  54. package/dist/utils/wallets.d.ts +2 -3
  55. package/dist/utils/wallets.d.ts.map +1 -1
  56. package/dist/widget-embedded.cjs.development.js +1814 -1327
  57. package/dist/widget-embedded.cjs.development.js.map +1 -1
  58. package/dist/widget-embedded.cjs.production.min.js +1814 -1327
  59. package/dist/widget-embedded.cjs.production.min.js.map +1 -1
  60. package/dist/widget-embedded.esm.js +1818 -1331
  61. package/dist/widget-embedded.esm.js.map +1 -1
  62. package/package.json +1 -1
  63. package/src/components/AppRouter.tsx +38 -3
  64. package/src/components/AppRoutes.tsx +8 -2
  65. package/src/components/ChangeSlippageButton.tsx +23 -0
  66. package/src/components/ConfirmSwapErrors.tsx +38 -0
  67. package/src/components/ConfirmSwapWarnings.tsx +38 -0
  68. package/src/components/Layout.tsx +22 -6
  69. package/src/components/UpdateUrl.tsx +100 -18
  70. package/src/components/warnings/BalanceWarnings.tsx +16 -0
  71. package/src/components/warnings/ConfirmSwapExtraMessages.tsx +14 -0
  72. package/src/components/warnings/HighSlippageWarning.tsx +21 -0
  73. package/src/components/warnings/MinRequiredSlippage.tsx +18 -0
  74. package/src/constants/navigationRoutes.ts +2 -2
  75. package/src/constants/swapSettings.ts +9 -0
  76. package/src/hooks/useNavigateBack.ts +37 -0
  77. package/src/pages/ConfirmSwapPage.tsx +30 -8
  78. package/src/pages/ConfirmWalletsPage.tsx +30 -17
  79. package/src/pages/HistoryPage.tsx +4 -4
  80. package/src/pages/Home.tsx +79 -36
  81. package/src/pages/LiquiditySourcesPage.tsx +11 -8
  82. package/src/pages/SelectChainPage.tsx +9 -28
  83. package/src/pages/SelectTokenPage.tsx +38 -27
  84. package/src/pages/SettingsPage.tsx +26 -11
  85. package/src/pages/SwapDetailsPage.tsx +9 -3
  86. package/src/pages/WalletsPage.tsx +37 -22
  87. package/src/store/bestRoute.ts +147 -28
  88. package/src/store/confirmSwap.ts +327 -0
  89. package/src/store/settings.ts +44 -32
  90. package/src/store/ui.ts +15 -0
  91. package/src/store/wallets.ts +93 -80
  92. package/src/swapBox.tsx +5 -5
  93. package/src/types/index.ts +1 -0
  94. package/src/types/swap.ts +13 -0
  95. package/src/utils/common.ts +4 -0
  96. package/src/utils/numbers.ts +17 -0
  97. package/src/utils/routing.ts +28 -77
  98. package/src/utils/swap.ts +445 -67
  99. package/src/utils/wallets.ts +4 -19
  100. package/dist/hooks/useBestRoute.d.ts +0 -8
  101. package/dist/hooks/useBestRoute.d.ts.map +0 -1
  102. package/dist/hooks/useConfirmSwap.d.ts +0 -2
  103. package/dist/hooks/useConfirmSwap.d.ts.map +0 -1
  104. package/src/hooks/useBestRoute.ts +0 -70
  105. package/src/hooks/useConfirmSwap.ts +0 -268
@@ -10,95 +10,62 @@ var React__default = _interopDefault(React);
10
10
  var reactRouter = require('react-router');
11
11
  var reactRouterDom = require('react-router-dom');
12
12
  var zustand = require('zustand');
13
- var immer = require('zustand/middleware/immer');
14
13
  var BigNumber = require('bignumber.js');
15
14
  var BigNumber__default = _interopDefault(BigNumber);
15
+ var middleware = require('zustand/middleware');
16
16
  var rangoSdk = require('rango-sdk');
17
- var walletsCore = require('@rango-dev/wallets-core');
18
- var providerAll = require('@rango-dev/provider-all');
19
17
  var walletsShared = require('@rango-dev/wallets-shared');
20
- var middleware = require('zustand/middleware');
18
+ var walletsCore = require('@rango-dev/wallets-core');
21
19
  var theme = require('@rango-dev/ui/src/theme');
20
+ var providerAll = require('@rango-dev/provider-all');
21
+ var shallow = require('zustand/shallow');
22
+
23
+ const navigationRoutes = {
24
+ home: '/',
25
+ fromChain: '/from-chain',
26
+ fromToken: '/from-token',
27
+ toChain: '/to-chain',
28
+ toToken: '/to-token',
29
+ settings: '/settings',
30
+ liquiditySources: '/settings/liquidity-sources',
31
+ history: '/history',
32
+ wallets: '/wallets',
33
+ confirmSwap: '/confirm-swap',
34
+ confirmWallets: '/confirm-wallets',
35
+ swapDetails: '/history/swap-details'
36
+ };
22
37
 
23
38
  const ZERO = /*#__PURE__*/new BigNumber__default(0);
24
39
 
25
- const numberToString = function (number, minDecimals, maxDecimals) {
26
- if (minDecimals === void 0) {
27
- minDecimals = null;
28
- }
29
- if (maxDecimals === void 0) {
30
- maxDecimals = null;
31
- }
32
- if (number === null) return '';
33
- if (number === '') return '';
34
- const n = new BigNumber.BigNumber(number);
35
- const roundingMode = 1;
36
- let maxI = 1000;
37
- for (let i = 0; i < 60; i++) {
38
- if (new BigNumber.BigNumber(n.toFixed(i, roundingMode)).eq(n)) {
39
- maxI = i;
40
- break;
41
- }
42
- }
43
- if (n.gte(10000)) return n.toFormat(0, roundingMode);
44
- if (n.gte(1000)) return n.toFormat(Math.min(maxI, Math.min(maxDecimals || 100, Math.max(minDecimals || 0, 1))), roundingMode);
45
- if (n.gte(100)) return n.toFormat(Math.min(maxI, Math.min(maxDecimals || 100, Math.max(minDecimals || 0, 1))), roundingMode);
46
- if (n.gte(1)) return n.toFormat(Math.min(maxI, Math.min(maxDecimals || 100, Math.max(minDecimals || 0, 2))), roundingMode);
47
- if (n.gte(0.01)) return n.toFormat(Math.min(maxI, Math.min(maxDecimals || 100, Math.max(minDecimals || 0, 4))), roundingMode);
48
- for (let i = minDecimals || 4; i < 17; i++) if (n.gte(Math.pow(10, -i))) return n.toFormat(Math.min(maxI, Math.min(maxDecimals || 100, Math.max(minDecimals || 0, i))), roundingMode);
49
- if (n.isEqualTo(0)) return '0';
50
- return n.toFormat(Math.min(maxI, Math.min(maxDecimals || 100, Math.max(minDecimals || 0, 8))), roundingMode);
51
- };
40
+ function removeDuplicateFrom(array) {
41
+ return Array.from(new Set(array));
42
+ }
43
+ function areEqual(array1, array2) {
44
+ return array1.length === array2.length && array1.every((v, i) => v === array2[i]);
45
+ }
52
46
 
53
47
  const getBestRouteToTokenUsdPrice = bestRoute => bestRoute?.result?.swaps[bestRoute?.result?.swaps.length - 1].to.usdPrice;
54
- const compareRoutes = (route1, route2, inputAmount, fromTokenUsdPrice, toTokenUsdPrice) => {
55
- let outUsdValue = (new BigNumber__default(route2.result?.outputAmount || '0') || ZERO).multipliedBy(toTokenUsdPrice || 0);
56
- if (outUsdValue.isNaN()) outUsdValue = ZERO;
57
- let inUsdValue = new BigNumber__default(inputAmount || '0').multipliedBy(fromTokenUsdPrice || 0);
58
- if (inUsdValue.isNaN()) inUsdValue = ZERO;
59
- const outToInRatio = inUsdValue === null || inUsdValue.lte(ZERO) ? 0 : outUsdValue === null || outUsdValue.lte(ZERO) ? 0 : outUsdValue.div(inUsdValue).minus(1).multipliedBy(100);
60
- const disableSwapButton = parseInt(outToInRatio?.toFixed(2) || '0') <= -10 && (inUsdValue === null || inUsdValue.gte(new BigNumber__default(400))) || parseInt(outToInRatio?.toFixed(2) || '0') <= -5 && (inUsdValue === null || inUsdValue.gte(new BigNumber__default(1000)));
61
- if (disableSwapButton) {
62
- return {
63
- isChanged: true,
64
- warningMessage: 'Route updated and price impact is too high, try again later!'
65
- };
66
- }
67
- const out1 = route1.result?.outputAmount || null;
68
- const out2 = route2.result?.outputAmount || null;
69
- if (!!out1 && !!out2) {
70
- const changePercent = new BigNumber__default(out2).div(new BigNumber__default(out1)).minus(1).multipliedBy(100);
71
- if (changePercent.toNumber() <= -1) {
72
- return {
73
- isChanged: true,
74
- warningMessage: `Output amount changed to ${numberToString(out2)}
75
- (${numberToString(changePercent, null, 2)}% change).`
76
- };
77
- }
78
- }
48
+ function isNumberOfSwapsChanged(route1, route2) {
79
49
  const route1Swaps = route1.result?.swaps || [];
80
50
  const route2Swaps = route2.result?.swaps || [];
81
- if (route1Swaps.length !== route2Swaps.length) return {
82
- isChanged: true,
83
- warningMessage: 'Route has been updated.'
84
- };else {
85
- for (let i = 0; i < route1Swaps.length; i++) {
86
- if (route1Swaps[i].swapperId !== route2Swaps[i].swapperId) return {
87
- isChanged: true,
88
- warningMessage: 'Route swappers has been updated.'
89
- };else if (route1Swaps[i].to.symbol !== route2Swaps[i].to.symbol) return {
90
- isChanged: true,
91
- warningMessage: 'Route internal coins has been updated.'
92
- };
93
- }
94
- }
95
- return {
96
- isChanged: false
97
- };
51
+ return route1Swaps.length !== route2Swaps.length;
52
+ }
53
+ function isRouteSwappersUpdated(route1, route2) {
54
+ const route1Swappers = route1.result?.swaps.map(swap => swap.swapperId) || [];
55
+ const route2Swappers = route2.result?.swaps.map(swap => swap.swapperId) || [];
56
+ return !areEqual(route1Swappers, route2Swappers);
57
+ }
58
+ function isRouteInternalCoinsUpdated(route1, route2) {
59
+ const route1InternalCoins = route1.result?.swaps.map(swap => swap.to.symbol) || [];
60
+ const route2InternalCoins = route2.result?.swaps.map(swap => swap.to.symbol) || [];
61
+ return !areEqual(route1InternalCoins, route2InternalCoins);
62
+ }
63
+ const isRouteChanged = (route1, route2) => {
64
+ return isNumberOfSwapsChanged(route1, route2) || isRouteSwappersUpdated(route1, route2) || isRouteInternalCoinsUpdated(route1, route2);
98
65
  };
99
- const getRequiredBalanceOfWallet = (wallet, fee) => {
66
+ const getRequiredBalanceOfWallet = (selectedWallet, fee) => {
100
67
  if (fee === null) return null;
101
- const relatedFeeStatus = fee?.find(item => item.blockchain === wallet.chain)?.wallets.find(it => it.address?.toLowerCase() === wallet.address.toLowerCase());
68
+ const relatedFeeStatus = fee?.find(item => item.blockchain === selectedWallet.chain)?.wallets.find(wallet => wallet.address?.toLowerCase() === selectedWallet.address.toLowerCase());
102
69
  if (!relatedFeeStatus) return null;
103
70
  return relatedFeeStatus.requiredAssets;
104
71
  };
@@ -112,49 +79,13 @@ const createSelectors = _store => {
112
79
  return store;
113
80
  };
114
81
 
115
- const getUsdValue = (token, amount) => new BigNumber__default(amount || ZERO).multipliedBy(token?.usdPrice || 0);
116
- const useBestRouteStore = /*#__PURE__*/createSelectors( /*#__PURE__*/zustand.create()( /*#__PURE__*/immer.immer(set => ({
117
- fromChain: null,
118
- fromToken: null,
119
- inputAmount: '',
120
- outputAmount: null,
121
- inputUsdValue: new BigNumber__default(0),
122
- outputUsdValue: new BigNumber__default(0),
123
- toChain: null,
124
- toToken: null,
125
- bestRoute: null,
126
- setBestRoute: bestRoute => set(state => {
127
- state.bestRoute = bestRoute;
128
- if (!!bestRoute) {
129
- const outputAmount = !!bestRoute.result?.outputAmount ? new BigNumber__default(bestRoute.result?.outputAmount) : null;
130
- state.outputAmount = outputAmount;
131
- state.outputUsdValue = new BigNumber__default(outputAmount || ZERO).multipliedBy(getBestRouteToTokenUsdPrice(bestRoute) || state.toToken?.usdPrice || 0);
132
- }
133
- }),
134
- setFromChain: chain => set(state => {
135
- state.fromChain = chain;
136
- }),
137
- setFromToken: token => set(state => {
138
- state.fromToken = token;
139
- if (!!state.inputAmount) state.inputUsdValue = getUsdValue(state.fromToken, state.inputAmount);
140
- }),
141
- setToChain: chain => set(state => {
142
- state.toChain = chain;
143
- }),
144
- setToToken: token => set(state => {
145
- state.toToken = token;
146
- }),
147
- setInputAmount: amount => set(state => {
148
- state.inputAmount = amount;
149
- if (!!state.fromToken) state.inputUsdValue = getUsdValue(state.fromToken, state.inputAmount);
150
- })
151
- }))));
152
-
153
82
  const httpService = /*#__PURE__*/new rangoSdk.RangoClient(process.env.REACT_API_KEY);
154
83
 
155
- function removeDuplicateFrom(array) {
156
- return Array.from(new Set(array));
157
- }
84
+ const SLIPPAGES = [0.5, 1, 3, 5, 8, 13, 20];
85
+ const DEFAULT_SLIPPAGE = 1;
86
+ const HIGH_SLIPPAGE = 5;
87
+ const MAX_SLIPPAGE = 100;
88
+ const MIN_SLIPPGAE = 0;
158
89
 
159
90
  const useMetaStore = /*#__PURE__*/createSelectors( /*#__PURE__*/zustand.create()(set => ({
160
91
  meta: {
@@ -182,103 +113,87 @@ const useMetaStore = /*#__PURE__*/createSelectors( /*#__PURE__*/zustand.create()
182
113
  }
183
114
  })));
184
115
 
185
- var SearchParams;
186
- (function (SearchParams) {
187
- SearchParams["FROM_CHAIN"] = "fromChain";
188
- SearchParams["FROM_TOKEN"] = "fromToken";
189
- SearchParams["TO_CHAIN"] = "toChain";
190
- SearchParams["TO_TOKEN"] = "toToken";
191
- SearchParams["FROM_AMOUNT"] = "fromAmount";
192
- })(SearchParams || (SearchParams = {}));
193
-
194
- function searchParamsToToken(tokens, searchParams) {
195
- return tokens.find(token => {
196
- const symbolAndAddress = searchParams?.split('--');
197
- if (symbolAndAddress?.length === 1) return token.symbol === symbolAndAddress[0] && token.address === null;
198
- return token.symbol === symbolAndAddress?.[0] && token.address === symbolAndAddress?.[1];
199
- }) || null;
200
- }
201
- function UpdateUrl() {
202
- const firstRender = React.useRef(true);
203
- const [searchParams, setSearchParams] = reactRouterDom.useSearchParams();
204
- const location = reactRouterDom.useLocation();
205
- const fromChain = useBestRouteStore.use.fromChain();
206
- const toChain = useBestRouteStore.use.toChain();
207
- const fromToken = useBestRouteStore.use.fromToken();
208
- const toToken = useBestRouteStore.use.toToken();
209
- const setFromChain = useBestRouteStore.use.setFromChain();
210
- const setFromToken = useBestRouteStore.use.setFromToken();
211
- const setToChain = useBestRouteStore.use.setToChain();
212
- const setToToken = useBestRouteStore.use.setToToken();
213
- const inputAmount = useBestRouteStore.use.inputAmount();
214
- const setInputAmount = useBestRouteStore.use.setInputAmount();
215
- const loadingStatus = useMetaStore.use.loadingStatus();
216
- const {
217
- blockchains,
218
- tokens
219
- } = useMetaStore.use.meta();
220
- React.useEffect(() => {
221
- if (!firstRender.current) {
222
- const fromChainString = fromChain?.name || '';
223
- const fromTokenString = (fromToken?.symbol || '') + (fromToken?.address ? `--${fromToken?.address}` : '');
224
- const toChainString = toChain?.name || '';
225
- const toTokenString = (toToken?.symbol || '') + (toToken?.address ? `--${toToken?.address}` : '');
226
- const fromAmount = inputAmount;
227
- setSearchParams({
228
- ...(fromChainString && {
229
- [SearchParams.FROM_CHAIN]: fromChainString
230
- }),
231
- ...(fromTokenString && {
232
- [SearchParams.FROM_TOKEN]: fromTokenString
233
- }),
234
- ...(toChainString && {
235
- [SearchParams.TO_CHAIN]: toChainString
236
- }),
237
- ...(toTokenString && {
238
- [SearchParams.TO_TOKEN]: toTokenString
239
- }),
240
- ...(fromAmount && {
241
- [SearchParams.FROM_AMOUNT]: fromAmount.toString()
242
- })
243
- }, {
244
- replace: true
245
- });
246
- }
247
- firstRender.current = false;
248
- }, [location.pathname, inputAmount]);
249
- React.useEffect(() => {
250
- if (loadingStatus === 'success') {
251
- const fronChainString = searchParams.get(SearchParams.FROM_CHAIN);
252
- const fromTokenString = searchParams.get(SearchParams.FROM_TOKEN);
253
- const toChainString = searchParams.get(SearchParams.TO_CHAIN);
254
- const toTokenString = searchParams.get(SearchParams.TO_TOKEN);
255
- const fromAmount = searchParams.get(SearchParams.FROM_AMOUNT);
256
- const fromChain = blockchains.find(blockchain => blockchain.name === fronChainString);
257
- const fromToken = searchParamsToToken(tokens, fromTokenString);
258
- const toChain = blockchains.find(blockchain => blockchain.name === toChainString);
259
- const toToken = searchParamsToToken(tokens, toTokenString);
260
- if (!!fromChain) {
261
- setFromChain(fromChain);
262
- if (!!fromToken) setFromToken(fromToken);
263
- }
264
- if (!!toChain) {
265
- setToChain(toChain);
266
- if (!!toToken) setToToken(toToken);
267
- }
268
- if (fromAmount) setInputAmount(fromAmount);
116
+ const useSettingsStore = /*#__PURE__*/createSelectors( /*#__PURE__*/zustand.create()( /*#__PURE__*/middleware.persist( /*#__PURE__*/middleware.subscribeWithSelector(set => ({
117
+ slippage: DEFAULT_SLIPPAGE,
118
+ customSlippage: null,
119
+ infiniteApprove: false,
120
+ disabledLiquiditySources: [],
121
+ theme: 'auto',
122
+ setSlippage: slippage => set(() => ({
123
+ slippage: slippage
124
+ })),
125
+ setCustomSlippage: customSlippage => set(() => ({
126
+ customSlippage: customSlippage
127
+ })),
128
+ toggleAllLiquiditySources: () => set(state => {
129
+ const {
130
+ swappers
131
+ } = useMetaStore.getState().meta;
132
+ const swappersGroup = removeDuplicateFrom(swappers.map(swapper => swapper.swapperGroup));
133
+ if (swappersGroup.length === state.disabledLiquiditySources.length) return {
134
+ disabledLiquiditySources: []
135
+ };else {
136
+ return {
137
+ disabledLiquiditySources: swappersGroup
138
+ };
269
139
  }
270
- }, [loadingStatus]);
271
- return null;
272
- }
140
+ }),
141
+ toggleInfiniteApprove: () => set(state => ({
142
+ infiniteApprove: !state.infiniteApprove
143
+ })),
144
+ toggleLiquiditySource: name => set(state => {
145
+ if (state.disabledLiquiditySources.includes(name)) return {
146
+ disabledLiquiditySources: state.disabledLiquiditySources.filter(liquiditySource => liquiditySource != name)
147
+ };else return {
148
+ disabledLiquiditySources: state.disabledLiquiditySources.concat(name)
149
+ };
150
+ }),
151
+ setTheme: theme => set(() => ({
152
+ theme
153
+ }))
154
+ })), {
155
+ name: 'user-settings'
156
+ })));
273
157
 
274
- function AppRouter(_ref) {
275
- let {
276
- children
277
- } = _ref;
278
- const isRouterInContext = reactRouter.useInRouterContext();
279
- const Router = isRouterInContext ? React.Fragment : reactRouter.MemoryRouter;
280
- return React__default.createElement(React__default.Fragment, null, React__default.createElement(Router, null, children), isRouterInContext && React__default.createElement(UpdateUrl, null));
281
- }
158
+ const secondsToString = s => {
159
+ const seconds = (s % 60).toString().padStart(2, '0');
160
+ const minutes = parseInt((s / 60).toString()).toString().padStart(2, '0');
161
+ return `${minutes}:${seconds}`;
162
+ };
163
+ const numberToString = function (number, minDecimals, maxDecimals) {
164
+ if (minDecimals === void 0) {
165
+ minDecimals = null;
166
+ }
167
+ if (maxDecimals === void 0) {
168
+ maxDecimals = null;
169
+ }
170
+ if (number === null) return '';
171
+ if (number === '') return '';
172
+ const n = new BigNumber.BigNumber(number);
173
+ const roundingMode = 1;
174
+ let maxI = 1000;
175
+ for (let i = 0; i < 60; i++) {
176
+ if (new BigNumber.BigNumber(n.toFixed(i, roundingMode)).eq(n)) {
177
+ maxI = i;
178
+ break;
179
+ }
180
+ }
181
+ if (n.gte(10000)) return n.toFormat(0, roundingMode);
182
+ if (n.gte(1000)) return n.toFormat(Math.min(maxI, Math.min(maxDecimals || 100, Math.max(minDecimals || 0, 1))), roundingMode);
183
+ if (n.gte(100)) return n.toFormat(Math.min(maxI, Math.min(maxDecimals || 100, Math.max(minDecimals || 0, 1))), roundingMode);
184
+ if (n.gte(1)) return n.toFormat(Math.min(maxI, Math.min(maxDecimals || 100, Math.max(minDecimals || 0, 2))), roundingMode);
185
+ if (n.gte(0.01)) return n.toFormat(Math.min(maxI, Math.min(maxDecimals || 100, Math.max(minDecimals || 0, 4))), roundingMode);
186
+ for (let i = minDecimals || 4; i < 17; i++) if (n.gte(Math.pow(10, -i))) return n.toFormat(Math.min(maxI, Math.min(maxDecimals || 100, Math.max(minDecimals || 0, i))), roundingMode);
187
+ if (n.isEqualTo(0)) return '0';
188
+ return n.toFormat(Math.min(maxI, Math.min(maxDecimals || 100, Math.max(minDecimals || 0, 8))), roundingMode);
189
+ };
190
+ const totalArrivalTime = data => data?.result?.swaps?.reduce((a, b) => a + b.estimatedTimeInSeconds, 0) || 0;
191
+ const decimalNumber = function (number, toFixed) {
192
+ if (number === void 0) {
193
+ number = '0';
194
+ }
195
+ return parseFloat(number).toFixed(toFixed);
196
+ };
282
197
 
283
198
  function getStateWallet(state) {
284
199
  switch (true) {
@@ -374,7 +289,7 @@ function getRequiredChains(route) {
374
289
  });
375
290
  return wallets;
376
291
  }
377
- function getSelectableWallets(accounts, selectedWallets, getWalletInfo, requiredChains) {
292
+ function getSelectableWallets(accounts, selectedWallets, getWalletInfo) {
378
293
  const connectedWallets = accounts.map(account => ({
379
294
  address: account.address,
380
295
  walletType: account.walletType,
@@ -383,12 +298,8 @@ function getSelectableWallets(accounts, selectedWallets, getWalletInfo, required
383
298
  name: getWalletInfo(account.walletType).name,
384
299
  selected: !!selectedWallets.find(wallet => wallet.chain === account.chain && wallet.walletType === account.walletType)
385
300
  }));
386
- return requiredChains ? connectedWallets.filter((wallet, index, array) => requiredChains.includes(wallet.chain) && array.findIndex(w => w.address === wallet.address) === index) : removeDuplicateWallets(connectedWallets, 'walletType');
301
+ return connectedWallets;
387
302
  }
388
- const removeDuplicateWallets = (arr, key) => {
389
- const map = new Map(arr.map(item => [item[key], item]));
390
- return Array.from(map.values());
391
- };
392
303
  function getBalanceFromWallet(balances, chain, symbol, address) {
393
304
  if (balances.length === 0) return null;
394
305
  const selectedChainBalances = balances.filter(balance => balance.chain === chain);
@@ -487,540 +398,1393 @@ const getKeplrCompatibleConnectedWallets = selectableWallets => {
487
398
  return walletsShared.KEPLR_COMPATIBLE_WALLETS.filter(compatibleWallet => connectedWalletTypes.has(compatibleWallet));
488
399
  };
489
400
 
490
- const useWalletsStore = /*#__PURE__*/createSelectors( /*#__PURE__*/zustand.create()(set => ({
491
- accounts: [],
492
- balances: [],
493
- selectedWallets: [],
494
- connectWallet: accounts => {
495
- const tokens = useMetaStore.getState().meta.tokens;
496
- set(state => ({
497
- accounts: state.accounts.concat(accounts),
498
- balances: state.balances.concat(accounts.map(account => ({
499
- balances: [],
500
- address: account.address,
501
- chain: account.chain,
502
- loading: true,
503
- walletType: account.walletType,
504
- error: false,
505
- explorerUrl: null
506
- })))
507
- }));
508
- accounts.forEach(async account => {
509
- try {
510
- const response = await httpService.getWalletsDetails([{
511
- address: account.address,
512
- blockchain: account.chain
513
- }]);
514
- const retrivedBalance = response.wallets[0];
515
- if (retrivedBalance) {
516
- set(state => ({
517
- balances: state.balances.map(balance => {
518
- return isAccountAndBalanceMatched(account, balance) ? makeBalanceFor(account, retrivedBalance, tokens) : balance;
519
- })
520
- }));
521
- } else throw new Error('Wallet not found');
522
- } catch (error) {
523
- set(state => ({
524
- balances: state.balances.map(balance => {
525
- return isAccountAndBalanceMatched(account, balance) ? resetBalanceState(balance) : balance;
526
- })
527
- }));
528
- }
529
- });
530
- },
531
- disconnectWallet: walletType => {
532
- set(state => ({
533
- accounts: state.accounts.filter(account => account.walletType !== walletType),
534
- balances: state.balances.filter(balance => balance.walletType !== walletType),
535
- selectedWallets: state.selectedWallets.filter(wallet => wallet.walletType != walletType)
536
- }));
537
- },
538
- initSelectedWallets: () => set(state => {
539
- const requiredChains = getRequiredChains(useBestRouteStore.getState().bestRoute);
540
- const connectedWallets = state.accounts;
541
- const selectedWallets = [];
542
- requiredChains.forEach(chain => {
543
- const anyWalletSelected = !!state.selectedWallets.find(wallet => wallet.chain === chain);
544
- if (!anyWalletSelected) {
545
- const firstWalletWithMatchedChain = connectedWallets.find(wallet => wallet.chain === chain);
546
- if (!!firstWalletWithMatchedChain) selectedWallets.push({
547
- address: firstWalletWithMatchedChain.address,
548
- chain: firstWalletWithMatchedChain.chain,
549
- walletType: firstWalletWithMatchedChain.walletType
550
- });
551
- }
552
- });
553
- return {
554
- selectedWallets: state.selectedWallets.concat(selectedWallets)
555
- };
556
- }),
557
- setSelectedWallet: wallet => set(state => ({
558
- selectedWallets: state.selectedWallets.filter(selectedWallet => selectedWallet.chain !== wallet.chain).concat({
559
- chain: wallet.chain,
560
- address: wallet.address,
561
- walletType: wallet.walletType
562
- })
563
- }))
564
- })));
565
-
566
- const navigationRoutes = {
567
- home: '/',
568
- fromChain: '/from-chain',
569
- fromToken: '/from-token',
570
- toChain: '/to-chain',
571
- toToken: '/to-token',
572
- settings: '/settings',
573
- liquiditySources: '/liquidity-sources',
574
- history: '/history',
575
- wallets: '/wallets',
576
- confirmSwap: '/confirm-swap',
577
- confirmWallets: '/confirm-wallets',
578
- swapDetails: '/swap-details'
579
- };
580
-
581
- const useSettingsStore = /*#__PURE__*/createSelectors( /*#__PURE__*/zustand.create()( /*#__PURE__*/middleware.persist( /*#__PURE__*/immer.immer(set => ({
582
- slippage: 1,
583
- customSlippage: null,
584
- infinitApprove: false,
585
- disabledLiquiditySources: [],
586
- theme: 'auto',
587
- setSlippage: slippage => set(state => {
588
- state.slippage = slippage;
589
- }),
590
- setCustomSlippage: customSlippage => {
591
- return set(state => {
592
- state.customSlippage = customSlippage;
593
- });
594
- },
595
- toggleAllLiquiditySources: () => set(state => {
596
- const {
597
- swappers
598
- } = useMetaStore.getState().meta;
599
- if (swappers.length - state.disabledLiquiditySources.length === 0) state.disabledLiquiditySources = [];else {
600
- const allSwappers = swappers.map(swapper => swapper.swapperGroup);
601
- state.disabledLiquiditySources = allSwappers;
401
+ function getOutputRatio(inputUsdValue, outputUsdValue) {
402
+ if (inputUsdValue.lte(ZERO) || outputUsdValue.lte(ZERO)) return 0;
403
+ return outputUsdValue.div(inputUsdValue).minus(1).multipliedBy(100);
404
+ }
405
+ function outputRatioHasWarning(inputUsdValue, outputRatio) {
406
+ return parseInt(outputRatio.toFixed(2) || '0') <= -10 && inputUsdValue.gte(new BigNumber__default(400)) || parseInt(outputRatio.toFixed(2) || '0') <= -5 && inputUsdValue.gte(new BigNumber__default(1000));
407
+ }
408
+ function hasLimitError(bestRoute) {
409
+ return (bestRoute?.result?.swaps || []).filter(swap => {
410
+ const minimum = !!swap.fromAmountMinValue ? new BigNumber__default(swap.fromAmountMinValue) : null;
411
+ const maximum = !!swap.fromAmountMaxValue ? new BigNumber__default(swap.fromAmountMaxValue) : null;
412
+ const isExclusive = swap.fromAmountRestrictionType === 'EXCLUSIVE';
413
+ if (isExclusive) {
414
+ return minimum?.gte(swap.fromAmount) || maximum?.lte(swap.fromAmount);
415
+ } else {
416
+ return minimum?.gt(swap.fromAmount) || maximum?.lt(swap.fromAmount);
602
417
  }
603
- }),
604
- toggleInfinitApprove: () => set(state => {
605
- state.infinitApprove = !state.infinitApprove;
606
- }),
607
- toggleLiquiditySource: name => set(state => {
608
- state.disabledLiquiditySources = state.disabledLiquiditySources.includes(name) ? state.disabledLiquiditySources.filter(liquiditySource => liquiditySource != name) : state.disabledLiquiditySources.concat(name);
609
- }),
610
- setTheme: theme => set(state => {
611
- state.theme = theme;
612
- })
613
- })), {
614
- name: 'user-settings'
615
- })));
616
-
617
- // import { WalletType } from '@rango-dev/wallets-shared';
618
- function useConfirmSwap() {
619
- const fromToken = useBestRouteStore.use.fromToken();
620
- const toToken = useBestRouteStore.use.toToken();
621
- const inputAmount = useBestRouteStore.use.inputAmount();
622
- const bestRoute = useBestRouteStore.use.bestRoute();
623
- const setBestRoute = useBestRouteStore.use.setBestRoute();
624
- const accounts = useWalletsStore.use.accounts();
625
- const selectedWallets = useWalletsStore.use.selectedWallets();
626
- const slippage = useSettingsStore.use.slippage();
627
- const disabledLiquiditySources = useSettingsStore.use.disabledLiquiditySources();
628
- const [loading, setLoading] = React.useState(false);
629
- const [error, setError] = React.useState('');
630
- const [warning, setWarning] = React.useState('');
631
- const [data, setData] = React.useState(null);
632
- const [feeStatus, setFeeStatus] = React.useState(null);
633
- const [bestRouteChanged, setBestRouteChanged] = React.useState(false);
634
- const [enoughBalance, setEnoughBalance] = React.useState(null);
635
- const hasEnoughBalanceOrProperSlippage = (route, selectedWallets, userSlippage, routeChanged) => {
636
- const fee = route.validationStatus;
637
- if (fee === null || fee.length === 0) return {
638
- balance: true,
639
- slippage: true,
640
- routeChanged
641
- };
642
- for (const wallet of selectedWallets) {
643
- const requiredAssets = getRequiredBalanceOfWallet(wallet, fee);
644
- if (!requiredAssets) continue;
645
- const hasEnoughBalance = requiredAssets?.map(it => it.ok).reduce((a, b) => a && b);
646
- if (!hasEnoughBalance) return {
647
- balance: false,
648
- slippage: true,
649
- routeChanged
650
- };
418
+ }).length > 0;
419
+ }
420
+ function LimitErrorMessage(bestRoute) {
421
+ if (!bestRoute) return {
422
+ swap: null,
423
+ fromAmountRangeError: '',
424
+ recommendation: ''
425
+ };
426
+ const swap = (bestRoute?.result?.swaps || []).filter(swap => {
427
+ const minimum = !!swap.fromAmountMinValue ? new BigNumber__default(swap.fromAmountMinValue) : null;
428
+ const maximum = !!swap.fromAmountMaxValue ? new BigNumber__default(swap.fromAmountMaxValue) : null;
429
+ const isExclusive = swap.fromAmountRestrictionType === 'EXCLUSIVE';
430
+ if (isExclusive) {
431
+ return minimum?.gte(swap.fromAmount) || maximum?.lte(swap.fromAmount);
432
+ } else {
433
+ return minimum?.gt(swap.fromAmount) || maximum?.lt(swap.fromAmount);
651
434
  }
652
- const slippages = route.result?.swaps?.map(s => s.recommendedSlippage);
653
- const slippageError = (slippages?.filter(s => !!s?.error)?.length || 0) > 0;
654
- const minSlippage = slippages?.map(s => parseFloat(s?.slippage.toString() || '0') || 0).filter(s => s > 0).sort((a, b) => b - a).find(() => true) || null;
655
- if (slippageError) {
656
- setError('Server cannot calculated required slippage for your swap');
657
- return {
658
- balance: true,
659
- slippage: false,
660
- routeChanged
661
- };
662
- } else if (minSlippage !== null && minSlippage > parseFloat(userSlippage)) {
663
- setError(`Your slippage should be ${minSlippage} at least`);
435
+ })[0];
436
+ if (!swap) return {
437
+ swap: null,
438
+ fromAmountRangeError: '',
439
+ recommendation: ''
440
+ };
441
+ const minimum = !!swap.fromAmountMinValue ? new BigNumber__default(swap.fromAmountMinValue) : null;
442
+ const maximum = !!swap.fromAmountMaxValue ? new BigNumber__default(swap.fromAmountMaxValue) : null;
443
+ const isExclusive = swap.fromAmountRestrictionType === 'EXCLUSIVE';
444
+ let fromAmountRangeError = '';
445
+ let recommendation = '';
446
+ if (!isExclusive && !!minimum && minimum.gt(swap.fromAmount)) {
447
+ fromAmountRangeError = `Required: >= ${numberToString(minimum)} ${swap.from.symbol}`;
448
+ recommendation = 'Increase your swap amount';
449
+ } else if (isExclusive && !!minimum && minimum.gte(swap.fromAmount)) {
450
+ fromAmountRangeError = `Required: > ${numberToString(minimum)} ${swap.from.symbol}`;
451
+ recommendation = 'Increase your swap amount';
452
+ }
453
+ if (!isExclusive && !!maximum && maximum.lt(swap.fromAmount)) {
454
+ fromAmountRangeError = `Required: <= ${numberToString(maximum)} ${swap.from.symbol}`;
455
+ recommendation = 'Decrease your swap amount';
456
+ } else if (isExclusive && !!maximum && maximum.lte(swap.fromAmount)) {
457
+ fromAmountRangeError = `Required: < ${numberToString(maximum)} ${swap.from.symbol}`;
458
+ recommendation = 'Decrease your swap amount';
459
+ }
460
+ return {
461
+ swap,
462
+ fromAmountRangeError,
463
+ recommendation
464
+ };
465
+ }
466
+ function getSwapButtonState(loadingMetaStatus, accounts, loading, bestRoute, hasLimitError, highValueLoss, priceImpactCanNotBeComputed, needsToWarnEthOnPath) {
467
+ if (loadingMetaStatus !== 'success') return {
468
+ title: 'Connect Wallet',
469
+ disabled: true
470
+ };
471
+ if (accounts.length == 0) return {
472
+ title: 'Connect Wallet',
473
+ disabled: false
474
+ };
475
+ if (loading) return {
476
+ title: 'Finding Best Route...',
477
+ disabled: true
478
+ };else if (!bestRoute) return {
479
+ title: 'Swap',
480
+ disabled: true
481
+ };else if (hasLimitError) return {
482
+ title: 'Limit Error',
483
+ disabled: true
484
+ };else if (highValueLoss) return {
485
+ title: 'Price impact is too high!',
486
+ disabled: true
487
+ };else if (priceImpactCanNotBeComputed) return {
488
+ title: 'USD price is unknown, price impact might be high!',
489
+ disabled: false,
490
+ hasWarning: true
491
+ };else if (needsToWarnEthOnPath) return {
492
+ title: 'The route goes through Ethereum. Continue?',
493
+ disabled: false,
494
+ hasWarning: true
495
+ };else return {
496
+ title: 'Swap',
497
+ disabled: false
498
+ };
499
+ }
500
+ function canComputePriceImpact(bestRoute, inputAmount, inputUsdValue, outputUsdValue) {
501
+ return !((inputUsdValue.lte(ZERO) || outputUsdValue.lte(ZERO)) && !!bestRoute?.result && !!inputAmount && inputAmount !== '0' && parseFloat(inputAmount || '0') !== 0 && !!bestRoute.result);
502
+ }
503
+ function calculatePendingSwap(inputAmount, bestRoute, wallets, settings, validateBalanceOrFee, meta) {
504
+ const simulationResult = bestRoute.result;
505
+ if (!simulationResult) throw Error('Simulation result should not be null');
506
+ return {
507
+ creationTime: new Date().getTime().toString(),
508
+ finishTime: null,
509
+ requestId: bestRoute.requestId || '',
510
+ inputAmount: inputAmount,
511
+ wallets,
512
+ status: 'running',
513
+ isPaused: false,
514
+ extraMessage: null,
515
+ extraMessageSeverity: null,
516
+ extraMessageDetail: null,
517
+ extraMessageErrorCode: null,
518
+ networkStatusExtraMessage: null,
519
+ networkStatusExtraMessageDetail: null,
520
+ lastNotificationTime: null,
521
+ //@ts-ignore
522
+ settings: settings,
523
+ simulationResult: simulationResult,
524
+ validateBalanceOrFee,
525
+ steps: bestRoute.result?.swaps?.map((swap, index) => {
526
+ const swapper = meta.swappers.find(swapper => swapper.id === swap.swapperId);
527
+ const swapperType = swapper?.types[0];
528
+ const fromBlockchain = meta.blockchains.find(blockchain => blockchain.name === swap.from.blockchain);
529
+ const toBlockchain = meta.blockchains.find(blockchain => blockchain.name === swap.to.blockchain);
664
530
  return {
665
- balance: true,
666
- slippage: false,
667
- routeChanged
531
+ id: index + 1,
532
+ fromBlockchain: swap.from.blockchain,
533
+ fromSymbol: swap.from.symbol,
534
+ fromSymbolAddress: swap.from.address,
535
+ fromDecimals: swap.from.decimals,
536
+ fromAmountPrecision: swap.fromAmountPrecision,
537
+ fromAmountMinValue: swap.fromAmountMinValue,
538
+ fromAmountMaxValue: swap.fromAmountMaxValue,
539
+ toBlockchain: swap.to.blockchain,
540
+ fromLogo: swap.from.logo,
541
+ toSymbol: swap.to.symbol,
542
+ toSymbolAddress: swap.to.address,
543
+ toDecimals: swap.to.decimals,
544
+ toLogo: swap.to.logo,
545
+ startTransactionTime: new Date().getTime(),
546
+ swapperId: swap.swapperId,
547
+ feeInUsd: numberToString(getUsdFeeOfStep(swap, meta.tokens), null, 2),
548
+ expectedOutputAmountHumanReadable: swap.toAmount,
549
+ outputAmount: '',
550
+ status: 'created',
551
+ networkStatus: null,
552
+ executedTransactionId: null,
553
+ externalTransactionId: null,
554
+ explorerUrl: null,
555
+ trackingCode: null,
556
+ cosmosTransaction: null,
557
+ solanaTransaction: null,
558
+ starknetTransaction: null,
559
+ starknetApprovalTransaction: null,
560
+ tronTransaction: null,
561
+ tronApprovalTransaction: null,
562
+ evmTransaction: null,
563
+ evmApprovalTransaction: null,
564
+ transferTransaction: null,
565
+ diagnosisUrl: null,
566
+ internalSteps: null,
567
+ fromBlockchainLogo: fromBlockchain.logo,
568
+ toBlockchainLogo: toBlockchain.logo,
569
+ swapperLogo: swapper?.logo,
570
+ swapperType: swapperType
668
571
  };
669
- }
670
- return {
671
- balance: true,
672
- slippage: true,
673
- routeChanged
674
- };
572
+ }) || []
675
573
  };
676
- const checkFeeAndBalance = async selectedWallets => {
677
- setLoading(true);
678
- setFeeStatus(null);
679
- const selectedWalletsMap = selectedWallets.reduce((selectedWalletsMap, selectedWallet) => (selectedWalletsMap[selectedWallet.chain] = selectedWallet.address, selectedWalletsMap), {});
680
- const connectedWallets = [];
681
- accounts.forEach(account => {
682
- const chainAndAccounts = connectedWallets.find(wallet => wallet.blockchain);
683
- if (!!chainAndAccounts) chainAndAccounts.addresses.push(account.address);else connectedWallets.push({
684
- blockchain: account.chain,
685
- addresses: [account.address]
686
- });
687
- });
688
- const r = await httpService.getBestRoute({
689
- amount: inputAmount.toString(),
690
- checkPrerequisites: true,
691
- from: {
692
- address: fromToken.address,
693
- blockchain: fromToken.blockchain,
694
- symbol: fromToken.symbol
695
- },
696
- to: {
697
- address: toToken.address,
698
- blockchain: toToken.blockchain,
699
- symbol: toToken.symbol
700
- },
701
- connectedWallets,
702
- selectedWallets: selectedWalletsMap,
703
- //@ts-ignore
704
- swapperGroups: disabledLiquiditySources,
705
- swappersGroupsExclude: true
706
- }).catch(error => {
707
- setError(error.message);
708
- setLoading(false);
574
+ }
575
+ function requiredWallets(route) {
576
+ const wallets = [];
577
+ route?.result?.swaps.forEach(swap => {
578
+ const currentStepFromBlockchain = swap.from.blockchain;
579
+ const currentStepToBlockchain = swap.to.blockchain;
580
+ let lastAddedWallet = wallets[wallets.length - 1];
581
+ if (currentStepFromBlockchain != lastAddedWallet) wallets.push(currentStepFromBlockchain);
582
+ lastAddedWallet = wallets[wallets.length - 1];
583
+ if (currentStepToBlockchain != lastAddedWallet) wallets.push(currentStepToBlockchain);
584
+ });
585
+ return wallets;
586
+ }
587
+ const getUsdPrice$1 = (blockchain, symbol, address, allTokens) => {
588
+ const token = allTokens?.find(t => t.blockchain === blockchain && t.symbol?.toUpperCase() === symbol?.toUpperCase() && t.address === address);
589
+ return token?.usdPrice || null;
590
+ };
591
+ function getUsdFeeOfStep(step, allTokens) {
592
+ let totalFeeInUsd = ZERO;
593
+ for (let i = 0; i < step.fee.length; i++) {
594
+ const fee = step.fee[i];
595
+ if (fee.expenseType === 'DECREASE_FROM_OUTPUT') continue;
596
+ const unitPrice = getUsdPrice$1(fee.asset.blockchain, fee.asset.symbol, fee.asset.address, allTokens);
597
+ totalFeeInUsd = totalFeeInUsd.plus(new BigNumber__default(fee.amount).multipliedBy(unitPrice || 0));
598
+ }
599
+ return totalFeeInUsd;
600
+ }
601
+ function getTotalFeeInUsd(bestRoute, allTokens) {
602
+ return bestRoute?.result?.swaps.reduce((totalFee, step) => totalFee.plus(getUsdFeeOfStep(step, allTokens)), ZERO) || null;
603
+ }
604
+ function hasHighFee(totalFeeInUsd) {
605
+ if (!totalFeeInUsd) return false;
606
+ return !totalFeeInUsd.lt(new BigNumber__default(30));
607
+ }
608
+ function getMinRequiredSlippage(route) {
609
+ const slippages = route.result?.swaps.map(slippage => slippage.recommendedSlippage);
610
+ return slippages?.map(s => s?.slippage || 0)?.filter(s => s > 0)?.sort((a, b) => b - a)?.find(() => true) || null;
611
+ }
612
+ function hasProperSlippage(userSlippage, minRequiredSlippage) {
613
+ if (!minRequiredSlippage) return true;
614
+ return parseFloat(userSlippage) > minRequiredSlippage;
615
+ }
616
+ function createBestRouteRequestBody(fromToken, toToken, inputAmount, wallets, selectedWallets, disabledLiquiditySources, slippage, checkPrerequisites) {
617
+ const selectedWalletsMap = selectedWallets.reduce((selectedWalletsMap, selectedWallet) => (selectedWalletsMap[selectedWallet.chain] = selectedWallet.address, selectedWalletsMap), {});
618
+ const connectedWallets = [];
619
+ wallets.forEach(wallet => {
620
+ const chainAndAccounts = connectedWallets.find(connectedWallet => connectedWallet.blockchain === wallet.chain);
621
+ if (!!chainAndAccounts) chainAndAccounts.addresses.push(wallet.address);else connectedWallets.push({
622
+ blockchain: wallet.chain,
623
+ addresses: [wallet.address]
709
624
  });
710
- setLoading(false);
711
- if (!r || !r.result || !bestRoute) return {
712
- bestRoute: null
713
- };
714
- if (!new BigNumber__default(r.requestAmount).isEqualTo(new BigNumber__default(inputAmount || '-1'))) return null;
715
- setFeeStatus(r.validationStatus);
716
- const routeChangeStatus = compareRoutes(bestRoute, r, inputAmount.toString(), fromToken.usdPrice, toToken.usdPrice);
717
- setBestRoute(r);
718
- const isChanged = routeChangeStatus.isChanged;
719
- // const changeWarningMessage = routeChangeStatus.warningMessage;
720
- setBestRouteChanged(isChanged);
721
- setWarning('Best route changed');
722
- setData(r);
625
+ });
626
+ const requestBody = {
627
+ amount: inputAmount.toString(),
628
+ checkPrerequisites,
629
+ from: {
630
+ address: fromToken.address,
631
+ blockchain: fromToken.blockchain,
632
+ symbol: fromToken.symbol
633
+ },
634
+ to: {
635
+ address: toToken.address,
636
+ blockchain: toToken.blockchain,
637
+ symbol: toToken.symbol
638
+ },
639
+ connectedWallets,
640
+ selectedWallets: selectedWalletsMap,
641
+ swapperGroups: disabledLiquiditySources,
642
+ swappersGroupsExclude: true,
643
+ //@ts-ignore
644
+ slippage: slippage.toString()
645
+ };
646
+ return requestBody;
647
+ }
648
+ function getWalletsForNewSwap(selectedWallets) {
649
+ const wallets = selectedWallets.reduce((selectedWalletsMap, selectedWallet) => (selectedWalletsMap[selectedWallet.chain] = {
650
+ address: selectedWallet.address,
651
+ walletType: selectedWallet.walletType
652
+ }, selectedWalletsMap), {});
653
+ return wallets;
654
+ }
655
+ function getRouteOutputAmount(route) {
656
+ return route.result?.outputAmount || null;
657
+ }
658
+ function getPercentageChange(oldValue, newValue) {
659
+ return new BigNumber__default(newValue).div(new BigNumber__default(oldValue)).minus(1).multipliedBy(100);
660
+ }
661
+ function isOutputAmountChangedALot(oldRoute, newRoute) {
662
+ const oldOutputAmount = getRouteOutputAmount(oldRoute);
663
+ const newOutputAmount = getRouteOutputAmount(newRoute);
664
+ if (!oldOutputAmount || !newOutputAmount) return false;
665
+ const percentageChange = getPercentageChange(oldOutputAmount, newOutputAmount);
666
+ return percentageChange.toNumber() <= -1;
667
+ }
668
+ function getBalanceWarnings(route, selectedWallets) {
669
+ const fee = route.validationStatus;
670
+ const requiredWallets = getRequiredChains(route);
671
+ const walletsSortedByRequiredWallets = selectedWallets.sort((selectedWallet1, selectedWallet2) => requiredWallets.indexOf(selectedWallet1.chain) - requiredWallets.indexOf(selectedWallet2.chain));
672
+ return walletsSortedByRequiredWallets.flatMap(wallet => getRequiredBalanceOfWallet(wallet, fee) || []).filter(asset => !asset.ok).map(asset => {
673
+ const symbol = asset.asset.symbol;
674
+ const currentAmount = numberToString(new BigNumber__default(asset.currentAmount.amount).shiftedBy(-asset.currentAmount.decimals), 8);
675
+ const requiredAmount = numberToString(new BigNumber__default(asset.requiredAmount.amount).shiftedBy(-asset.requiredAmount.decimals), 8);
676
+ let reason = '';
677
+ if (asset.reason === 'FEE') reason = ' for network fee';
678
+ if (asset.reason === 'INPUT_ASSET') reason = ' for swap';
679
+ if (asset.reason === 'FEE_AND_INPUT_ASSET') reason = ' for input and network fee';
680
+ const warningMessage = `Needs ≈ ${requiredAmount} ${symbol}${reason}, but you have ${currentAmount} ${symbol} in your ${asset.asset.blockchain} wallet.`;
681
+ return warningMessage;
682
+ });
683
+ }
684
+
685
+ const getUsdValue = (token, amount) => new BigNumber__default(amount || ZERO).multipliedBy(token?.usdPrice || 0);
686
+ const useBestRouteStore = /*#__PURE__*/createSelectors( /*#__PURE__*/zustand.create()( /*#__PURE__*/middleware.subscribeWithSelector(set => ({
687
+ fromChain: null,
688
+ fromToken: null,
689
+ inputAmount: '',
690
+ outputAmount: null,
691
+ inputUsdValue: new BigNumber__default(0),
692
+ outputUsdValue: new BigNumber__default(0),
693
+ toChain: null,
694
+ toToken: null,
695
+ bestRoute: null,
696
+ loading: false,
697
+ error: '',
698
+ setBestRoute: bestRoute => set(state => {
699
+ let outputAmount = null;
700
+ let outputUsdValue = ZERO;
701
+ if (!!bestRoute) {
702
+ outputAmount = !!bestRoute.result?.outputAmount ? new BigNumber__default(bestRoute.result?.outputAmount) : null;
703
+ outputUsdValue = new BigNumber__default(outputAmount || ZERO).multipliedBy(getBestRouteToTokenUsdPrice(bestRoute) || state.toToken?.usdPrice || 0);
704
+ }
723
705
  return {
724
- hasEnoughBalanceOrSlippage: hasEnoughBalanceOrProperSlippage(r, selectedWallets, slippage.toString(), isChanged),
725
- bestRoute: r
706
+ bestRoute,
707
+ ...(!!bestRoute && {
708
+ outputAmount,
709
+ outputUsdValue
710
+ })
726
711
  };
727
- };
728
- const swap = () => {
729
- if (!bestRoute) return;
730
- if (inputAmount.toString() === '') return;
731
- // const wallets = selectedWallets.reduce(
732
- // (
733
- // selectedWalletsMap: { [p: string]: { address: string; walletType: WalletType } },
734
- // selectedWallet,
735
- // ) => (
736
- // (selectedWalletsMap[selectedWallet.chain] = {
737
- // address: selectedWallet.address,
738
- // walletType: selectedWallet.walletType,
739
- // }),
740
- // selectedWalletsMap
741
- // ),
742
- // {},
743
- // );
744
- const proceedAnyway = enoughBalance !== null;
745
- // const settings: SwapSavedSettings = {
746
- // slippage: slippage.toString(),
747
- // disabledSwappersGroups: ['Osmosis'],
748
- // disabledSwappersIds: [],
749
- // };
750
- // if (proceedAnyway) {
751
- // const newSwap: PendingSwap = calculatePendingSwap(
752
- // inputAmount!.toString(),
753
- // bestRoute,
754
- // wallets,
755
- // settings,
756
- // false,
757
- // );
758
- // }
759
- !proceedAnyway && checkFeeAndBalance(selectedWallets).then(data => {
760
- if (!data) {
761
- setError('confirm swap error');
762
- return;
763
- }
764
- if (!data.bestRoute) {
765
- setError('confirm swap error');
766
- return;
767
- } else {
768
- // @ts-ignore
769
- const {
770
- hasEnoughBalanceOrSlippage
771
- } = data;
772
- if (!hasEnoughBalanceOrSlippage) {
773
- return;
774
- }
775
- setEnoughBalance(hasEnoughBalanceOrSlippage.balance && hasEnoughBalanceOrSlippage.slippage);
776
- if (hasEnoughBalanceOrSlippage.balance && hasEnoughBalanceOrSlippage.slippage && !hasEnoughBalanceOrSlippage.routeChanged) ; else if (!hasEnoughBalanceOrSlippage.balance) {
777
- setError('not enough balance');
778
- }
779
- }
712
+ }),
713
+ setFromChain: chain => set(() => ({
714
+ fromChain: chain
715
+ })),
716
+ setFromToken: token => set(state => ({
717
+ fromToken: token,
718
+ ...(!!state.inputAmount && {
719
+ inputUsdValue: getUsdValue(token, state.inputAmount)
720
+ })
721
+ })),
722
+ setToChain: chain => set(() => ({
723
+ toChain: chain
724
+ })),
725
+ setToToken: token => set(() => ({
726
+ toToken: token
727
+ })),
728
+ setInputAmount: amount => set(state => ({
729
+ inputAmount: amount,
730
+ ...(!!state.fromToken && {
731
+ inputUsdValue: getUsdValue(state.fromToken, amount)
732
+ })
733
+ }))
734
+ }))));
735
+ const bestRoute = (bestRouteStore, settingsStore) => {
736
+ let abortController = null;
737
+ const fetchBestRoute = () => {
738
+ const {
739
+ fromToken,
740
+ toToken,
741
+ inputAmount
742
+ } = bestRouteStore.getState();
743
+ const {
744
+ slippage,
745
+ customSlippage,
746
+ disabledLiquiditySources
747
+ } = settingsStore.getState();
748
+ if (!fromToken || !toToken || !inputAmount) return;
749
+ abortController?.abort();
750
+ abortController = new AbortController();
751
+ const userSlippage = customSlippage | slippage;
752
+ const requestBody = createBestRouteRequestBody(fromToken, toToken, inputAmount, [], [], disabledLiquiditySources, userSlippage, false);
753
+ bestRouteStore.setState({
754
+ loading: true,
755
+ bestRoute: null
756
+ });
757
+ httpService.getBestRoute(requestBody, {
758
+ signal: abortController.signal
759
+ }).then(res => {
760
+ const {
761
+ setBestRoute
762
+ } = bestRouteStore.getState();
763
+ setBestRoute(res);
764
+ bestRouteStore.setState({
765
+ loading: false
766
+ });
767
+ abortController = null;
780
768
  }).catch(error => {
781
- console.log('unexpected error', error);
769
+ if (error.code === 'ERR_CANCELED') return;
770
+ bestRouteStore.setState({
771
+ error: error.message,
772
+ loading: false
773
+ });
782
774
  });
783
775
  };
776
+ useBestRouteStore.subscribe(state => ({
777
+ fromChain: state.fromChain,
778
+ fromToken: state.fromToken,
779
+ toChain: state.toChain,
780
+ toToken: state.toToken,
781
+ inputAmount: state.inputAmount
782
+ }), fetchBestRoute.bind(null), {
783
+ equalityFn: (prevState, state) => {
784
+ if (prevState.fromChain?.name !== state.fromChain?.name || prevState.toChain?.name !== state.toChain?.name || prevState.fromToken?.symbol !== state.fromToken?.symbol || prevState.toToken?.symbol !== state.toToken?.symbol || prevState.fromToken?.blockchain !== state.fromToken?.blockchain || prevState.toToken?.blockchain !== state.toToken?.blockchain || prevState.fromToken?.address !== state.fromToken?.address || prevState.toToken?.address !== state.toToken?.address || prevState.inputAmount !== state.inputAmount) return false;else return true;
785
+ }
786
+ });
787
+ useSettingsStore.subscribe(state => ({
788
+ slippage: state.slippage,
789
+ customSlippage: state.customSlippage,
790
+ disabledLiquiditySources: state.disabledLiquiditySources
791
+ }), fetchBestRoute.bind(null), {
792
+ equalityFn: (prevState, state) => {
793
+ if (prevState.slippage !== state.slippage || prevState.customSlippage !== state.customSlippage || prevState.disabledLiquiditySources.length !== state.disabledLiquiditySources.length) return false;else return true;
794
+ }
795
+ });
784
796
  return {
785
- loading,
786
- error,
787
- data,
788
- warning,
789
- feeStatus,
790
- bestRouteChanged,
791
- enoughBalance,
792
- swap
797
+ fetchBestRoute
793
798
  };
794
- }
799
+ };
800
+ const {
801
+ fetchBestRoute
802
+ } = /*#__PURE__*/bestRoute(useBestRouteStore, useSettingsStore);
795
803
 
796
- function ConfirmSwapPage() {
797
- const navigate = reactRouterDom.useNavigate();
798
- const bestRoute = useBestRouteStore.use.bestRoute();
799
- const {
800
- error,
801
- loading,
802
- warning,
803
- swap
804
- } = useConfirmSwap();
805
- return React__default.createElement(ui.ConfirmSwap, {
806
- onConfirm: swap.bind(null),
807
- onBack: navigate.bind(null, -1),
808
- bestRoute: bestRoute,
809
- loading: loading,
810
- error: error,
811
- warning: warning
812
- });
813
- }
804
+ var SearchParams;
805
+ (function (SearchParams) {
806
+ SearchParams["FROM_CHAIN"] = "fromChain";
807
+ SearchParams["FROM_TOKEN"] = "fromToken";
808
+ SearchParams["TO_CHAIN"] = "toChain";
809
+ SearchParams["TO_TOKEN"] = "toToken";
810
+ SearchParams["FROM_AMOUNT"] = "fromAmount";
811
+ })(SearchParams || (SearchParams = {}));
814
812
 
815
- const pendingSwap = [{
816
- creationTime: '1673164511955',
817
- finishTime: '1673164550137',
818
- requestId: '51e211d9-d61c-45d2-a4d4-1f9f7f90ee85',
819
- inputAmount: '1',
820
- wallets: {
821
- OSMOSIS: {
822
- walletType: 'keplr',
823
- address: 'osmo1unf2rcytjxfpz8x8ar63h4qeftadptg5t0nqcl'
824
- }
825
- },
826
- status: 'running',
827
- isPaused: false,
828
- extraMessage: null,
829
- extraMessageSeverity: 'info',
830
- extraMessageDetail: '',
831
- extraMessageErrorCode: null,
832
- networkStatusExtraMessage: null,
833
- networkStatusExtraMessageDetail: null,
834
- lastNotificationTime: null,
835
- settings: {
836
- slippage: '1.0',
837
- disabledSwappersIds: [],
838
- disabledSwappersGroups: []
839
- },
840
- simulationResult: {
841
- outputAmount: '1.540670',
842
- swaps: [{
843
- swapperId: 'Osmosis',
844
- swapperType: 'DEX',
845
- swapperLogo: '',
846
- // @ts-ignore
847
- result: null,
848
- from: {
849
- symbol: 'JUNO',
850
- logo: 'https://api.rango.exchange/tokens/COSMOS/JUNO.png',
851
- address: 'ibc/46b44899322f3cd854d2d46deef881958467cdd4b3b10086da49296bbed94bed',
852
- blockchain: 'OSMOSIS',
853
- blockchainLogo: '',
854
- decimals: 6,
855
- usdPrice: 1.1091996179668873
856
- },
857
- to: {
858
- symbol: 'OSMO',
859
- logo: 'https://api.rango.exchange/i/mJQPS2',
860
- address: null,
861
- blockchain: 'OSMOSIS',
862
- decimals: 6,
863
- blockchainLogo: '',
864
- usdPrice: 0.7192435454440882
865
- },
866
- fromAmount: '1.000000',
867
- fromAmountPrecision: null,
868
- fromAmountMinValue: null,
869
- fromAmountMaxValue: null,
870
- toAmount: '1.540670',
871
- fee: [{
872
- name: '',
873
- asset: {
874
- blockchain: 'OSMOSIS',
875
- symbol: 'OSMO',
876
- address: null
877
- },
878
- expenseType: 'FROM_SOURCE_WALLET',
879
- amount: '0'
880
- }],
881
- estimatedTimeInSeconds: 45,
882
- swapChainType: 'INTRA_CHAIN',
883
- routes: [{
884
- nodes: [{
885
- nodes: [{
886
- marketName: 'pool#498',
887
- marketId: null,
888
- percent: 1
889
- }],
890
- from: 'JUNO',
891
- fromLogo: 'https://api.rango.exchange/tokens/COSMOS/JUNO.png',
892
- fromAddress: 'ibc/46b44899322f3cd854d2d46deef881958467cdd4b3b10086da49296bbed94bed',
893
- fromBlockchain: 'OSMOSIS',
894
- to: 'ATOM',
895
- toLogo: 'https://api.rango.exchange/tokens/COSMOS/ATOM.png',
896
- toAddress: 'ibc/27394fb092d2eccd56123c74f36e4c1f926001ceada9ca97ea622b25f41e5eb2',
897
- toBlockchain: 'OSMOSIS'
898
- }, {
899
- nodes: [{
900
- marketName: 'pool#8',
901
- marketId: null,
902
- percent: 1
903
- }],
904
- from: 'ATOM',
905
- fromLogo: 'https://api.rango.exchange/tokens/COSMOS/ATOM.png',
906
- fromAddress: 'ibc/27394fb092d2eccd56123c74f36e4c1f926001ceada9ca97ea622b25f41e5eb2',
907
- fromBlockchain: 'OSMOSIS',
908
- to: 'IRIS',
909
- toLogo: 'https://api.rango.exchange/tokens/COSMOS/IRIS.png',
910
- toAddress: 'ibc/7c4d60aa95e5a7558b0a364860979ca34b7ff8aaf255b87af9e879374470cec0',
911
- toBlockchain: 'OSMOSIS'
813
+ function searchParamsToToken(tokens, searchParams) {
814
+ return tokens.find(token => {
815
+ const symbolAndAddress = searchParams?.split('--');
816
+ if (symbolAndAddress?.length === 1) return token.symbol === symbolAndAddress[0] && token.address === null;
817
+ return token.symbol === symbolAndAddress?.[0] && token.address === symbolAndAddress?.[1];
818
+ }) || null;
819
+ }
820
+ function UpdateUrl() {
821
+ const firstRender = React.useRef(true);
822
+ const [searchParams, setSearchParams] = reactRouterDom.useSearchParams();
823
+ const location = reactRouterDom.useLocation();
824
+ const firstRenderSearchParams = React.useRef(location.search);
825
+ const searchParamsRef = React.useRef({});
826
+ React.useEffect(() => {
827
+ const params = {};
828
+ reactRouterDom.createSearchParams(firstRenderSearchParams.current).forEach((value, key) => {
829
+ params[key] = value;
830
+ });
831
+ searchParamsRef.current = params;
832
+ }, []);
833
+ const fromChain = useBestRouteStore.use.fromChain();
834
+ const toChain = useBestRouteStore.use.toChain();
835
+ const fromToken = useBestRouteStore.use.fromToken();
836
+ const toToken = useBestRouteStore.use.toToken();
837
+ const setFromChain = useBestRouteStore.use.setFromChain();
838
+ const setFromToken = useBestRouteStore.use.setFromToken();
839
+ const setToChain = useBestRouteStore.use.setToChain();
840
+ const setToToken = useBestRouteStore.use.setToToken();
841
+ const inputAmount = useBestRouteStore.use.inputAmount();
842
+ const setInputAmount = useBestRouteStore.use.setInputAmount();
843
+ const loadingStatus = useMetaStore.use.loadingStatus();
844
+ const {
845
+ blockchains,
846
+ tokens
847
+ } = useMetaStore.use.meta();
848
+ React.useEffect(() => {
849
+ let fromChainString = '',
850
+ fromTokenString = '',
851
+ toChainString = '',
852
+ toTokenString = '',
853
+ fromAmount = '';
854
+ if (loadingStatus !== 'success' && ![navigationRoutes.confirmWallets, navigationRoutes.confirmSwap].includes(location.pathname)) {
855
+ fromChainString = searchParamsRef.current[SearchParams.FROM_CHAIN];
856
+ fromTokenString = searchParamsRef.current[SearchParams.FROM_TOKEN];
857
+ toChainString = searchParamsRef.current[SearchParams.TO_CHAIN];
858
+ toTokenString = searchParamsRef.current[SearchParams.TO_TOKEN];
859
+ fromAmount = searchParamsRef.current[SearchParams.FROM_AMOUNT];
860
+ setSearchParams({
861
+ ...(fromChainString && {
862
+ [SearchParams.FROM_CHAIN]: fromChainString
863
+ }),
864
+ ...(fromTokenString && {
865
+ [SearchParams.FROM_TOKEN]: fromTokenString
866
+ }),
867
+ ...(toChainString && {
868
+ [SearchParams.TO_CHAIN]: toChainString
869
+ }),
870
+ ...(toTokenString && {
871
+ [SearchParams.TO_TOKEN]: toTokenString
872
+ }),
873
+ ...(fromAmount && {
874
+ [SearchParams.FROM_AMOUNT]: fromAmount.toString()
875
+ })
876
+ }, {
877
+ replace: true
878
+ });
879
+ }
880
+ if (!firstRender.current) {
881
+ let fromChainString = '',
882
+ fromTokenString = '',
883
+ toChainString = '',
884
+ toTokenString = '',
885
+ fromAmount = '';
886
+ if (loadingStatus !== 'success') {
887
+ fromChainString = searchParamsRef.current[SearchParams.FROM_CHAIN];
888
+ fromTokenString = searchParamsRef.current[SearchParams.FROM_TOKEN];
889
+ toChainString = searchParamsRef.current[SearchParams.TO_CHAIN];
890
+ toTokenString = searchParamsRef.current[SearchParams.TO_TOKEN];
891
+ fromAmount = searchParamsRef.current[SearchParams.FROM_AMOUNT];
892
+ } else {
893
+ if (location.state === 'redirect') return;
894
+ fromChainString = fromChain?.name || '';
895
+ fromTokenString = (fromToken?.symbol || '') + (fromToken?.address ? `--${fromToken?.address}` : '');
896
+ toChainString = toChain?.name || '';
897
+ toTokenString = (toToken?.symbol || '') + (toToken?.address ? `--${toToken?.address}` : '');
898
+ fromAmount = inputAmount;
899
+ setSearchParams({
900
+ ...(fromChainString && {
901
+ [SearchParams.FROM_CHAIN]: fromChainString
902
+ }),
903
+ ...(fromTokenString && {
904
+ [SearchParams.FROM_TOKEN]: fromTokenString
905
+ }),
906
+ ...(toChainString && {
907
+ [SearchParams.TO_CHAIN]: toChainString
908
+ }),
909
+ ...(toTokenString && {
910
+ [SearchParams.TO_TOKEN]: toTokenString
911
+ }),
912
+ ...(fromAmount && {
913
+ [SearchParams.FROM_AMOUNT]: fromAmount.toString()
914
+ })
912
915
  }, {
913
- nodes: [{
914
- marketName: 'pool#7',
915
- marketId: null,
916
- percent: 1
917
- }],
918
- from: 'IRIS',
919
- fromLogo: 'https://api.rango.exchange/tokens/COSMOS/IRIS.png',
920
- fromAddress: 'ibc/7c4d60aa95e5a7558b0a364860979ca34b7ff8aaf255b87af9e879374470cec0',
921
- fromBlockchain: 'OSMOSIS',
922
- to: 'OSMO',
923
- toLogo: 'https://api.rango.exchange/tokens/COSMOS/OSMO.png',
924
- toAddress: null,
925
- toBlockchain: 'OSMOSIS'
926
- }]
927
- }],
928
- recommendedSlippage: null,
929
- timeStat: {
930
- min: 6,
931
- avg: 40,
932
- max: 241
933
- },
934
- includesDestinationTx: false
935
- }]
936
- },
937
- validateBalanceOrFee: true,
938
- steps: [{
939
- id: 1,
940
- fromBlockchain: 'OSMOSIS',
941
- fromSymbol: 'JUNO',
942
- fromSymbolAddress: 'ibc/46b44899322f3cd854d2d46deef881958467cdd4b3b10086da49296bbed94bed',
943
- fromDecimals: 6,
944
- fromAmountPrecision: null,
945
- fromAmountMinValue: null,
946
- swapperLogo: '',
947
- swapperType: '',
948
- fromAmountMaxValue: null,
949
- toBlockchainLogo: 'https://api.rango.exchange/swappers/osmosis.png',
950
- fromBlockchainLogo: 'https://api.rango.exchange/swappers/osmosis.png',
951
- toBlockchain: 'OSMOSIS',
952
- fromLogo: 'https://api.rango.exchange/tokens/COSMOS/JUNO.png',
953
- toSymbol: 'OSMO',
954
- toSymbolAddress: null,
955
- toDecimals: 6,
956
- toLogo: 'https://api.rango.exchange/i/mJQPS2',
957
- startTransactionTime: 1673164519916,
958
- swapperId: 'Osmosis',
959
- expectedOutputAmountHumanReadable: '1.540670',
960
- outputAmount: '1.540658',
961
- status: 'running',
962
- networkStatus: null,
963
- executedTransactionId: '0f8f17eecc863c2d6be65ef52cfe3128ff3cd7baeddf133160bea8ccdfbf876b',
964
- explorerUrl: [{
965
- url: 'https://www.mintscan.io/osmosis/txs/0f8f17eecc863c2d6be65ef52cfe3128ff3cd7baeddf133160bea8ccdfbf876b',
966
- description: null
967
- }],
968
- cosmosTransaction: {
969
- type: rangoSdk.TransactionType.COSMOS,
970
- fromWalletAddress: 'osmo1unf2rcytjxfpz8x8ar63h4qeftadptg5t0nqcl',
971
- blockChain: 'OSMOSIS',
972
- data: {
973
- chainId: 'osmosis-1',
974
- account_number: 102721,
975
- sequence: '308',
976
- msgs: [{
977
- __type: 'OsmosisSwapMessage',
978
- type: 'osmosis/gamm/swap-exact-amount-in',
979
- value: {
980
- sender: 'osmo1unf2rcytjxfpz8x8ar63h4qeftadptg5t0nqcl',
981
- routes: [{
982
- pool_id: '498',
983
- token_out_denom: 'ibc/27394FB092D2ECCD56123C74F36E4C1F926001CEADA9CA97EA622B25F41E5EB2'
984
- }, {
985
- pool_id: '8',
986
- token_out_denom: 'ibc/7C4D60AA95E5A7558B0A364860979CA34B7FF8AAF255B87AF9E879374470CEC0'
987
- }, {
988
- pool_id: '7',
989
- token_out_denom: 'uosmo'
990
- }],
991
- token_in: {
992
- denom: 'ibc/46B44899322F3CD854D2D46DEEF881958467CDD4B3B10086DA49296BBED94BED',
993
- amount: '1000000'
994
- },
995
- token_out_min_amount: '1525264'
996
- }
997
- }],
998
- protoMsgs: [{
999
- type_url: '/osmosis.gamm.v1beta1.MsgSwapExactAmountIn',
1000
- value: [10, 43, 111, 115, 109, 111, 49, 117, 110, 102, 50, 114, 99, 121, 116, 106, 120, 102, 112, 122, 56, 120, 56, 97, 114, 54, 51, 104, 52, 113, 101, 102, 116, 97, 100, 112, 116, 103, 53, 116, 48, 110, 113, 99, 108, 18, 73, 8, -14, 3, 18, 68, 105, 98, 99, 47, 50, 55, 51, 57, 52, 70, 66, 48, 57, 50, 68, 50, 69, 67, 67, 68, 53, 54, 49, 50, 51, 67, 55, 52, 70, 51, 54, 69, 52, 67, 49, 70, 57, 50, 54, 48, 48, 49, 67, 69, 65, 68, 65, 57, 67, 65, 57, 55, 69, 65, 54, 50, 50, 66, 50, 53, 70, 52, 49, 69, 53, 69, 66, 50, 18, 72, 8, 8, 18, 68, 105, 98, 99, 47, 55, 67, 52, 68, 54, 48, 65, 65, 57, 53, 69, 53, 65, 55, 53, 53, 56, 66, 48, 65, 51, 54, 52, 56, 54, 48, 57, 55, 57, 67, 65, 51, 52, 66, 55, 70, 70, 56, 65, 65, 70, 50, 53, 53, 66, 56, 55, 65, 70, 57, 69, 56, 55, 57, 51, 55, 52, 52, 55, 48, 67, 69, 67, 48, 18, 9, 8, 7, 18, 5, 117, 111, 115, 109, 111, 26, 79, 10, 68, 105, 98, 99, 47, 52, 54, 66, 52, 52, 56, 57, 57, 51, 50, 50, 70, 51, 67, 68, 56, 53, 52, 68, 50, 68, 52, 54, 68, 69, 69, 70, 56, 56, 49, 57, 53, 56, 52, 54, 55, 67, 68, 68, 52, 66, 51, 66, 49, 48, 48, 56, 54, 68, 65, 52, 57, 50, 57, 54, 66, 66, 69, 68, 57, 52, 66, 69, 68, 18, 7, 49, 48, 48, 48, 48, 48, 48, 34, 7, 49, 53, 50, 53, 50, 54, 52]
1001
- }],
1002
- memo: '',
1003
- source: null,
1004
- fee: {
1005
- gas: '900000',
1006
- amount: [{
1007
- denom: 'uosmo',
1008
- amount: '0'
1009
- }]
1010
- },
1011
- signType: 'AMINO',
1012
- rpcUrl: ''
1013
- },
1014
- rawTransfer: null
1015
- },
1016
- solanaTransaction: null,
1017
- evmTransaction: null,
1018
- evmApprovalTransaction: null,
1019
- transferTransaction: null,
1020
- diagnosisUrl: null,
1021
- internalSteps: null
1022
- }]
1023
- }, {
916
+ replace: true
917
+ });
918
+ }
919
+ }
920
+ firstRender.current = false;
921
+ }, [location.pathname, inputAmount]);
922
+ React.useEffect(() => {
923
+ if (loadingStatus === 'success') {
924
+ const fronChainString = searchParams.get(SearchParams.FROM_CHAIN);
925
+ const fromTokenString = searchParams.get(SearchParams.FROM_TOKEN);
926
+ const toChainString = searchParams.get(SearchParams.TO_CHAIN);
927
+ const toTokenString = searchParams.get(SearchParams.TO_TOKEN);
928
+ const fromAmount = searchParams.get(SearchParams.FROM_AMOUNT);
929
+ const fromChain = blockchains.find(blockchain => blockchain.name === fronChainString);
930
+ const fromToken = searchParamsToToken(tokens, fromTokenString);
931
+ const toChain = blockchains.find(blockchain => blockchain.name === toChainString);
932
+ const toToken = searchParamsToToken(tokens, toTokenString);
933
+ if (!!fromChain) {
934
+ setFromChain(fromChain);
935
+ if (!!fromToken) setFromToken(fromToken);
936
+ }
937
+ if (!!toChain) {
938
+ setToChain(toChain);
939
+ if (!!toToken) setToToken(toToken);
940
+ }
941
+ if (fromAmount) setInputAmount(fromAmount);
942
+ }
943
+ }, [loadingStatus]);
944
+ return null;
945
+ }
946
+
947
+ const ButtonsContainer = /*#__PURE__*/ui.styled('div', {
948
+ display: 'flex'
949
+ });
950
+ function HeaderButtons(props) {
951
+ const {
952
+ onClickRefresh
953
+ } = props;
954
+ const navigate = reactRouterDom.useNavigate();
955
+ return React__default.createElement(ButtonsContainer, null, React__default.createElement(ui.Tooltip, {
956
+ content: "Retry"
957
+ }, React__default.createElement(ui.Button, {
958
+ variant: "ghost",
959
+ onClick: onClickRefresh.bind(null)
960
+ }, React__default.createElement(ui.RetryIcon, {
961
+ size: 28
962
+ }))), React__default.createElement(ui.Tooltip, {
963
+ content: "Transactions History"
964
+ }, React__default.createElement(ui.Button, {
965
+ variant: "ghost",
966
+ onClick: () => navigate(navigationRoutes.history)
967
+ }, React__default.createElement(ui.HistoryIcon, {
968
+ size: 24
969
+ }))), React__default.createElement(ui.Tooltip, {
970
+ content: "Settings"
971
+ }, React__default.createElement(ui.Button, {
972
+ variant: "ghost",
973
+ onClick: () => navigate(navigationRoutes.settings)
974
+ }, React__default.createElement(ui.SettingsIcon, {
975
+ size: 24
976
+ }))));
977
+ }
978
+
979
+ const HeaderContainer = /*#__PURE__*/ui.styled('div', {
980
+ display: 'flex',
981
+ justifyContent: 'space-between',
982
+ alignItems: 'center',
983
+ width: '100%',
984
+ padding: '$16 0'
985
+ });
986
+ function Header(props) {
987
+ const {
988
+ onClickRefresh
989
+ } = props;
990
+ return React__default.createElement(HeaderContainer, null, React__default.createElement(ui.Typography, {
991
+ variant: "h4"
992
+ }, "SWAP"), React__default.createElement(HeaderButtons, {
993
+ onClickRefresh: onClickRefresh
994
+ }));
995
+ }
996
+
997
+ const useWalletsStore = /*#__PURE__*/createSelectors( /*#__PURE__*/zustand.create()( /*#__PURE__*/middleware.subscribeWithSelector(set => ({
998
+ accounts: [],
999
+ balances: [],
1000
+ selectedWallets: [],
1001
+ connectWallet: accounts => {
1002
+ const tokens = useMetaStore.getState().meta.tokens;
1003
+ set(state => ({
1004
+ accounts: state.accounts.concat(accounts),
1005
+ balances: state.balances.concat(accounts.map(account => ({
1006
+ balances: [],
1007
+ address: account.address,
1008
+ chain: account.chain,
1009
+ loading: true,
1010
+ walletType: account.walletType,
1011
+ error: false,
1012
+ explorerUrl: null
1013
+ })))
1014
+ }));
1015
+ accounts.forEach(async account => {
1016
+ try {
1017
+ const response = await httpService.getWalletsDetails([{
1018
+ address: account.address,
1019
+ blockchain: account.chain
1020
+ }]);
1021
+ const retrivedBalance = response.wallets[0];
1022
+ if (retrivedBalance) {
1023
+ set(state => ({
1024
+ balances: state.balances.map(balance => {
1025
+ return isAccountAndBalanceMatched(account, balance) ? makeBalanceFor(account, retrivedBalance, tokens) : balance;
1026
+ })
1027
+ }));
1028
+ } else throw new Error('Wallet not found');
1029
+ } catch (error) {
1030
+ set(state => ({
1031
+ balances: state.balances.map(balance => {
1032
+ return isAccountAndBalanceMatched(account, balance) ? resetBalanceState(balance) : balance;
1033
+ })
1034
+ }));
1035
+ }
1036
+ });
1037
+ },
1038
+ disconnectWallet: walletType => {
1039
+ set(state => ({
1040
+ accounts: state.accounts.filter(account => account.walletType !== walletType),
1041
+ balances: state.balances.filter(balance => balance.walletType !== walletType),
1042
+ selectedWallets: state.selectedWallets.filter(wallet => wallet.walletType != walletType)
1043
+ }));
1044
+ },
1045
+ initSelectedWallets: () => set(state => {
1046
+ const requiredChains = getRequiredChains(useBestRouteStore.getState().bestRoute);
1047
+ const connectedWallets = state.accounts;
1048
+ const selectedWallets = [];
1049
+ requiredChains.forEach(chain => {
1050
+ const anyWalletSelected = !!state.selectedWallets.find(wallet => wallet.chain === chain);
1051
+ if (!anyWalletSelected) {
1052
+ const firstWalletWithMatchedChain = connectedWallets.find(wallet => wallet.chain === chain);
1053
+ if (!!firstWalletWithMatchedChain) selectedWallets.push({
1054
+ address: firstWalletWithMatchedChain.address,
1055
+ chain: firstWalletWithMatchedChain.chain,
1056
+ walletType: firstWalletWithMatchedChain.walletType
1057
+ });
1058
+ }
1059
+ });
1060
+ return {
1061
+ selectedWallets: state.selectedWallets.concat(selectedWallets)
1062
+ };
1063
+ }),
1064
+ setSelectedWallet: wallet => set(state => ({
1065
+ selectedWallets: state.selectedWallets.filter(selectedWallet => selectedWallet.chain !== wallet.chain).concat({
1066
+ chain: wallet.chain,
1067
+ address: wallet.address,
1068
+ walletType: wallet.walletType
1069
+ })
1070
+ }))
1071
+ }))));
1072
+
1073
+ const Box = /*#__PURE__*/ui.styled('div', {
1074
+ display: 'flex',
1075
+ flexDirection: 'column',
1076
+ width: '100%'
1077
+ });
1078
+ const Container = /*#__PURE__*/ui.styled('div', {
1079
+ boxSizing: 'border-box',
1080
+ backgroundColor: '$neutrals300',
1081
+ borderRadius: '$5',
1082
+ padding: '$8 0',
1083
+ '.form': {
1084
+ display: 'flex',
1085
+ width: '100%',
1086
+ padding: '$8 $16'
1087
+ }
1088
+ });
1089
+ const StyledImage = /*#__PURE__*/ui.styled('img', {
1090
+ width: '$24',
1091
+ maxHeight: '$24'
1092
+ });
1093
+ const Options = /*#__PURE__*/ui.styled('div', {
1094
+ display: 'flex',
1095
+ justifyContent: 'flex-end',
1096
+ padding: '0 $8'
1097
+ });
1098
+ const ImagePlaceholder = /*#__PURE__*/ui.styled('span', {
1099
+ width: '24px',
1100
+ height: '24px',
1101
+ backgroundColor: '$neutrals300',
1102
+ borderRadius: '99999px'
1103
+ });
1104
+ const OutputContainer = /*#__PURE__*/ui.styled('div', {
1105
+ height: '$48',
1106
+ borderRadius: '$5',
1107
+ flexGrow: 1,
1108
+ width: '70%',
1109
+ backgroundColor: '$background',
1110
+ border: '1px solid transparent',
1111
+ position: 'relative',
1112
+ display: 'flex',
1113
+ alignItems: 'center',
1114
+ paddingLeft: '$8',
1115
+ paddingRight: '$8'
1116
+ });
1117
+ function TokenInfo(props) {
1118
+ const {
1119
+ type,
1120
+ chain,
1121
+ token
1122
+ } = props;
1123
+ const loadingStatus = useMetaStore.use.loadingStatus();
1124
+ const fromChain = useBestRouteStore.use.fromChain();
1125
+ const toChain = useBestRouteStore.use.toChain();
1126
+ const inputUsdValue = useBestRouteStore.use.inputUsdValue();
1127
+ const fromToken = useBestRouteStore.use.fromToken();
1128
+ const setInputAmount = useBestRouteStore.use.setInputAmount();
1129
+ const bestRoute = useBestRouteStore.use.bestRoute();
1130
+ const inputAmount = useBestRouteStore.use.inputAmount();
1131
+ const balances = useWalletsStore.use.balances();
1132
+ const navigate = reactRouterDom.useNavigate();
1133
+ const tokenBalance = !!fromChain && !!fromToken ? numberToString(getBalanceFromWallet(balances, fromChain?.name, fromToken?.symbol, fromToken?.address)?.amount || '0', 8) : '0';
1134
+ const tokenBalanceReal = !!fromChain && !!fromToken ? numberToString(getBalanceFromWallet(balances, fromChain?.name, fromToken?.symbol, fromToken?.address)?.amount || '0', getBalanceFromWallet(balances, fromChain?.name, fromToken?.symbol, fromToken?.address)?.decimal) : '0';
1135
+ const ItemSuffix = React__default.createElement("div", {
1136
+ style: {
1137
+ display: 'flex',
1138
+ justifyContent: 'center',
1139
+ alignItems: 'center'
1140
+ }
1141
+ }, loadingStatus === 'failed' && React__default.createElement(ui.InfoCircleIcon, {
1142
+ color: "error",
1143
+ size: 24
1144
+ }), React__default.createElement(ui.AngleDownIcon, null));
1145
+ return React__default.createElement(Box, null, React__default.createElement("div", null, React__default.createElement(ui.Typography, {
1146
+ variant: "body2"
1147
+ }, type)), React__default.createElement(Container, null, props.type === 'From' && React__default.createElement(Options, null, React__default.createElement("div", {
1148
+ className: "balance",
1149
+ onClick: () => {
1150
+ if (tokenBalance !== '0') setInputAmount(tokenBalanceReal.split(',').join(''));
1151
+ }
1152
+ }, React__default.createElement(ui.Button, {
1153
+ variant: "ghost",
1154
+ size: "small"
1155
+ }, React__default.createElement(ui.Typography, {
1156
+ variant: "body2"
1157
+ }, `Max: ${tokenBalance} ${fromToken?.symbol || ''}`)))), React__default.createElement("div", {
1158
+ className: "form"
1159
+ }, React__default.createElement(ui.Button, {
1160
+ onClick: () => {
1161
+ navigate(`/${props.type.toLowerCase()}-chain`);
1162
+ },
1163
+ variant: "outlined",
1164
+ disabled: loadingStatus === 'failed',
1165
+ loading: loadingStatus === 'loading',
1166
+ prefix: loadingStatus === 'success' && chain ? React__default.createElement(StyledImage, {
1167
+ src: chain.logo
1168
+ }) : React__default.createElement(ImagePlaceholder, null),
1169
+ suffix: ItemSuffix,
1170
+ align: "start",
1171
+ size: "large",
1172
+ style: {
1173
+ marginRight: '.5rem'
1174
+ }
1175
+ }, loadingStatus === 'success' && chain ? chain.displayName : 'Chain'), React__default.createElement(ui.Button, {
1176
+ onClick: () => {
1177
+ navigate(`/${props.type.toLowerCase()}-token`);
1178
+ },
1179
+ variant: "outlined",
1180
+ disabled: loadingStatus === 'failed' || type === 'From' && !fromChain || type === 'To' && !toChain,
1181
+ loading: loadingStatus === 'loading',
1182
+ prefix: loadingStatus === 'success' && token ? React__default.createElement(StyledImage, {
1183
+ src: token.image
1184
+ }) : React__default.createElement(ImagePlaceholder, null),
1185
+ suffix: ItemSuffix,
1186
+ size: "large",
1187
+ align: "start",
1188
+ style: {
1189
+ marginRight: '.5rem'
1190
+ }
1191
+ }, loadingStatus === 'success' && token ? token.symbol : 'Token'), props.type === 'From' ? React__default.createElement(ui.TextField, {
1192
+ type: "number",
1193
+ size: "large",
1194
+ autoFocus: true,
1195
+ placeholder: "0",
1196
+ style: {
1197
+ width: '70%',
1198
+ position: 'relative',
1199
+ backgroundColor: '$background !important'
1200
+ },
1201
+ suffix: React__default.createElement("span", {
1202
+ style: {
1203
+ position: 'absolute',
1204
+ right: '4px',
1205
+ bottom: '2px'
1206
+ }
1207
+ }, React__default.createElement(ui.Typography, {
1208
+ variant: "caption"
1209
+ }, `$${numberToString(inputUsdValue)}`)),
1210
+ value: props.inputAmount || '',
1211
+ onChange: props.type === 'From' ? event => {
1212
+ props.onAmountChange(event.target.value);
1213
+ } : undefined
1214
+ }) : React__default.createElement(OutputContainer, null, React__default.createElement(ui.Typography, {
1215
+ variant: "body1"
1216
+ }, bestRoute ? `≈ ${numberToString(props.outputAmount)}` : inputAmount ? '?' : '0'), React__default.createElement("span", {
1217
+ style: {
1218
+ position: 'absolute',
1219
+ right: '4px',
1220
+ bottom: '2px'
1221
+ }
1222
+ }, React__default.createElement(ui.Typography, {
1223
+ variant: "caption"
1224
+ }, `$${numberToString(props.outputUsdValue)}`))))));
1225
+ }
1226
+
1227
+ const Container$1 = /*#__PURE__*/theme.styled('div', {
1228
+ display: 'flex',
1229
+ width: '100%',
1230
+ justifyContent: 'end',
1231
+ alignItems: 'center',
1232
+ paddingTop: '$16'
1233
+ });
1234
+ const Logo = /*#__PURE__*/theme.styled('svg', {
1235
+ fill: '$foreground',
1236
+ width: '$24',
1237
+ margin: '0 $8 0 $16'
1238
+ });
1239
+ const StyledAnchor = /*#__PURE__*/theme.styled('a', {
1240
+ display: 'flex',
1241
+ justifyContent: 'center',
1242
+ alignItems: 'center',
1243
+ textDecoration: 'none'
1244
+ });
1245
+ function BottomLogo() {
1246
+ return React__default.createElement(Container$1, null, React__default.createElement(ui.Typography, {
1247
+ variant: "caption"
1248
+ }, "Powered By"), React__default.createElement(StyledAnchor, {
1249
+ href: "https://rango.exchange",
1250
+ target: "_blank"
1251
+ }, React__default.createElement(Logo, {
1252
+ xmlns: "http://www.w3.org/2000/svg",
1253
+ viewBox: "0 0 33.68 29"
1254
+ }, React__default.createElement("defs", null), React__default.createElement("g", {
1255
+ id: "Layer_2",
1256
+ "data-name": "Layer 2"
1257
+ }, React__default.createElement("g", {
1258
+ id: "Layer_1-2",
1259
+ "data-name": "Layer 1"
1260
+ }, React__default.createElement("path", {
1261
+ d: "M33.68,18.05A17.93,17.93,0,0,0,28.34,5.29,18.31,18.31,0,0,0,15.45,0H13.54V7.41L6.07,0H.69L9.83,9.07H0V11A17.93,17.93,0,0,0,5.34,23.71,18.32,18.32,0,0,0,18.24,29h1.9V21.59l7.38,7.31h5.39l-9-9h9.82ZM17.37,16.16H12.49a1.93,1.93,0,0,0-1.35.55,1.89,1.89,0,0,0-.56,1.34,1.85,1.85,0,0,0,.56,1.33,1.93,1.93,0,0,0,1.35.55h3.84V25.1A14.43,14.43,0,0,1,8,21a14.21,14.21,0,0,1-4.1-8.2H21.2a1.86,1.86,0,0,0,.74-.13,1.92,1.92,0,0,0,.64-.4,2,2,0,0,0,.43-.62,1.88,1.88,0,0,0,0-1.47,2,2,0,0,0-.43-.62,1.92,1.92,0,0,0-.64-.4,1.86,1.86,0,0,0-.74-.13H17.35V3.9A14.43,14.43,0,0,1,25.64,8a14.19,14.19,0,0,1,4.11,8.2Zm2.12-5.27a1.43,1.43,0,0,1,.26-.83,1.52,1.52,0,0,1,.67-.56,1.55,1.55,0,0,1,.88-.08,1.51,1.51,0,0,1,.77.4,1.54,1.54,0,0,1,.42.77,1.41,1.41,0,0,1-.09.86,1.47,1.47,0,0,1-.55.68,1.56,1.56,0,0,1-.84.25,1.52,1.52,0,0,1-1.52-1.49Z"
1262
+ }), React__default.createElement("path", {
1263
+ d: "M21.7,11.57a.68.68,0,0,0-.12-.38.64.64,0,0,0-.31-.25.68.68,0,0,0-.75.15.61.61,0,0,0-.19.35.62.62,0,0,0,0,.4.67.67,0,0,0,.25.3.69.69,0,0,0,.39.12.7.7,0,0,0,.49-.2A.68.68,0,0,0,21.7,11.57Z"
1264
+ })))), React__default.createElement(ui.Typography, {
1265
+ variant: "body2"
1266
+ }, "RANGO")));
1267
+ }
1268
+
1269
+ function SwithFromAndTo(_ref) {
1270
+ let {
1271
+ count
1272
+ } = _ref;
1273
+ const firstRender = React.useRef(true);
1274
+ const [searchParams, setSearchParams] = reactRouterDom.useSearchParams();
1275
+ const outputAmount = useBestRouteStore.use.outputAmount();
1276
+ React.useEffect(() => {
1277
+ if (!firstRender.current) {
1278
+ const fromChainString = searchParams.get(SearchParams.FROM_CHAIN);
1279
+ const fromTokenString = searchParams.get(SearchParams.FROM_TOKEN);
1280
+ const toChainString = searchParams.get(SearchParams.TO_CHAIN);
1281
+ const toTokenString = searchParams.get(SearchParams.TO_TOKEN);
1282
+ setSearchParams({
1283
+ ...(toChainString && {
1284
+ [SearchParams.FROM_CHAIN]: toChainString
1285
+ }),
1286
+ ...(toTokenString && {
1287
+ [SearchParams.FROM_TOKEN]: toTokenString
1288
+ }),
1289
+ ...(fromChainString && {
1290
+ [SearchParams.TO_CHAIN]: fromChainString
1291
+ }),
1292
+ ...(fromTokenString && {
1293
+ [SearchParams.TO_TOKEN]: fromTokenString
1294
+ }),
1295
+ ...(outputAmount && {
1296
+ [SearchParams.FROM_AMOUNT]: outputAmount.toString()
1297
+ })
1298
+ });
1299
+ } else {
1300
+ firstRender.current = false;
1301
+ }
1302
+ }, [count]);
1303
+ return null;
1304
+ }
1305
+
1306
+ const Footer = /*#__PURE__*/ui.styled('div', {
1307
+ display: 'flex',
1308
+ flexDirection: 'column',
1309
+ width: '100%',
1310
+ paddingTop: '$16'
1311
+ });
1312
+
1313
+ const errorMessages = {
1314
+ genericServerError: 'Error connecting server, please reload the app and try again'
1315
+ };
1316
+
1317
+ const Container$2 = /*#__PURE__*/ui.styled('div', {
1318
+ display: 'flex',
1319
+ flexDirection: 'column',
1320
+ justifyContent: 'center',
1321
+ alignItems: 'center'
1322
+ });
1323
+ const SwitchButtonContainer = /*#__PURE__*/ui.styled('div', {
1324
+ display: 'flex',
1325
+ justifyContent: 'center',
1326
+ alignItems: 'center',
1327
+ position: 'relative',
1328
+ top: '11px'
1329
+ });
1330
+ const BestRouteContainer = /*#__PURE__*/ui.styled('div', {
1331
+ width: '100%',
1332
+ paddingTop: '$16'
1333
+ });
1334
+ const Alerts = /*#__PURE__*/ui.styled('div', {
1335
+ width: '100%',
1336
+ paddingTop: '$16'
1337
+ });
1338
+ function Home() {
1339
+ const waningMessage = '';
1340
+ const isRouterInContext = reactRouterDom.useInRouterContext();
1341
+ const navigate = reactRouterDom.useNavigate();
1342
+ const [count, setCount] = React.useState(0);
1343
+ const fromChain = useBestRouteStore.use.fromChain();
1344
+ const fromToken = useBestRouteStore.use.fromToken();
1345
+ const toChain = useBestRouteStore.use.toChain();
1346
+ const toToken = useBestRouteStore.use.toToken();
1347
+ const setFromChain = useBestRouteStore.use.setFromChain();
1348
+ const setFromToken = useBestRouteStore.use.setFromToken();
1349
+ const setToChain = useBestRouteStore.use.setToChain();
1350
+ const setToToken = useBestRouteStore.use.setToToken();
1351
+ const inputUsdValue = useBestRouteStore.use.inputUsdValue();
1352
+ const inputAmount = useBestRouteStore.use.inputAmount();
1353
+ const setInputAmount = useBestRouteStore.use.setInputAmount();
1354
+ const outputAmount = useBestRouteStore.use.outputAmount();
1355
+ const outputUsdValue = useBestRouteStore.use.outputUsdValue();
1356
+ const bestRoute = useBestRouteStore.use.bestRoute();
1357
+ const tokens = useMetaStore.use.meta().tokens;
1358
+ const fetchingBestRoute = useBestRouteStore.use.loading();
1359
+ const bestRouteError = useBestRouteStore.use.error();
1360
+ const loadingMetaStatus = useMetaStore.use.loadingStatus();
1361
+ const accounts = useWalletsStore.use.accounts();
1362
+ const swithFromAndTo = () => {
1363
+ setFromChain(toChain);
1364
+ setFromToken(toToken);
1365
+ setToChain(fromChain);
1366
+ setToToken(fromToken);
1367
+ setInputAmount(outputAmount?.toString() || '');
1368
+ setCount(prev => prev + 1);
1369
+ };
1370
+ const errorMessage = loadingMetaStatus === 'failed' ? errorMessages.genericServerError : bestRouteError;
1371
+ const needsToWarnEthOnPath = false;
1372
+ const showBestRoute = inputAmount && (!!bestRoute || fetchingBestRoute || bestRouteError);
1373
+ const outToInRatio = getOutputRatio(inputUsdValue, outputUsdValue);
1374
+ const highValueLoss = outputRatioHasWarning(inputUsdValue, outToInRatio);
1375
+ const {
1376
+ fromAmountRangeError,
1377
+ recommendation,
1378
+ swap
1379
+ } = LimitErrorMessage(bestRoute);
1380
+ const priceImpactCanNotBeComputed = !canComputePriceImpact(bestRoute, inputAmount, inputUsdValue, outputUsdValue);
1381
+ const swapButtonState = getSwapButtonState(loadingMetaStatus, accounts, fetchingBestRoute, bestRoute, hasLimitError(bestRoute), highValueLoss, priceImpactCanNotBeComputed, needsToWarnEthOnPath);
1382
+ const totalFeeInUsd = getTotalFeeInUsd(bestRoute, tokens);
1383
+ const highFee = hasHighFee(totalFeeInUsd);
1384
+ return React__default.createElement(Container$2, null, React__default.createElement(Header, {
1385
+ onClickRefresh: fetchBestRoute
1386
+ }), React__default.createElement(TokenInfo, {
1387
+ type: "From",
1388
+ chain: fromChain,
1389
+ token: fromToken,
1390
+ onAmountChange: setInputAmount,
1391
+ inputAmount: inputAmount
1392
+ }), React__default.createElement(SwitchButtonContainer, null, React__default.createElement(ui.Button, {
1393
+ variant: "ghost",
1394
+ onClick: swithFromAndTo
1395
+ }, React__default.createElement(ui.VerticalSwapIcon, {
1396
+ size: 36
1397
+ }), isRouterInContext && React__default.createElement(SwithFromAndTo, {
1398
+ count: count
1399
+ }))), React__default.createElement(TokenInfo, {
1400
+ type: "To",
1401
+ chain: toChain,
1402
+ token: toToken,
1403
+ outputAmount: outputAmount,
1404
+ outputUsdValue: outputUsdValue
1405
+ }), showBestRoute && React__default.createElement(BestRouteContainer, null, React__default.createElement(ui.BestRoute, {
1406
+ error: bestRouteError,
1407
+ loading: fetchingBestRoute,
1408
+ data: bestRoute,
1409
+ totalFee: numberToString(totalFeeInUsd, 0, 2),
1410
+ feeWarning: highFee,
1411
+ totalTime: secondsToString(totalArrivalTime(bestRoute))
1412
+ })), (errorMessage || waningMessage || hasLimitError(bestRoute)) && React__default.createElement(Alerts, null, errorMessage && React__default.createElement(ui.Alert, {
1413
+ type: "error"
1414
+ }, React__default.createElement(ui.Typography, {
1415
+ variant: "body2"
1416
+ }, errorMessage)), hasLimitError(bestRoute) && React__default.createElement(ui.Alert, {
1417
+ type: "error",
1418
+ title: `${swap?.swapperId} Limit`
1419
+ }, React__default.createElement(React__default.Fragment, null, React__default.createElement(ui.Typography, {
1420
+ variant: "body2"
1421
+ }, fromAmountRangeError), React__default.createElement("br", null), React__default.createElement(ui.Typography, {
1422
+ variant: "body2"
1423
+ }, "Yours: ", numberToString(swap?.fromAmount || null), swap?.from.symbol), React__default.createElement("br", null), React__default.createElement(ui.Typography, {
1424
+ variant: "body2"
1425
+ }, recommendation))), waningMessage ), React__default.createElement(Footer, null, React__default.createElement(ui.Button, {
1426
+ type: "primary",
1427
+ align: "grow",
1428
+ size: "large",
1429
+ disabled: swapButtonState.disabled,
1430
+ onClick: () => {
1431
+ if (swapButtonState.title === 'Connect Wallet') navigate(navigationRoutes.wallets);else {
1432
+ navigate(navigationRoutes.confirmWallets);
1433
+ }
1434
+ }
1435
+ }, swapButtonState.title), React__default.createElement(BottomLogo, null)));
1436
+ }
1437
+
1438
+ const Route = props => {
1439
+ const location = reactRouter.useLocation();
1440
+ const navigate = reactRouter.useNavigate();
1441
+ const ref = React.useRef(true);
1442
+ React.useEffect(() => {
1443
+ if ([navigationRoutes.confirmWallets, navigationRoutes.confirmSwap].includes(location.pathname) && ref.current) navigate(navigationRoutes.home + location.search, {
1444
+ state: 'redirect'
1445
+ });
1446
+ ref.current = false;
1447
+ }, []);
1448
+ if ([navigationRoutes.confirmWallets, navigationRoutes.confirmSwap].includes(location.pathname) && ref.current) return React__default.createElement(Home, null);
1449
+ return React__default.createElement(React__default.Fragment, null, " ", props.children);
1450
+ };
1451
+ function AppRouter(_ref) {
1452
+ let {
1453
+ children
1454
+ } = _ref;
1455
+ const isRouterInContext = reactRouter.useInRouterContext();
1456
+ const Router = isRouterInContext ? Route : reactRouter.MemoryRouter;
1457
+ return React__default.createElement(React__default.Fragment, null, React__default.createElement(Router, null, children), isRouterInContext && React__default.createElement(UpdateUrl, null));
1458
+ }
1459
+
1460
+ const useUiStore = /*#__PURE__*/createSelectors( /*#__PURE__*/zustand.create()(set => ({
1461
+ connectWalletsButtonDisabled: false,
1462
+ toggleConnectWalletsButton: () => set(state => ({
1463
+ connectWalletsButtonDisabled: !state.connectWalletsButtonDisabled
1464
+ }))
1465
+ })));
1466
+
1467
+ const StyledButton = /*#__PURE__*/ui.styled(ui.Button, {
1468
+ marginTop: '$8'
1469
+ });
1470
+ function ChangeSlippageButton() {
1471
+ const navigate = reactRouterDom.useNavigate();
1472
+ return React__default.createElement(StyledButton, {
1473
+ type: "primary",
1474
+ variant: "contained",
1475
+ size: "small",
1476
+ onClick: navigate.bind(null, navigationRoutes.settings)
1477
+ }, "Change Slippage");
1478
+ }
1479
+
1480
+ function HighSlippageWarning(props) {
1481
+ const {
1482
+ selectedSlippage
1483
+ } = props;
1484
+ return React__default.createElement(ui.Alert, {
1485
+ type: "warning"
1486
+ }, React__default.createElement(ui.Typography, {
1487
+ variant: "body2"
1488
+ }, "slippage is high=> Caution, your slippage is high (=", selectedSlippage, "). Your trade may be front run.", React__default.createElement(ChangeSlippageButton, null)));
1489
+ }
1490
+
1491
+ function ConfirmSwapExtraMessages(props) {
1492
+ const {
1493
+ selectedSlippage
1494
+ } = props;
1495
+ const highSlippage = selectedSlippage >= HIGH_SLIPPAGE;
1496
+ return React__default.createElement(React__default.Fragment, null, highSlippage && React__default.createElement(HighSlippageWarning, {
1497
+ selectedSlippage: selectedSlippage
1498
+ }));
1499
+ }
1500
+
1501
+ function useNavigateBack() {
1502
+ const isRouterInContext = reactRouterDom.useInRouterContext();
1503
+ const navigate = reactRouterDom.useNavigate();
1504
+ const navigateBackFrom = currentRoute => {
1505
+ if (!isRouterInContext || window.history.state && window.history.state.idx > 0) navigate(-1);else {
1506
+ if ([navigationRoutes.fromChain, navigationRoutes.fromToken, navigationRoutes.toChain, navigationRoutes.toToken, navigationRoutes.settings, navigationRoutes.wallets, navigationRoutes.history].includes(currentRoute)) navigate(navigationRoutes.home, {
1507
+ replace: true
1508
+ });else if (currentRoute === navigationRoutes.liquiditySources) {
1509
+ navigate(navigationRoutes.settings, {
1510
+ replace: true
1511
+ });
1512
+ } else if (currentRoute === navigationRoutes.swapDetails) navigate(navigationRoutes.history, {
1513
+ replace: true
1514
+ });
1515
+ }
1516
+ };
1517
+ return {
1518
+ navigateBackFrom
1519
+ };
1520
+ }
1521
+
1522
+ const useConfirmSwapStore = /*#__PURE__*/createSelectors( /*#__PURE__*/zustand.create()( /*#__PURE__*/middleware.subscribeWithSelector(() => ({
1523
+ loading: false,
1524
+ errors: [],
1525
+ warnings: [],
1526
+ proceedAnyway: false
1527
+ }))));
1528
+ var ConfirmSwapErrorTypes;
1529
+ (function (ConfirmSwapErrorTypes) {
1530
+ ConfirmSwapErrorTypes[ConfirmSwapErrorTypes["NO_ROUTE"] = 0] = "NO_ROUTE";
1531
+ ConfirmSwapErrorTypes[ConfirmSwapErrorTypes["ROUTE_UPDATED_WITH_HIGH_VALUE_LOSS"] = 1] = "ROUTE_UPDATED_WITH_HIGH_VALUE_LOSS";
1532
+ ConfirmSwapErrorTypes[ConfirmSwapErrorTypes["REQUEST_FAILED"] = 2] = "REQUEST_FAILED";
1533
+ ConfirmSwapErrorTypes[ConfirmSwapErrorTypes["INSUFFICIENT_SLIPPAGE"] = 3] = "INSUFFICIENT_SLIPPAGE";
1534
+ })(ConfirmSwapErrorTypes || (ConfirmSwapErrorTypes = {}));
1535
+ var ConfirmSwapWarningTypes;
1536
+ (function (ConfirmSwapWarningTypes) {
1537
+ ConfirmSwapWarningTypes[ConfirmSwapWarningTypes["ROUTE_UPDATED"] = 0] = "ROUTE_UPDATED";
1538
+ ConfirmSwapWarningTypes[ConfirmSwapWarningTypes["ROUTE_SWAPPERS_UPDATED"] = 1] = "ROUTE_SWAPPERS_UPDATED";
1539
+ ConfirmSwapWarningTypes[ConfirmSwapWarningTypes["ROUTE_COINS_UPDATED"] = 2] = "ROUTE_COINS_UPDATED";
1540
+ ConfirmSwapWarningTypes[ConfirmSwapWarningTypes["ROUTE_AND_OUTPUT_AMOUNT_UPDATED"] = 3] = "ROUTE_AND_OUTPUT_AMOUNT_UPDATED";
1541
+ ConfirmSwapWarningTypes[ConfirmSwapWarningTypes["INSUFFICIENT_BALANCE"] = 4] = "INSUFFICIENT_BALANCE";
1542
+ })(ConfirmSwapWarningTypes || (ConfirmSwapWarningTypes = {}));
1543
+ const confirmSwap = () => {
1544
+ const {
1545
+ fromToken,
1546
+ toToken,
1547
+ inputAmount,
1548
+ bestRoute: initialRoute,
1549
+ inputUsdValue,
1550
+ setBestRoute
1551
+ } = useBestRouteStore.getState();
1552
+ const {
1553
+ accounts,
1554
+ selectedWallets
1555
+ } = useWalletsStore.getState();
1556
+ const {
1557
+ proceedAnyway
1558
+ } = useConfirmSwapStore.getState();
1559
+ const {
1560
+ disabledLiquiditySources,
1561
+ slippage,
1562
+ customSlippage
1563
+ } = useSettingsStore.getState();
1564
+ const {
1565
+ meta
1566
+ } = useMetaStore.getState();
1567
+ const userSlippage = customSlippage || slippage;
1568
+ if (!fromToken || !toToken || !inputAmount || !initialRoute) return;
1569
+ if (proceedAnyway) {
1570
+ const swapSettings = {
1571
+ slippage: userSlippage.toString(),
1572
+ disabledSwappersGroups: disabledLiquiditySources
1573
+ };
1574
+ const newSwap = calculatePendingSwap(inputAmount.toString(), initialRoute, getWalletsForNewSwap(selectedWallets), swapSettings, false, meta);
1575
+ console.log('new swap:', newSwap);
1576
+ return useConfirmSwapStore.setState({
1577
+ errors: [],
1578
+ warnings: [],
1579
+ proceedAnyway: false
1580
+ });
1581
+ }
1582
+ let abortController = new AbortController();
1583
+ useConfirmSwapStore.setState({
1584
+ loading: true
1585
+ });
1586
+ const requestBody = createBestRouteRequestBody(fromToken, toToken, inputAmount, accounts, selectedWallets, disabledLiquiditySources, userSlippage, true);
1587
+ const unsubscribeFromBestRouteStore = useBestRouteStore.subscribe(state => state.bestRoute, () => {
1588
+ abortController.abort();
1589
+ }, {
1590
+ equalityFn: shallow.shallow
1591
+ });
1592
+ const unsubscribeFromWalletsStore = useWalletsStore.subscribe(state => state.selectedWallets, () => {
1593
+ abortController?.abort();
1594
+ }, {
1595
+ equalityFn: (prevState, state) => {
1596
+ const selectedWalletsChanged = !state.every(wallet => !!prevState.find(prevWallet => wallet.address === prevWallet.address && wallet.chain === prevWallet.chain));
1597
+ if (selectedWalletsChanged) return false;else return true;
1598
+ }
1599
+ });
1600
+ httpService.getBestRoute(requestBody, {
1601
+ signal: abortController.signal
1602
+ }).then(confiremedRoute => {
1603
+ useConfirmSwapStore.setState({
1604
+ loading: false
1605
+ });
1606
+ if (!confiremedRoute.result || !new BigNumber__default(confiremedRoute.requestAmount).isEqualTo(new BigNumber__default(inputAmount || '-1'))) return useConfirmSwapStore.setState(prevState => ({
1607
+ errors: prevState.errors.concat({
1608
+ type: ConfirmSwapErrorTypes.NO_ROUTE
1609
+ })
1610
+ }));
1611
+ const confirmSwap = {
1612
+ loading: false,
1613
+ errors: [],
1614
+ warnings: [],
1615
+ proceedAnyway
1616
+ };
1617
+ const routeChanged = isRouteChanged(initialRoute, confiremedRoute);
1618
+ if (routeChanged) {
1619
+ setBestRoute(confiremedRoute);
1620
+ const newRouteOutputUsdValue = new BigNumber__default(confiremedRoute.result?.outputAmount || '0').multipliedBy(toToken.usdPrice || 0);
1621
+ const outputRatio = getOutputRatio(inputUsdValue, newRouteOutputUsdValue);
1622
+ const highValueLoss = outputRatioHasWarning(inputUsdValue, outputRatio);
1623
+ if (isNumberOfSwapsChanged(initialRoute, confiremedRoute)) confirmSwap.warnings.push({
1624
+ type: ConfirmSwapWarningTypes.ROUTE_UPDATED
1625
+ });else if (isRouteSwappersUpdated(initialRoute, confiremedRoute)) confirmSwap.warnings.push({
1626
+ type: ConfirmSwapWarningTypes.ROUTE_SWAPPERS_UPDATED
1627
+ });else isRouteInternalCoinsUpdated(initialRoute, confiremedRoute);
1628
+ confirmSwap.warnings.push({
1629
+ type: ConfirmSwapWarningTypes.ROUTE_COINS_UPDATED
1630
+ });
1631
+ if (highValueLoss) confirmSwap.errors.push({
1632
+ type: ConfirmSwapErrorTypes.ROUTE_UPDATED_WITH_HIGH_VALUE_LOSS
1633
+ });else if (isOutputAmountChangedALot(initialRoute, confiremedRoute)) confirmSwap.warnings.push({
1634
+ type: ConfirmSwapWarningTypes.ROUTE_AND_OUTPUT_AMOUNT_UPDATED,
1635
+ newOutputAmount: numberToString(getRouteOutputAmount(confiremedRoute)),
1636
+ percentageChange: numberToString(getPercentageChange(getRouteOutputAmount(initialRoute), getRouteOutputAmount(confiremedRoute)), null, 2)
1637
+ });
1638
+ }
1639
+ const balanceWarnings = getBalanceWarnings(confiremedRoute, selectedWallets);
1640
+ const enoughBalance = balanceWarnings.length === 0;
1641
+ if (!enoughBalance) confirmSwap.warnings.push({
1642
+ type: ConfirmSwapWarningTypes.INSUFFICIENT_BALANCE,
1643
+ messages: balanceWarnings
1644
+ });
1645
+ const minRequiredSlippage = getMinRequiredSlippage(initialRoute);
1646
+ if (!hasProperSlippage(userSlippage.toString(), minRequiredSlippage)) confirmSwap.errors.push({
1647
+ type: ConfirmSwapErrorTypes.INSUFFICIENT_SLIPPAGE,
1648
+ minRequiredSlippage
1649
+ });
1650
+ const noErrors = confirmSwap.errors.length === 0;
1651
+ const noWarnings = confirmSwap.warnings.length === 0;
1652
+ if ((noErrors || !noErrors && proceedAnyway) && (noWarnings || !noWarnings && proceedAnyway)) {
1653
+ const swapSettings = {
1654
+ slippage: userSlippage.toString(),
1655
+ disabledSwappersGroups: disabledLiquiditySources
1656
+ };
1657
+ const newSwap = calculatePendingSwap(inputAmount.toString(), initialRoute, getWalletsForNewSwap(selectedWallets), swapSettings, false, meta);
1658
+ console.log('new swap:', newSwap);
1659
+ } else if (!proceedAnyway) confirmSwap.proceedAnyway = true;
1660
+ abortController = null;
1661
+ useConfirmSwapStore.setState(confirmSwap);
1662
+ unsubscribeFromBestRouteStore();
1663
+ unsubscribeFromWalletsStore();
1664
+ }).catch(error => {
1665
+ abortController = null;
1666
+ if (error.code === 'ERR_CANCELED') {
1667
+ useConfirmSwapStore.setState({
1668
+ errors: [],
1669
+ warnings: [],
1670
+ loading: false,
1671
+ proceedAnyway: false
1672
+ });
1673
+ unsubscribeFromBestRouteStore();
1674
+ unsubscribeFromWalletsStore();
1675
+ }
1676
+ const status = error.response?.status;
1677
+ useConfirmSwapStore.setState(prevState => ({
1678
+ loading: false,
1679
+ errors: prevState.errors.concat({
1680
+ type: ConfirmSwapErrorTypes.REQUEST_FAILED,
1681
+ status
1682
+ })
1683
+ }));
1684
+ });
1685
+ };
1686
+
1687
+ function MinRequiredSlippage(_ref) {
1688
+ let {
1689
+ minRequiredSlippage
1690
+ } = _ref;
1691
+ return React__default.createElement(ui.Typography, {
1692
+ variant: "body2"
1693
+ }, "slippage is low => We recommend you to increase slippage to at least", minRequiredSlippage, "for this route.", React__default.createElement(ChangeSlippageButton, null));
1694
+ }
1695
+
1696
+ function ConfirmSwapErrors(errors) {
1697
+ return errors.flatMap(error => {
1698
+ switch (error.type) {
1699
+ case ConfirmSwapErrorTypes.NO_ROUTE:
1700
+ return React__default.createElement(ui.Typography, {
1701
+ variant: "body2"
1702
+ }, "No routes found. Please try again later.");
1703
+ case ConfirmSwapErrorTypes.REQUEST_FAILED:
1704
+ return React__default.createElement(ui.Typography, {
1705
+ variant: "body2"
1706
+ }, `Failed to confirm swap ${error.status ? `'status': ${error.status})` : ''}, please try again.`);
1707
+ case ConfirmSwapErrorTypes.ROUTE_UPDATED_WITH_HIGH_VALUE_LOSS:
1708
+ return React__default.createElement(ui.Typography, {
1709
+ variant: "body2"
1710
+ }, "Route updated and price impact is too high, try again later!");
1711
+ case ConfirmSwapErrorTypes.INSUFFICIENT_SLIPPAGE:
1712
+ return React__default.createElement(MinRequiredSlippage, {
1713
+ minRequiredSlippage: error.minRequiredSlippage
1714
+ });
1715
+ default:
1716
+ return [];
1717
+ }
1718
+ });
1719
+ }
1720
+
1721
+ function BalanceWarnings(_ref) {
1722
+ let {
1723
+ messages
1724
+ } = _ref;
1725
+ return React__default.createElement("div", null, messages.map(warning => React__default.createElement(ui.Typography, {
1726
+ variant: "body2"
1727
+ }, warning)));
1728
+ }
1729
+
1730
+ function ConfirmSwapWarnings(warnings) {
1731
+ return warnings.flatMap(warning => {
1732
+ switch (warning.type) {
1733
+ case ConfirmSwapWarningTypes.ROUTE_UPDATED:
1734
+ return React__default.createElement(ui.Typography, {
1735
+ variant: "body2"
1736
+ }, "Route has been updated.");
1737
+ case ConfirmSwapWarningTypes.ROUTE_AND_OUTPUT_AMOUNT_UPDATED:
1738
+ return React__default.createElement(ui.Typography, {
1739
+ variant: "body2"
1740
+ }, `Output amount changed to ${warning.newOutputAmount}
1741
+ (${warning.percentageChange}% change).`);
1742
+ case ConfirmSwapWarningTypes.ROUTE_SWAPPERS_UPDATED:
1743
+ return React__default.createElement(ui.Typography, {
1744
+ variant: "body2"
1745
+ }, "Route swappers has been updated.");
1746
+ case ConfirmSwapWarningTypes.ROUTE_COINS_UPDATED:
1747
+ return React__default.createElement(ui.Typography, {
1748
+ variant: "body2"
1749
+ }, "Route internal coins has been updated.");
1750
+ case ConfirmSwapWarningTypes.INSUFFICIENT_BALANCE:
1751
+ return React__default.createElement(BalanceWarnings, {
1752
+ messages: warning.messages
1753
+ });
1754
+ default:
1755
+ return [];
1756
+ }
1757
+ });
1758
+ }
1759
+
1760
+ function ConfirmSwapPage() {
1761
+ const {
1762
+ navigateBackFrom
1763
+ } = useNavigateBack();
1764
+ const bestRoute = useBestRouteStore.use.bestRoute();
1765
+ const loading = useConfirmSwapStore.use.loading();
1766
+ const warnings = useConfirmSwapStore.use.warnings();
1767
+ const errors = useConfirmSwapStore.use.errors();
1768
+ console.log('loading:', loading, 'warnings:', warnings, 'errors:', errors);
1769
+ const slippage = useSettingsStore.use.slippage();
1770
+ const customSlippage = useSettingsStore.use.customSlippage();
1771
+ const selectedSlippage = customSlippage || slippage;
1772
+ return React__default.createElement(ui.ConfirmSwap, {
1773
+ onConfirm: confirmSwap.bind(null),
1774
+ onBack: navigateBackFrom.bind(null, navigationRoutes.confirmSwap),
1775
+ bestRoute: bestRoute,
1776
+ loading: loading,
1777
+ errors: ConfirmSwapErrors(errors),
1778
+ warnings: ConfirmSwapWarnings(warnings),
1779
+ extraMessages: React__default.createElement(ConfirmSwapExtraMessages, {
1780
+ selectedSlippage: selectedSlippage
1781
+ }),
1782
+ confirmButtonTitle: warnings.length > 0 || errors.length > 0 ? 'Proceed anyway!' : 'Confirm swap!',
1783
+ confirmButtonDisabled: errors.length > 0
1784
+ });
1785
+ }
1786
+
1787
+ const pendingSwap = [{
1024
1788
  creationTime: '1673164511955',
1025
1789
  finishTime: '1673164550137',
1026
1790
  requestId: '51e211d9-d61c-45d2-a4d4-1f9f7f90ee85',
@@ -1031,7 +1795,7 @@ const pendingSwap = [{
1031
1795
  address: 'osmo1unf2rcytjxfpz8x8ar63h4qeftadptg5t0nqcl'
1032
1796
  }
1033
1797
  },
1034
- status: 'failed',
1798
+ status: 'running',
1035
1799
  isPaused: false,
1036
1800
  extraMessage: null,
1037
1801
  extraMessageSeverity: 'info',
@@ -1049,10 +1813,10 @@ const pendingSwap = [{
1049
1813
  outputAmount: '1.540670',
1050
1814
  swaps: [{
1051
1815
  swapperId: 'Osmosis',
1816
+ swapperType: 'DEX',
1052
1817
  swapperLogo: '',
1053
1818
  // @ts-ignore
1054
1819
  result: null,
1055
- swapperType: 'DEX',
1056
1820
  from: {
1057
1821
  symbol: 'JUNO',
1058
1822
  logo: 'https://api.rango.exchange/tokens/COSMOS/JUNO.png',
@@ -1151,12 +1915,12 @@ const pendingSwap = [{
1151
1915
  fromDecimals: 6,
1152
1916
  fromAmountPrecision: null,
1153
1917
  fromAmountMinValue: null,
1918
+ swapperLogo: '',
1919
+ swapperType: '',
1154
1920
  fromAmountMaxValue: null,
1155
1921
  toBlockchainLogo: 'https://api.rango.exchange/swappers/osmosis.png',
1156
1922
  fromBlockchainLogo: 'https://api.rango.exchange/swappers/osmosis.png',
1157
1923
  toBlockchain: 'OSMOSIS',
1158
- swapperLogo: '',
1159
- swapperType: '',
1160
1924
  fromLogo: 'https://api.rango.exchange/tokens/COSMOS/JUNO.png',
1161
1925
  toSymbol: 'OSMO',
1162
1926
  toSymbolAddress: null,
@@ -1166,7 +1930,7 @@ const pendingSwap = [{
1166
1930
  swapperId: 'Osmosis',
1167
1931
  expectedOutputAmountHumanReadable: '1.540670',
1168
1932
  outputAmount: '1.540658',
1169
- status: 'failed',
1933
+ status: 'running',
1170
1934
  networkStatus: null,
1171
1935
  executedTransactionId: '0f8f17eecc863c2d6be65ef52cfe3128ff3cd7baeddf133160bea8ccdfbf876b',
1172
1936
  explorerUrl: [{
@@ -1239,7 +2003,7 @@ const pendingSwap = [{
1239
2003
  address: 'osmo1unf2rcytjxfpz8x8ar63h4qeftadptg5t0nqcl'
1240
2004
  }
1241
2005
  },
1242
- status: 'success',
2006
+ status: 'failed',
1243
2007
  isPaused: false,
1244
2008
  extraMessage: null,
1245
2009
  extraMessageSeverity: 'info',
@@ -1256,11 +2020,11 @@ const pendingSwap = [{
1256
2020
  simulationResult: {
1257
2021
  outputAmount: '1.540670',
1258
2022
  swaps: [{
1259
- // @ts-ignore
1260
- result: [],
1261
2023
  swapperId: 'Osmosis',
1262
- swapperType: 'DEX',
1263
2024
  swapperLogo: '',
2025
+ // @ts-ignore
2026
+ result: null,
2027
+ swapperType: 'DEX',
1264
2028
  from: {
1265
2029
  symbol: 'JUNO',
1266
2030
  logo: 'https://api.rango.exchange/tokens/COSMOS/JUNO.png',
@@ -1359,12 +2123,12 @@ const pendingSwap = [{
1359
2123
  fromDecimals: 6,
1360
2124
  fromAmountPrecision: null,
1361
2125
  fromAmountMinValue: null,
1362
- swapperLogo: '',
1363
- swapperType: '',
1364
2126
  fromAmountMaxValue: null,
1365
2127
  toBlockchainLogo: 'https://api.rango.exchange/swappers/osmosis.png',
1366
2128
  fromBlockchainLogo: 'https://api.rango.exchange/swappers/osmosis.png',
1367
2129
  toBlockchain: 'OSMOSIS',
2130
+ swapperLogo: '',
2131
+ swapperType: '',
1368
2132
  fromLogo: 'https://api.rango.exchange/tokens/COSMOS/JUNO.png',
1369
2133
  toSymbol: 'OSMO',
1370
2134
  toSymbolAddress: null,
@@ -1374,7 +2138,7 @@ const pendingSwap = [{
1374
2138
  swapperId: 'Osmosis',
1375
2139
  expectedOutputAmountHumanReadable: '1.540670',
1376
2140
  outputAmount: '1.540658',
1377
- status: 'success',
2141
+ status: 'failed',
1378
2142
  networkStatus: null,
1379
2143
  executedTransactionId: '0f8f17eecc863c2d6be65ef52cfe3128ff3cd7baeddf133160bea8ccdfbf876b',
1380
2144
  explorerUrl: [{
@@ -1415,541 +2179,246 @@ const pendingSwap = [{
1415
2179
  type_url: '/osmosis.gamm.v1beta1.MsgSwapExactAmountIn',
1416
2180
  value: [10, 43, 111, 115, 109, 111, 49, 117, 110, 102, 50, 114, 99, 121, 116, 106, 120, 102, 112, 122, 56, 120, 56, 97, 114, 54, 51, 104, 52, 113, 101, 102, 116, 97, 100, 112, 116, 103, 53, 116, 48, 110, 113, 99, 108, 18, 73, 8, -14, 3, 18, 68, 105, 98, 99, 47, 50, 55, 51, 57, 52, 70, 66, 48, 57, 50, 68, 50, 69, 67, 67, 68, 53, 54, 49, 50, 51, 67, 55, 52, 70, 51, 54, 69, 52, 67, 49, 70, 57, 50, 54, 48, 48, 49, 67, 69, 65, 68, 65, 57, 67, 65, 57, 55, 69, 65, 54, 50, 50, 66, 50, 53, 70, 52, 49, 69, 53, 69, 66, 50, 18, 72, 8, 8, 18, 68, 105, 98, 99, 47, 55, 67, 52, 68, 54, 48, 65, 65, 57, 53, 69, 53, 65, 55, 53, 53, 56, 66, 48, 65, 51, 54, 52, 56, 54, 48, 57, 55, 57, 67, 65, 51, 52, 66, 55, 70, 70, 56, 65, 65, 70, 50, 53, 53, 66, 56, 55, 65, 70, 57, 69, 56, 55, 57, 51, 55, 52, 52, 55, 48, 67, 69, 67, 48, 18, 9, 8, 7, 18, 5, 117, 111, 115, 109, 111, 26, 79, 10, 68, 105, 98, 99, 47, 52, 54, 66, 52, 52, 56, 57, 57, 51, 50, 50, 70, 51, 67, 68, 56, 53, 52, 68, 50, 68, 52, 54, 68, 69, 69, 70, 56, 56, 49, 57, 53, 56, 52, 54, 55, 67, 68, 68, 52, 66, 51, 66, 49, 48, 48, 56, 54, 68, 65, 52, 57, 50, 57, 54, 66, 66, 69, 68, 57, 52, 66, 69, 68, 18, 7, 49, 48, 48, 48, 48, 48, 48, 34, 7, 49, 53, 50, 53, 50, 54, 52]
1417
2181
  }],
1418
- memo: '',
1419
- source: null,
1420
- fee: {
1421
- gas: '900000',
1422
- amount: [{
1423
- denom: 'uosmo',
1424
- amount: '0'
1425
- }]
1426
- },
1427
- signType: 'AMINO',
1428
- rpcUrl: ''
1429
- },
1430
- rawTransfer: null
1431
- },
1432
- solanaTransaction: null,
1433
- evmTransaction: null,
1434
- evmApprovalTransaction: null,
1435
- transferTransaction: null,
1436
- diagnosisUrl: null,
1437
- internalSteps: null
1438
- }]
1439
- }];
1440
- function HistoryPage() {
1441
- const navigate = reactRouterDom.useNavigate();
1442
- return React__default.createElement(ui.History, {
1443
- list: pendingSwap,
1444
- onSwapClick: () => navigate(navigationRoutes.swapDetails),
1445
- onBack: () => {
1446
- navigate(-1);
1447
- }
1448
- });
1449
- }
1450
-
1451
- const ButtonsContainer = /*#__PURE__*/ui.styled('div', {
1452
- display: 'flex'
1453
- });
1454
- function HeaderButtons(props) {
1455
- const {
1456
- onClickRefresh
1457
- } = props;
1458
- const navigate = reactRouterDom.useNavigate();
1459
- return React__default.createElement(ButtonsContainer, null, React__default.createElement(ui.Tooltip, {
1460
- content: "Retry"
1461
- }, React__default.createElement(ui.Button, {
1462
- variant: "ghost",
1463
- onClick: onClickRefresh.bind(null)
1464
- }, React__default.createElement(ui.RetryIcon, {
1465
- size: 28
1466
- }))), React__default.createElement(ui.Tooltip, {
1467
- content: "Transactions History"
1468
- }, React__default.createElement(ui.Button, {
1469
- variant: "ghost",
1470
- onClick: () => navigate(navigationRoutes.history)
1471
- }, React__default.createElement(ui.HistoryIcon, {
1472
- size: 24
1473
- }))), React__default.createElement(ui.Tooltip, {
1474
- content: "Settings"
1475
- }, React__default.createElement(ui.Button, {
1476
- variant: "ghost",
1477
- onClick: () => navigate(navigationRoutes.settings)
1478
- }, React__default.createElement(ui.SettingsIcon, {
1479
- size: 24
1480
- }))));
1481
- }
1482
-
1483
- const HeaderContainer = /*#__PURE__*/ui.styled('div', {
1484
- display: 'flex',
1485
- justifyContent: 'space-between',
1486
- alignItems: 'center',
1487
- width: '100%',
1488
- padding: '$16 0'
1489
- });
1490
- function Header(props) {
1491
- const {
1492
- onClickRefresh
1493
- } = props;
1494
- return React__default.createElement(HeaderContainer, null, React__default.createElement(ui.Typography, {
1495
- variant: "h4"
1496
- }, "SWAP"), React__default.createElement(HeaderButtons, {
1497
- onClickRefresh: onClickRefresh
1498
- }));
1499
- }
1500
-
1501
- const Box = /*#__PURE__*/ui.styled('div', {
1502
- display: 'flex',
1503
- flexDirection: 'column',
1504
- width: '100%'
1505
- });
1506
- const Container = /*#__PURE__*/ui.styled('div', {
1507
- boxSizing: 'border-box',
1508
- backgroundColor: '$neutrals300',
1509
- borderRadius: '$5',
1510
- padding: '$8 0',
1511
- '.form': {
1512
- display: 'flex',
1513
- width: '100%',
1514
- padding: '$8 $16'
1515
- }
1516
- });
1517
- const StyledImage = /*#__PURE__*/ui.styled('img', {
1518
- width: '$24',
1519
- maxHeight: '$24'
1520
- });
1521
- const Options = /*#__PURE__*/ui.styled('div', {
1522
- display: 'flex',
1523
- justifyContent: 'flex-end',
1524
- padding: '0 $8'
1525
- });
1526
- const ImagePlaceholder = /*#__PURE__*/ui.styled('span', {
1527
- width: '24px',
1528
- height: '24px',
1529
- backgroundColor: '$neutrals300',
1530
- borderRadius: '99999px'
1531
- });
1532
- const OutputContainer = /*#__PURE__*/ui.styled('div', {
1533
- height: '$48',
1534
- borderRadius: '$5',
1535
- flexGrow: 1,
1536
- width: '70%',
1537
- backgroundColor: '$background',
1538
- border: '1px solid transparent',
1539
- position: 'relative',
1540
- display: 'flex',
1541
- alignItems: 'center',
1542
- paddingLeft: '$8',
1543
- paddingRight: '$8'
1544
- });
1545
- function TokenInfo(props) {
1546
- const {
1547
- type,
1548
- chain,
1549
- token
1550
- } = props;
1551
- const loadingStatus = useMetaStore.use.loadingStatus();
1552
- const fromChain = useBestRouteStore.use.fromChain();
1553
- const toChain = useBestRouteStore.use.toChain();
1554
- const inputUsdValue = useBestRouteStore.use.inputUsdValue();
1555
- const fromToken = useBestRouteStore.use.fromToken();
1556
- const setInputAmount = useBestRouteStore.use.setInputAmount();
1557
- const bestRoute = useBestRouteStore.use.bestRoute();
1558
- const inputAmount = useBestRouteStore.use.inputAmount();
1559
- const balances = useWalletsStore.use.balances();
1560
- const navigate = reactRouterDom.useNavigate();
1561
- const tokenBalance = !!fromChain && !!fromToken ? numberToString(getBalanceFromWallet(balances, fromChain?.name, fromToken?.symbol, fromToken?.address)?.amount || '0', 8) : '0';
1562
- const tokenBalanceReal = !!fromChain && !!fromToken ? numberToString(getBalanceFromWallet(balances, fromChain?.name, fromToken?.symbol, fromToken?.address)?.amount || '0', getBalanceFromWallet(balances, fromChain?.name, fromToken?.symbol, fromToken?.address)?.decimal) : '0';
1563
- const ItemSuffix = React__default.createElement("div", {
1564
- style: {
1565
- display: 'flex',
1566
- justifyContent: 'center',
1567
- alignItems: 'center'
1568
- }
1569
- }, loadingStatus === 'failed' && React__default.createElement(ui.InfoCircleIcon, {
1570
- color: "error",
1571
- size: 24
1572
- }), React__default.createElement(ui.AngleDownIcon, null));
1573
- return React__default.createElement(Box, null, React__default.createElement("div", null, React__default.createElement(ui.Typography, {
1574
- variant: "body2"
1575
- }, type)), React__default.createElement(Container, null, props.type === 'From' && React__default.createElement(Options, null, React__default.createElement("div", {
1576
- className: "balance",
1577
- onClick: () => {
1578
- if (tokenBalance !== '0') setInputAmount(tokenBalanceReal.split(',').join(''));
1579
- }
1580
- }, React__default.createElement(ui.Button, {
1581
- variant: "ghost",
1582
- size: "small"
1583
- }, React__default.createElement(ui.Typography, {
1584
- variant: "body2"
1585
- }, `Max: ${tokenBalance} ${fromToken?.symbol || ''}`)))), React__default.createElement("div", {
1586
- className: "form"
1587
- }, React__default.createElement(ui.Button, {
1588
- onClick: () => {
1589
- navigate(`/${props.type.toLowerCase()}-chain`);
1590
- },
1591
- variant: "outlined",
1592
- disabled: loadingStatus === 'failed',
1593
- loading: loadingStatus === 'loading',
1594
- prefix: loadingStatus === 'success' && chain ? React__default.createElement(StyledImage, {
1595
- src: chain.logo
1596
- }) : React__default.createElement(ImagePlaceholder, null),
1597
- suffix: ItemSuffix,
1598
- align: "start",
1599
- size: "large",
1600
- style: {
1601
- marginRight: '.5rem'
1602
- }
1603
- }, loadingStatus === 'success' && chain ? chain.displayName : 'Chain'), React__default.createElement(ui.Button, {
1604
- onClick: () => {
1605
- navigate(`/${props.type.toLowerCase()}-token`);
1606
- },
1607
- variant: "outlined",
1608
- disabled: loadingStatus === 'failed' || type === 'From' && !fromChain || type === 'To' && !toChain,
1609
- loading: loadingStatus === 'loading',
1610
- prefix: loadingStatus === 'success' && token ? React__default.createElement(StyledImage, {
1611
- src: token.image
1612
- }) : React__default.createElement(ImagePlaceholder, null),
1613
- suffix: ItemSuffix,
1614
- size: "large",
1615
- align: "start",
1616
- style: {
1617
- marginRight: '.5rem'
1618
- }
1619
- }, loadingStatus === 'success' && token ? token.symbol : 'Token'), props.type === 'From' ? React__default.createElement(ui.TextField, {
1620
- type: "number",
1621
- size: "large",
1622
- autoFocus: true,
1623
- placeholder: "0",
1624
- style: {
1625
- width: '70%',
1626
- position: 'relative',
1627
- backgroundColor: '$background !important'
2182
+ memo: '',
2183
+ source: null,
2184
+ fee: {
2185
+ gas: '900000',
2186
+ amount: [{
2187
+ denom: 'uosmo',
2188
+ amount: '0'
2189
+ }]
2190
+ },
2191
+ signType: 'AMINO',
2192
+ rpcUrl: ''
2193
+ },
2194
+ rawTransfer: null
1628
2195
  },
1629
- suffix: React__default.createElement("span", {
1630
- style: {
1631
- position: 'absolute',
1632
- right: '4px',
1633
- bottom: '2px'
1634
- }
1635
- }, React__default.createElement(ui.Typography, {
1636
- variant: "caption"
1637
- }, `$${numberToString(inputUsdValue)}`)),
1638
- value: props.inputAmount || '',
1639
- onChange: props.type === 'From' ? event => {
1640
- props.onAmountChange(event.target.value);
1641
- } : undefined
1642
- }) : React__default.createElement(OutputContainer, null, React__default.createElement(ui.Typography, {
1643
- variant: "body1"
1644
- }, bestRoute ? `≈ ${numberToString(props.outputAmount)}` : inputAmount ? '?' : '0'), React__default.createElement("span", {
1645
- style: {
1646
- position: 'absolute',
1647
- right: '4px',
1648
- bottom: '2px'
1649
- }
1650
- }, React__default.createElement(ui.Typography, {
1651
- variant: "caption"
1652
- }, `$${numberToString(props.outputUsdValue)}`))))));
1653
- }
1654
-
1655
- const Container$1 = /*#__PURE__*/theme.styled('div', {
1656
- display: 'flex',
1657
- width: '100%',
1658
- justifyContent: 'end',
1659
- alignItems: 'center',
1660
- paddingTop: '$16'
1661
- });
1662
- const Logo = /*#__PURE__*/theme.styled('svg', {
1663
- fill: '$foreground',
1664
- width: '$24',
1665
- margin: '0 $8 0 $16'
1666
- });
1667
- const StyledAnchor = /*#__PURE__*/theme.styled('a', {
1668
- display: 'flex',
1669
- justifyContent: 'center',
1670
- alignItems: 'center',
1671
- textDecoration: 'none'
1672
- });
1673
- function BottomLogo() {
1674
- return React__default.createElement(Container$1, null, React__default.createElement(ui.Typography, {
1675
- variant: "caption"
1676
- }, "Powered By"), React__default.createElement(StyledAnchor, {
1677
- href: "https://rango.exchange",
1678
- target: "_blank"
1679
- }, React__default.createElement(Logo, {
1680
- xmlns: "http://www.w3.org/2000/svg",
1681
- viewBox: "0 0 33.68 29"
1682
- }, React__default.createElement("defs", null), React__default.createElement("g", {
1683
- id: "Layer_2",
1684
- "data-name": "Layer 2"
1685
- }, React__default.createElement("g", {
1686
- id: "Layer_1-2",
1687
- "data-name": "Layer 1"
1688
- }, React__default.createElement("path", {
1689
- d: "M33.68,18.05A17.93,17.93,0,0,0,28.34,5.29,18.31,18.31,0,0,0,15.45,0H13.54V7.41L6.07,0H.69L9.83,9.07H0V11A17.93,17.93,0,0,0,5.34,23.71,18.32,18.32,0,0,0,18.24,29h1.9V21.59l7.38,7.31h5.39l-9-9h9.82ZM17.37,16.16H12.49a1.93,1.93,0,0,0-1.35.55,1.89,1.89,0,0,0-.56,1.34,1.85,1.85,0,0,0,.56,1.33,1.93,1.93,0,0,0,1.35.55h3.84V25.1A14.43,14.43,0,0,1,8,21a14.21,14.21,0,0,1-4.1-8.2H21.2a1.86,1.86,0,0,0,.74-.13,1.92,1.92,0,0,0,.64-.4,2,2,0,0,0,.43-.62,1.88,1.88,0,0,0,0-1.47,2,2,0,0,0-.43-.62,1.92,1.92,0,0,0-.64-.4,1.86,1.86,0,0,0-.74-.13H17.35V3.9A14.43,14.43,0,0,1,25.64,8a14.19,14.19,0,0,1,4.11,8.2Zm2.12-5.27a1.43,1.43,0,0,1,.26-.83,1.52,1.52,0,0,1,.67-.56,1.55,1.55,0,0,1,.88-.08,1.51,1.51,0,0,1,.77.4,1.54,1.54,0,0,1,.42.77,1.41,1.41,0,0,1-.09.86,1.47,1.47,0,0,1-.55.68,1.56,1.56,0,0,1-.84.25,1.52,1.52,0,0,1-1.52-1.49Z"
1690
- }), React__default.createElement("path", {
1691
- d: "M21.7,11.57a.68.68,0,0,0-.12-.38.64.64,0,0,0-.31-.25.68.68,0,0,0-.75.15.61.61,0,0,0-.19.35.62.62,0,0,0,0,.4.67.67,0,0,0,.25.3.69.69,0,0,0,.39.12.7.7,0,0,0,.49-.2A.68.68,0,0,0,21.7,11.57Z"
1692
- })))), React__default.createElement(ui.Typography, {
1693
- variant: "body2"
1694
- }, "RANGO")));
1695
- }
1696
-
1697
- function SwithFromAndTo(_ref) {
1698
- let {
1699
- count
1700
- } = _ref;
1701
- const firstRender = React.useRef(true);
1702
- const [searchParams, setSearchParams] = reactRouterDom.useSearchParams();
1703
- const outputAmount = useBestRouteStore.use.outputAmount();
1704
- React.useEffect(() => {
1705
- if (!firstRender.current) {
1706
- const fromChainString = searchParams.get(SearchParams.FROM_CHAIN);
1707
- const fromTokenString = searchParams.get(SearchParams.FROM_TOKEN);
1708
- const toChainString = searchParams.get(SearchParams.TO_CHAIN);
1709
- const toTokenString = searchParams.get(SearchParams.TO_TOKEN);
1710
- setSearchParams({
1711
- ...(toChainString && {
1712
- [SearchParams.FROM_CHAIN]: toChainString
1713
- }),
1714
- ...(toTokenString && {
1715
- [SearchParams.FROM_TOKEN]: toTokenString
1716
- }),
1717
- ...(fromChainString && {
1718
- [SearchParams.TO_CHAIN]: fromChainString
1719
- }),
1720
- ...(fromTokenString && {
1721
- [SearchParams.TO_TOKEN]: fromTokenString
1722
- }),
1723
- ...(outputAmount && {
1724
- [SearchParams.FROM_AMOUNT]: outputAmount.toString()
1725
- })
1726
- });
1727
- } else {
1728
- firstRender.current = false;
2196
+ solanaTransaction: null,
2197
+ evmTransaction: null,
2198
+ evmApprovalTransaction: null,
2199
+ transferTransaction: null,
2200
+ diagnosisUrl: null,
2201
+ internalSteps: null
2202
+ }]
2203
+ }, {
2204
+ creationTime: '1673164511955',
2205
+ finishTime: '1673164550137',
2206
+ requestId: '51e211d9-d61c-45d2-a4d4-1f9f7f90ee85',
2207
+ inputAmount: '1',
2208
+ wallets: {
2209
+ OSMOSIS: {
2210
+ walletType: 'keplr',
2211
+ address: 'osmo1unf2rcytjxfpz8x8ar63h4qeftadptg5t0nqcl'
1729
2212
  }
1730
- }, [count]);
1731
- return null;
1732
- }
1733
-
1734
- const Footer = /*#__PURE__*/ui.styled('div', {
1735
- display: 'flex',
1736
- flexDirection: 'column',
1737
- width: '100%',
1738
- paddingTop: '$16'
1739
- });
1740
-
1741
- function useBestRoute() {
1742
- const fromToken = useBestRouteStore.use.fromToken();
1743
- const toToken = useBestRouteStore.use.toToken();
1744
- const inputAmount = useBestRouteStore.use.inputAmount();
1745
- const slippage = useSettingsStore.use.slippage();
1746
- const customSlippage = useSettingsStore.use.customSlippage();
1747
- const disabledLiquiditySources = useSettingsStore.use.disabledLiquiditySources();
1748
- const [count, setCount] = React.useState(0);
1749
- const [loading, setLoading] = React.useState(false);
1750
- const [error, setError] = React.useState('');
1751
- const [data, setData] = React.useState(null);
1752
- const abortControllerRef = React.useRef(null);
1753
- const retry = () => {
1754
- setCount(prev => prev + 1);
1755
- };
1756
- React.useEffect(() => {
1757
- if (abortControllerRef.current) abortControllerRef.current.abort();
1758
- const abortController = new AbortController();
1759
- abortControllerRef.current = abortController;
1760
- if (!!fromToken && !!toToken && !!inputAmount) {
1761
- if (!!data) setData(null);
1762
- const requestBody = {
1763
- amount: inputAmount?.toString(),
1764
- connectedWallets: [],
1765
- selectedWallets: {},
1766
- checkPrerequisites: false,
1767
- swapperGroups: disabledLiquiditySources,
1768
- swappersGroupsExclude: true,
1769
- from: {
1770
- address: fromToken.address,
1771
- blockchain: fromToken.blockchain,
1772
- symbol: fromToken.symbol
2213
+ },
2214
+ status: 'success',
2215
+ isPaused: false,
2216
+ extraMessage: null,
2217
+ extraMessageSeverity: 'info',
2218
+ extraMessageDetail: '',
2219
+ extraMessageErrorCode: null,
2220
+ networkStatusExtraMessage: null,
2221
+ networkStatusExtraMessageDetail: null,
2222
+ lastNotificationTime: null,
2223
+ settings: {
2224
+ slippage: '1.0',
2225
+ disabledSwappersIds: [],
2226
+ disabledSwappersGroups: []
2227
+ },
2228
+ simulationResult: {
2229
+ outputAmount: '1.540670',
2230
+ swaps: [{
2231
+ // @ts-ignore
2232
+ result: [],
2233
+ swapperId: 'Osmosis',
2234
+ swapperType: 'DEX',
2235
+ swapperLogo: '',
2236
+ from: {
2237
+ symbol: 'JUNO',
2238
+ logo: 'https://api.rango.exchange/tokens/COSMOS/JUNO.png',
2239
+ address: 'ibc/46b44899322f3cd854d2d46deef881958467cdd4b3b10086da49296bbed94bed',
2240
+ blockchain: 'OSMOSIS',
2241
+ blockchainLogo: '',
2242
+ decimals: 6,
2243
+ usdPrice: 1.1091996179668873
2244
+ },
2245
+ to: {
2246
+ symbol: 'OSMO',
2247
+ logo: 'https://api.rango.exchange/i/mJQPS2',
2248
+ address: null,
2249
+ blockchain: 'OSMOSIS',
2250
+ decimals: 6,
2251
+ blockchainLogo: '',
2252
+ usdPrice: 0.7192435454440882
2253
+ },
2254
+ fromAmount: '1.000000',
2255
+ fromAmountPrecision: null,
2256
+ fromAmountMinValue: null,
2257
+ fromAmountMaxValue: null,
2258
+ toAmount: '1.540670',
2259
+ fee: [{
2260
+ name: '',
2261
+ asset: {
2262
+ blockchain: 'OSMOSIS',
2263
+ symbol: 'OSMO',
2264
+ address: null
2265
+ },
2266
+ expenseType: 'FROM_SOURCE_WALLET',
2267
+ amount: '0'
2268
+ }],
2269
+ estimatedTimeInSeconds: 45,
2270
+ swapChainType: 'INTRA_CHAIN',
2271
+ routes: [{
2272
+ nodes: [{
2273
+ nodes: [{
2274
+ marketName: 'pool#498',
2275
+ marketId: null,
2276
+ percent: 1
2277
+ }],
2278
+ from: 'JUNO',
2279
+ fromLogo: 'https://api.rango.exchange/tokens/COSMOS/JUNO.png',
2280
+ fromAddress: 'ibc/46b44899322f3cd854d2d46deef881958467cdd4b3b10086da49296bbed94bed',
2281
+ fromBlockchain: 'OSMOSIS',
2282
+ to: 'ATOM',
2283
+ toLogo: 'https://api.rango.exchange/tokens/COSMOS/ATOM.png',
2284
+ toAddress: 'ibc/27394fb092d2eccd56123c74f36e4c1f926001ceada9ca97ea622b25f41e5eb2',
2285
+ toBlockchain: 'OSMOSIS'
2286
+ }, {
2287
+ nodes: [{
2288
+ marketName: 'pool#8',
2289
+ marketId: null,
2290
+ percent: 1
2291
+ }],
2292
+ from: 'ATOM',
2293
+ fromLogo: 'https://api.rango.exchange/tokens/COSMOS/ATOM.png',
2294
+ fromAddress: 'ibc/27394fb092d2eccd56123c74f36e4c1f926001ceada9ca97ea622b25f41e5eb2',
2295
+ fromBlockchain: 'OSMOSIS',
2296
+ to: 'IRIS',
2297
+ toLogo: 'https://api.rango.exchange/tokens/COSMOS/IRIS.png',
2298
+ toAddress: 'ibc/7c4d60aa95e5a7558b0a364860979ca34b7ff8aaf255b87af9e879374470cec0',
2299
+ toBlockchain: 'OSMOSIS'
2300
+ }, {
2301
+ nodes: [{
2302
+ marketName: 'pool#7',
2303
+ marketId: null,
2304
+ percent: 1
2305
+ }],
2306
+ from: 'IRIS',
2307
+ fromLogo: 'https://api.rango.exchange/tokens/COSMOS/IRIS.png',
2308
+ fromAddress: 'ibc/7c4d60aa95e5a7558b0a364860979ca34b7ff8aaf255b87af9e879374470cec0',
2309
+ fromBlockchain: 'OSMOSIS',
2310
+ to: 'OSMO',
2311
+ toLogo: 'https://api.rango.exchange/tokens/COSMOS/OSMO.png',
2312
+ toAddress: null,
2313
+ toBlockchain: 'OSMOSIS'
2314
+ }]
2315
+ }],
2316
+ recommendedSlippage: null,
2317
+ timeStat: {
2318
+ min: 6,
2319
+ avg: 40,
2320
+ max: 241
2321
+ },
2322
+ includesDestinationTx: false
2323
+ }]
2324
+ },
2325
+ validateBalanceOrFee: true,
2326
+ steps: [{
2327
+ id: 1,
2328
+ fromBlockchain: 'OSMOSIS',
2329
+ fromSymbol: 'JUNO',
2330
+ fromSymbolAddress: 'ibc/46b44899322f3cd854d2d46deef881958467cdd4b3b10086da49296bbed94bed',
2331
+ fromDecimals: 6,
2332
+ fromAmountPrecision: null,
2333
+ fromAmountMinValue: null,
2334
+ swapperLogo: '',
2335
+ swapperType: '',
2336
+ fromAmountMaxValue: null,
2337
+ toBlockchainLogo: 'https://api.rango.exchange/swappers/osmosis.png',
2338
+ fromBlockchainLogo: 'https://api.rango.exchange/swappers/osmosis.png',
2339
+ toBlockchain: 'OSMOSIS',
2340
+ fromLogo: 'https://api.rango.exchange/tokens/COSMOS/JUNO.png',
2341
+ toSymbol: 'OSMO',
2342
+ toSymbolAddress: null,
2343
+ toDecimals: 6,
2344
+ toLogo: 'https://api.rango.exchange/i/mJQPS2',
2345
+ startTransactionTime: 1673164519916,
2346
+ swapperId: 'Osmosis',
2347
+ expectedOutputAmountHumanReadable: '1.540670',
2348
+ outputAmount: '1.540658',
2349
+ status: 'success',
2350
+ networkStatus: null,
2351
+ executedTransactionId: '0f8f17eecc863c2d6be65ef52cfe3128ff3cd7baeddf133160bea8ccdfbf876b',
2352
+ explorerUrl: [{
2353
+ url: 'https://www.mintscan.io/osmosis/txs/0f8f17eecc863c2d6be65ef52cfe3128ff3cd7baeddf133160bea8ccdfbf876b',
2354
+ description: null
2355
+ }],
2356
+ cosmosTransaction: {
2357
+ type: rangoSdk.TransactionType.COSMOS,
2358
+ fromWalletAddress: 'osmo1unf2rcytjxfpz8x8ar63h4qeftadptg5t0nqcl',
2359
+ blockChain: 'OSMOSIS',
2360
+ data: {
2361
+ chainId: 'osmosis-1',
2362
+ account_number: 102721,
2363
+ sequence: '308',
2364
+ msgs: [{
2365
+ __type: 'OsmosisSwapMessage',
2366
+ type: 'osmosis/gamm/swap-exact-amount-in',
2367
+ value: {
2368
+ sender: 'osmo1unf2rcytjxfpz8x8ar63h4qeftadptg5t0nqcl',
2369
+ routes: [{
2370
+ pool_id: '498',
2371
+ token_out_denom: 'ibc/27394FB092D2ECCD56123C74F36E4C1F926001CEADA9CA97EA622B25F41E5EB2'
2372
+ }, {
2373
+ pool_id: '8',
2374
+ token_out_denom: 'ibc/7C4D60AA95E5A7558B0A364860979CA34B7FF8AAF255B87AF9E879374470CEC0'
2375
+ }, {
2376
+ pool_id: '7',
2377
+ token_out_denom: 'uosmo'
2378
+ }],
2379
+ token_in: {
2380
+ denom: 'ibc/46B44899322F3CD854D2D46DEEF881958467CDD4B3B10086DA49296BBED94BED',
2381
+ amount: '1000000'
2382
+ },
2383
+ token_out_min_amount: '1525264'
2384
+ }
2385
+ }],
2386
+ protoMsgs: [{
2387
+ type_url: '/osmosis.gamm.v1beta1.MsgSwapExactAmountIn',
2388
+ value: [10, 43, 111, 115, 109, 111, 49, 117, 110, 102, 50, 114, 99, 121, 116, 106, 120, 102, 112, 122, 56, 120, 56, 97, 114, 54, 51, 104, 52, 113, 101, 102, 116, 97, 100, 112, 116, 103, 53, 116, 48, 110, 113, 99, 108, 18, 73, 8, -14, 3, 18, 68, 105, 98, 99, 47, 50, 55, 51, 57, 52, 70, 66, 48, 57, 50, 68, 50, 69, 67, 67, 68, 53, 54, 49, 50, 51, 67, 55, 52, 70, 51, 54, 69, 52, 67, 49, 70, 57, 50, 54, 48, 48, 49, 67, 69, 65, 68, 65, 57, 67, 65, 57, 55, 69, 65, 54, 50, 50, 66, 50, 53, 70, 52, 49, 69, 53, 69, 66, 50, 18, 72, 8, 8, 18, 68, 105, 98, 99, 47, 55, 67, 52, 68, 54, 48, 65, 65, 57, 53, 69, 53, 65, 55, 53, 53, 56, 66, 48, 65, 51, 54, 52, 56, 54, 48, 57, 55, 57, 67, 65, 51, 52, 66, 55, 70, 70, 56, 65, 65, 70, 50, 53, 53, 66, 56, 55, 65, 70, 57, 69, 56, 55, 57, 51, 55, 52, 52, 55, 48, 67, 69, 67, 48, 18, 9, 8, 7, 18, 5, 117, 111, 115, 109, 111, 26, 79, 10, 68, 105, 98, 99, 47, 52, 54, 66, 52, 52, 56, 57, 57, 51, 50, 50, 70, 51, 67, 68, 56, 53, 52, 68, 50, 68, 52, 54, 68, 69, 69, 70, 56, 56, 49, 57, 53, 56, 52, 54, 55, 67, 68, 68, 52, 66, 51, 66, 49, 48, 48, 56, 54, 68, 65, 52, 57, 50, 57, 54, 66, 66, 69, 68, 57, 52, 66, 69, 68, 18, 7, 49, 48, 48, 48, 48, 48, 48, 34, 7, 49, 53, 50, 53, 50, 54, 52]
2389
+ }],
2390
+ memo: '',
2391
+ source: null,
2392
+ fee: {
2393
+ gas: '900000',
2394
+ amount: [{
2395
+ denom: 'uosmo',
2396
+ amount: '0'
2397
+ }]
1773
2398
  },
1774
- to: {
1775
- address: toToken.address,
1776
- blockchain: toToken.blockchain,
1777
- symbol: toToken.symbol
1778
- }
1779
- };
1780
- setLoading(true);
1781
- httpService.getBestRoute(requestBody, {
1782
- signal: abortControllerRef.current.signal
1783
- }).then(res => {
1784
- setData(res);
1785
- setLoading(false);
1786
- abortControllerRef.current = null;
1787
- }).catch(error => {
1788
- if (error.code === 'ERR_CANCELED') return;
1789
- setError(error.message);
1790
- setLoading(false);
1791
- });
1792
- }
1793
- }, [fromToken, toToken, inputAmount, count, slippage, customSlippage, disabledLiquiditySources.length]);
1794
- return {
1795
- loading,
1796
- error,
1797
- data,
1798
- retry
1799
- };
1800
- }
1801
-
1802
- const errorMessages = {
1803
- genericServerError: 'Error connecting server, please reload the app and try again'
1804
- };
1805
-
1806
- function getOutputRatio(inputUsdValue, outputUsdValue) {
1807
- if (inputUsdValue.lte(ZERO) || outputUsdValue.lte(ZERO)) return 0;
1808
- return outputUsdValue.div(inputUsdValue).minus(1).multipliedBy(100);
1809
- }
1810
- function outputRatioHasWarning(inputUsdValue, outputRatio) {
1811
- return parseInt(outputRatio.toFixed(2) || '0') <= -10 && inputUsdValue.gte(new BigNumber__default(400)) || parseInt(outputRatio.toFixed(2) || '0') <= -5 && inputUsdValue.gte(new BigNumber__default(1000));
1812
- }
1813
- function hasLimitError(bestRoute) {
1814
- return (bestRoute?.result?.swaps || []).filter(swap => {
1815
- const minimum = !!swap.fromAmountMinValue ? new BigNumber__default(swap.fromAmountMinValue) : null;
1816
- const maximum = !!swap.fromAmountMaxValue ? new BigNumber__default(swap.fromAmountMaxValue) : null;
1817
- const isExclusive = swap.fromAmountRestrictionType === 'EXCLUSIVE';
1818
- if (isExclusive) {
1819
- return minimum?.gte(swap.fromAmount) || maximum?.lte(swap.fromAmount);
1820
- } else {
1821
- return minimum?.gt(swap.fromAmount) || maximum?.lt(swap.fromAmount);
1822
- }
1823
- }).length > 0;
1824
- }
1825
- function getSwapButtonTitle(accounts, loading, hasLimitError, highValueLoss, priceImpactCanNotBeComputed, needsToWarnEthOnPath) {
1826
- if (loading) return 'Finding Best Route...';
1827
- if (accounts.length == 0) return 'Connect Wallet';else if (hasLimitError) return 'Limit Error';else if (highValueLoss) return 'Price impact is too high!';else if (priceImpactCanNotBeComputed) return 'USD price is unknown, price impact might be high!';else if (needsToWarnEthOnPath) return 'The route goes through Ethereum. Continue?';else return 'Swap';
1828
- }
1829
- function canComputePriceImpact(bestRoute, inputAmount, inputUsdValue, outputUsdValue) {
1830
- return !((inputUsdValue.lte(ZERO) || outputUsdValue.lte(ZERO)) && !!bestRoute?.result && !!inputAmount && inputAmount !== '0' && parseFloat(inputAmount || '0') !== 0);
1831
- }
1832
- function requiredWallets(route) {
1833
- const wallets = [];
1834
- route?.result?.swaps.forEach(swap => {
1835
- const currentStepFromBlockchain = swap.from.blockchain;
1836
- const currentStepToBlockchain = swap.to.blockchain;
1837
- let lastAddedWallet = wallets[wallets.length - 1];
1838
- if (currentStepFromBlockchain != lastAddedWallet) wallets.push(currentStepFromBlockchain);
1839
- lastAddedWallet = wallets[wallets.length - 1];
1840
- if (currentStepToBlockchain != lastAddedWallet) wallets.push(currentStepToBlockchain);
1841
- });
1842
- return wallets;
1843
- }
1844
-
1845
- const Container$2 = /*#__PURE__*/ui.styled('div', {
1846
- display: 'flex',
1847
- flexDirection: 'column',
1848
- justifyContent: 'center',
1849
- alignItems: 'center'
1850
- });
1851
- const SwitchButtonContainer = /*#__PURE__*/ui.styled('div', {
1852
- display: 'flex',
1853
- justifyContent: 'center',
1854
- alignItems: 'center',
1855
- position: 'relative',
1856
- top: '11px'
1857
- });
1858
- const BestRouteContainer = /*#__PURE__*/ui.styled('div', {
1859
- width: '100%',
1860
- paddingTop: '$16'
1861
- });
1862
- const Alerts = /*#__PURE__*/ui.styled('div', {
1863
- paddingTop: '$16'
1864
- });
1865
- function Home() {
1866
- const waningMessage = '';
1867
- const isRouterInContext = reactRouterDom.useInRouterContext();
2399
+ signType: 'AMINO',
2400
+ rpcUrl: ''
2401
+ },
2402
+ rawTransfer: null
2403
+ },
2404
+ solanaTransaction: null,
2405
+ evmTransaction: null,
2406
+ evmApprovalTransaction: null,
2407
+ transferTransaction: null,
2408
+ diagnosisUrl: null,
2409
+ internalSteps: null
2410
+ }]
2411
+ }];
2412
+ function HistoryPage() {
1868
2413
  const navigate = reactRouterDom.useNavigate();
1869
- const [count, setCount] = React.useState(0);
1870
- const fromChain = useBestRouteStore.use.fromChain();
1871
- const fromToken = useBestRouteStore.use.fromToken();
1872
- const toChain = useBestRouteStore.use.toChain();
1873
- const toToken = useBestRouteStore.use.toToken();
1874
- const setFromChain = useBestRouteStore.use.setFromChain();
1875
- const setFromToken = useBestRouteStore.use.setFromToken();
1876
- const setToChain = useBestRouteStore.use.setToChain();
1877
- const setToToken = useBestRouteStore.use.setToToken();
1878
- const setBestRoute = useBestRouteStore.use.setBestRoute();
1879
- const inputUsdValue = useBestRouteStore.use.inputUsdValue();
1880
- const inputAmount = useBestRouteStore.use.inputAmount();
1881
- const setInputAmount = useBestRouteStore.use.setInputAmount();
1882
- const outputAmount = useBestRouteStore.use.outputAmount();
1883
- const outputUsdValue = useBestRouteStore.use.outputUsdValue();
1884
- const bestRoute = useBestRouteStore.use.bestRoute();
1885
- const loadingMetaStatus = useMetaStore.use.loadingStatus();
1886
- const accounts = useWalletsStore.use.accounts();
1887
- const swithFromAndTo = () => {
1888
- setFromChain(toChain);
1889
- setFromToken(toToken);
1890
- setToChain(fromChain);
1891
- setToToken(fromToken);
1892
- setInputAmount(outputAmount?.toString() || '');
1893
- setCount(prev => prev + 1);
1894
- };
1895
2414
  const {
1896
- data,
1897
- loading: fetchingBestRoute,
1898
- error: bestRouteError,
1899
- retry
1900
- } = useBestRoute();
1901
- const noConnectedWallet = accounts.length > 0;
1902
- const noRoutesFound = !bestRoute?.result;
1903
- const errorMessage = loadingMetaStatus === 'failed' ? errorMessages.genericServerError : bestRouteError;
1904
- const needsToWarnEthOnPath = false;
1905
- const showBestRoute = inputAmount && (!!data || fetchingBestRoute || bestRouteError);
1906
- const outToInRatio = getOutputRatio(inputUsdValue, outputUsdValue);
1907
- const highValueLoss = outputRatioHasWarning(inputUsdValue, outToInRatio);
1908
- const priceImpactCanNotBeComputed = !canComputePriceImpact(bestRoute, inputAmount, inputUsdValue, outputUsdValue);
1909
- const buttonTitle = getSwapButtonTitle(accounts, fetchingBestRoute, hasLimitError(bestRoute), highValueLoss, priceImpactCanNotBeComputed, needsToWarnEthOnPath);
1910
- const buttonDisabled = loadingMetaStatus != 'success' || fetchingBestRoute || highValueLoss || noConnectedWallet && noRoutesFound || hasLimitError(bestRoute);
1911
- React.useEffect(() => {
1912
- setBestRoute(data);
1913
- }, [data]);
1914
- return React__default.createElement(Container$2, null, React__default.createElement(Header, {
1915
- onClickRefresh: retry
1916
- }), React__default.createElement(TokenInfo, {
1917
- type: "From",
1918
- chain: fromChain,
1919
- token: fromToken,
1920
- onAmountChange: setInputAmount,
1921
- inputAmount: inputAmount
1922
- }), React__default.createElement(SwitchButtonContainer, null, React__default.createElement(ui.Button, {
1923
- variant: "ghost",
1924
- onClick: swithFromAndTo
1925
- }, React__default.createElement(ui.VerticalSwapIcon, {
1926
- size: 36
1927
- }), isRouterInContext && React__default.createElement(SwithFromAndTo, {
1928
- count: count
1929
- }))), React__default.createElement(TokenInfo, {
1930
- type: "To",
1931
- chain: toChain,
1932
- token: toToken,
1933
- outputAmount: outputAmount,
1934
- outputUsdValue: outputUsdValue
1935
- }), showBestRoute && React__default.createElement(BestRouteContainer, null, React__default.createElement(ui.BestRoute, {
1936
- error: bestRouteError,
1937
- loading: fetchingBestRoute,
1938
- data: data
1939
- })), (errorMessage || waningMessage) && React__default.createElement(Alerts, null, errorMessage && React__default.createElement(ui.Alert, {
1940
- description: errorMessage,
1941
- type: "error"
1942
- }), waningMessage ), React__default.createElement(Footer, null, React__default.createElement(ui.Button, {
1943
- type: "primary",
1944
- align: "grow",
1945
- size: "large",
1946
- disabled: buttonDisabled,
1947
- onClick: () => {
1948
- if (buttonTitle === 'Connect Wallet') navigate(navigationRoutes.wallets);else {
1949
- navigate(navigationRoutes.confirmWallets);
1950
- }
1951
- }
1952
- }, buttonTitle), React__default.createElement(BottomLogo, null)));
2415
+ navigateBackFrom
2416
+ } = useNavigateBack();
2417
+ return React__default.createElement(ui.History, {
2418
+ list: pendingSwap,
2419
+ onSwapClick: navigate.bind(null, navigationRoutes.swapDetails),
2420
+ onBack: navigateBackFrom.bind(null, navigationRoutes.history)
2421
+ });
1953
2422
  }
1954
2423
 
1955
2424
  function LiquiditySourcePage() {
@@ -1959,7 +2428,9 @@ function LiquiditySourcePage() {
1959
2428
  const toggleLiquiditySource = useSettingsStore.use.toggleLiquiditySource();
1960
2429
  const disabledLiquiditySources = useSettingsStore.use.disabledLiquiditySources();
1961
2430
  const toggleAllLiquiditySources = useSettingsStore.use.toggleAllLiquiditySources();
1962
- const navigate = reactRouterDom.useNavigate();
2431
+ const {
2432
+ navigateBackFrom
2433
+ } = useNavigateBack();
1963
2434
  const uniqueSwappersGroups = [];
1964
2435
  removeDuplicateFrom(swappers.map(s => s.swapperGroup)).map(swapperGroup => {
1965
2436
  return swappers.find(s => s.swapperGroup === swapperGroup);
@@ -1979,9 +2450,7 @@ function LiquiditySourcePage() {
1979
2450
  toggleAll: toggleAllLiquiditySources,
1980
2451
  list: uniqueSwappersGroups,
1981
2452
  onChange: liquiditySource => toggleLiquiditySource(liquiditySource.title),
1982
- onBack: () => {
1983
- navigate(-1);
1984
- }
2453
+ onBack: navigateBackFrom.bind(null, navigationRoutes.liquiditySources)
1985
2454
  });
1986
2455
  }
1987
2456
 
@@ -1989,7 +2458,6 @@ function SelectChainPage(props) {
1989
2458
  const {
1990
2459
  type
1991
2460
  } = props;
1992
- const accounts = useWalletsStore.use.accounts();
1993
2461
  const {
1994
2462
  blockchains
1995
2463
  } = useMetaStore.use.meta();
@@ -2000,30 +2468,21 @@ function SelectChainPage(props) {
2000
2468
  const setToChain = useBestRouteStore.use.setToChain();
2001
2469
  const setFromToken = useBestRouteStore.use.setFromToken();
2002
2470
  const setToToken = useBestRouteStore.use.setToToken();
2003
- const navigate = reactRouterDom.useNavigate();
2004
- const [list, setList] = React.useState(blockchains);
2005
- React.useEffect(() => {
2006
- let chainSortedByConnectedWallets = [];
2007
- if (accounts.length !== 0) {
2008
- const connectedChains = removeDuplicateFrom(accounts.map(account => account.chain));
2009
- chainSortedByConnectedWallets = blockchains.sort((blockchainA, blockchainB) => connectedChains.lastIndexOf(blockchainA.name) - connectedChains.lastIndexOf(blockchainB.name));
2010
- } else {
2011
- chainSortedByConnectedWallets = blockchains;
2012
- }
2013
- setList(chainSortedByConnectedWallets);
2014
- }, [blockchains.length, accounts.length]);
2471
+ const {
2472
+ navigateBackFrom
2473
+ } = useNavigateBack();
2015
2474
  return React__default.createElement(ui.BlockchainSelector, {
2016
2475
  type: type === 'from' ? 'Source' : 'Destination',
2017
- list: list,
2476
+ list: blockchains,
2018
2477
  selected: type === 'from' ? fromChain : toChain,
2019
2478
  loadingStatus: loadingStatus,
2020
2479
  onChange: chain => {
2021
2480
  if (type === 'from') setFromChain(chain);else setToChain(chain);
2022
2481
  if (type === 'from' && fromChain?.name != chain.name) setFromToken(null);
2023
2482
  if (type === 'to' && toChain?.name != chain.name) setToToken(null);
2024
- navigate(-1);
2483
+ navigateBackFrom(navigationRoutes.fromChain);
2025
2484
  },
2026
- onBack: navigate.bind(null, -1)
2485
+ onBack: navigateBackFrom.bind(null, navigationRoutes.fromChain)
2027
2486
  });
2028
2487
  }
2029
2488
 
@@ -2031,7 +2490,9 @@ function SelectTokenPage(props) {
2031
2490
  const {
2032
2491
  type
2033
2492
  } = props;
2034
- const navigate = reactRouterDom.useNavigate();
2493
+ const {
2494
+ navigateBackFrom
2495
+ } = useNavigateBack();
2035
2496
  const {
2036
2497
  tokens
2037
2498
  } = useMetaStore.use.meta();
@@ -2065,9 +2526,9 @@ function SelectTokenPage(props) {
2065
2526
  selected: type === 'from' ? fromToken : toToken,
2066
2527
  onChange: token => {
2067
2528
  if (type === 'from') setFromToken(token);else setToToken(token);
2068
- navigate(-1);
2529
+ navigateBackFrom(navigationRoutes.fromToken);
2069
2530
  },
2070
- onBack: navigate.bind(null, -1)
2531
+ onBack: navigateBackFrom.bind(null, navigationRoutes.fromToken)
2071
2532
  });
2072
2533
  }
2073
2534
 
@@ -2083,6 +2544,11 @@ function SettingsPage() {
2083
2544
  swappers
2084
2545
  } = useMetaStore.use.meta();
2085
2546
  const navigate = reactRouterDom.useNavigate();
2547
+ const {
2548
+ navigateBackFrom
2549
+ } = useNavigateBack();
2550
+ const infiniteApprove = useSettingsStore.use.infiniteApprove();
2551
+ const toggleInfiniteApprove = useSettingsStore.use.toggleInfiniteApprove();
2086
2552
  const uniqueSwappersGroups = [];
2087
2553
  removeDuplicateFrom(swappers.map(s => s.swapperGroup)).map(swapperGroup => {
2088
2554
  return swappers.find(s => s.swapperGroup === swapperGroup);
@@ -2099,19 +2565,21 @@ function SettingsPage() {
2099
2565
  }
2100
2566
  });
2101
2567
  return React__default.createElement(ui.Settings, {
2102
- slippages: [1, 2, 3, 4],
2568
+ slippages: SLIPPAGES,
2103
2569
  selectedSlippage: slippage,
2104
2570
  onSlippageChange: slippage => setSlippage(slippage),
2105
2571
  liquiditySources: uniqueSwappersGroups,
2106
2572
  selectedLiquiditySources: uniqueSwappersGroups.filter(s => s.selected),
2107
- onLiquiditySourcesClick: () => navigate(navigationRoutes.liquiditySources),
2108
- onBack: navigate.bind(null, -1),
2573
+ onLiquiditySourcesClick: navigate.bind(null, navigationRoutes.liquiditySources),
2574
+ onBack: navigateBackFrom.bind(null, navigationRoutes.settings),
2109
2575
  customSlippage: customSlippage || NaN,
2110
2576
  onCustomSlippageChange: setCustomSlippage,
2111
- minSlippage: 1,
2112
- maxSlippage: 10,
2577
+ minSlippage: MIN_SLIPPGAE,
2578
+ maxSlippage: MAX_SLIPPAGE,
2113
2579
  selectedTheme: theme,
2114
- onThemeChange: setTheme
2580
+ onThemeChange: setTheme,
2581
+ infiniteApprove: infiniteApprove,
2582
+ toggleInfiniteApprove: toggleInfiniteApprove
2115
2583
  });
2116
2584
  }
2117
2585
 
@@ -2127,7 +2595,9 @@ const AlertContainer = /*#__PURE__*/ui.styled('div', {
2127
2595
  paddingBottom: '$16'
2128
2596
  });
2129
2597
  function WalletsPage() {
2130
- const navigate = reactRouterDom.useNavigate();
2598
+ const {
2599
+ navigateBackFrom
2600
+ } = useNavigateBack();
2131
2601
  const {
2132
2602
  state,
2133
2603
  disconnect,
@@ -2136,6 +2606,7 @@ function WalletsPage() {
2136
2606
  } = walletsCore.useWallets();
2137
2607
  const wallets = getlistWallet(state, getWalletInfo, Object.values(walletsShared.WalletType));
2138
2608
  const [walletErrorMessage, setWalletErrorMessage] = React.useState('');
2609
+ const toggleConnectWalletsButton = useUiStore.use.toggleConnectWalletsButton();
2139
2610
  const onSelectWallet = async type => {
2140
2611
  const wallet = state(type);
2141
2612
  try {
@@ -2149,24 +2620,29 @@ function WalletsPage() {
2149
2620
  setWalletErrorMessage('Error: ' + e.message);
2150
2621
  }
2151
2622
  };
2623
+ React.useEffect(() => {
2624
+ toggleConnectWalletsButton();
2625
+ return () => toggleConnectWalletsButton();
2626
+ }, []);
2152
2627
  return React__default.createElement(ui.SecondaryPage, {
2153
2628
  title: "Select Wallet",
2154
2629
  textField: false,
2155
- onBack: () => {
2156
- navigate(-1);
2157
- },
2158
- Content: React__default.createElement(React__default.Fragment, null, walletErrorMessage && React__default.createElement(AlertContainer, null, React__default.createElement(ui.Alert, {
2159
- type: "error",
2160
- description: walletErrorMessage
2161
- })), React__default.createElement(ListContainer, null, wallets.map((info, index) => React__default.createElement(ui.Wallet, Object.assign({}, info, {
2162
- key: index,
2163
- onClick: onSelectWallet
2164
- })))))
2165
- });
2630
+ onBack: navigateBackFrom.bind(null, navigationRoutes.wallets)
2631
+ }, React__default.createElement(React__default.Fragment, null, walletErrorMessage && React__default.createElement(AlertContainer, null, React__default.createElement(ui.Alert, {
2632
+ type: "error"
2633
+ }, React__default.createElement(ui.Typography, {
2634
+ variant: "body2"
2635
+ }, walletErrorMessage))), React__default.createElement(ListContainer, null, wallets.map((info, index) => React__default.createElement(ui.Wallet, Object.assign({}, info, {
2636
+ key: index,
2637
+ onClick: onSelectWallet
2638
+ }))))));
2166
2639
  }
2167
2640
 
2168
2641
  function ConfirmWalletsPage() {
2169
2642
  const navigate = reactRouterDom.useNavigate();
2643
+ const {
2644
+ navigateBackFrom
2645
+ } = useNavigateBack();
2170
2646
  const bestRoute = useBestRouteStore.use.bestRoute();
2171
2647
  const {
2172
2648
  blockchains
@@ -2180,10 +2656,14 @@ function ConfirmWalletsPage() {
2180
2656
  connect
2181
2657
  } = walletsCore.useWallets();
2182
2658
  const confirmDisabled = !requiredWallets(bestRoute).every(chain => selectedWallets.map(wallet => wallet.chain).includes(chain));
2659
+ const firstStep = bestRoute?.result?.swaps[0];
2660
+ const lastStep = bestRoute?.result?.swaps[bestRoute?.result?.swaps.length - 1];
2661
+ const fromAmount = decimalNumber(firstStep?.fromAmount, 3);
2662
+ const toAmount = decimalNumber(lastStep?.toAmount, 3);
2183
2663
  React.useEffect(() => {
2184
2664
  initSelectedWallets();
2185
2665
  }, []);
2186
- const selectableWallets = getSelectableWallets(accounts, selectedWallets, getWalletInfo, getRequiredChains(bestRoute));
2666
+ const selectableWallets = getSelectableWallets(accounts, selectedWallets, getWalletInfo);
2187
2667
  const handleConnectChain = wallet => {
2188
2668
  const network = wallet;
2189
2669
  getKeplrCompatibleConnectedWallets(selectableWallets).forEach(compatibleWallet => connect?.(compatibleWallet, network));
@@ -2191,9 +2671,11 @@ function ConfirmWalletsPage() {
2191
2671
  return React__default.createElement(ui.ConfirmWallets, {
2192
2672
  requiredWallets: getRequiredChains(bestRoute),
2193
2673
  selectableWallets: selectableWallets,
2194
- onBack: () => navigate(-1),
2674
+ onBack: navigateBackFrom.bind(null, navigationRoutes.confirmWallets),
2195
2675
  swap: bestRoute,
2196
- onConfirm: () => navigate(navigationRoutes.confirmSwap),
2676
+ fromAmount: fromAmount,
2677
+ toAmount: toAmount,
2678
+ onConfirm: navigate.bind(null, navigationRoutes.confirmSwap),
2197
2679
  onChange: wallet => setSelectedWallet(wallet),
2198
2680
  confirmDisabled: confirmDisabled,
2199
2681
  handleConnectChain: wallet => handleConnectChain(wallet),
@@ -2664,9 +3146,11 @@ const pendingSwap$1 = {
2664
3146
  };
2665
3147
 
2666
3148
  function SwapDetailsPage() {
2667
- const navigate = reactRouterDom.useNavigate();
3149
+ const {
3150
+ navigateBackFrom
3151
+ } = useNavigateBack();
2668
3152
  return React__default.createElement(ui.SwapHistory, {
2669
- onBack: navigate.bind(null, -1),
3153
+ onBack: navigateBackFrom.bind(null, navigationRoutes.swapDetails),
2670
3154
  pendingSwap: pendingSwap$1
2671
3155
  });
2672
3156
  }
@@ -2739,8 +3223,9 @@ function Layout() {
2739
3223
  const {
2740
3224
  getWalletInfo
2741
3225
  } = walletsCore.useWallets();
2742
- const filterSelelectedWallets = getSelectableWallets(accounts, selectedWallets, getWalletInfo);
3226
+ const connectedWalletsImages = removeDuplicateFrom(getSelectableWallets(accounts, selectedWallets, getWalletInfo).map(w => w.image));
2743
3227
  const totalBalance = calculateWalletUsdValue(balances);
3228
+ const connectWalletsButtonDisabled = useUiStore.use.connectWalletsButtonDisabled();
2744
3229
  return React__default.createElement(React__default.Fragment, null, React__default.createElement(Header$1, null, React__default.createElement(ui.Button, {
2745
3230
  size: "small",
2746
3231
  suffix: React__default.createElement(ui.AddWalletIcon, {
@@ -2748,10 +3233,12 @@ function Layout() {
2748
3233
  }),
2749
3234
  variant: "ghost",
2750
3235
  flexContent: true,
2751
- onClick: () => navigate(navigationRoutes.wallets)
2752
- }, accounts?.length ? filterSelelectedWallets.map((selectedWallet, index) => React__default.createElement(WalletImage, {
3236
+ onClick: () => {
3237
+ if (!connectWalletsButtonDisabled) navigate(navigationRoutes.wallets);
3238
+ }
3239
+ }, connectedWalletsImages?.length ? connectedWalletsImages.map((walletImage, index) => React__default.createElement(WalletImage, {
2753
3240
  key: index,
2754
- src: selectedWallet.image
3241
+ src: walletImage
2755
3242
  })) : React__default.createElement(React__default.Fragment, null), React__default.createElement(ui.Typography, {
2756
3243
  variant: "body2"
2757
3244
  }, !accounts?.length ? 'Connect Wallet' : `$${totalBalance || 0}`))), React__default.createElement(AppRoutes, null));