@rango-dev/widget-embedded 0.1.10-next.77 → 0.1.10-next.81

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 +1790 -1357
  57. package/dist/widget-embedded.cjs.development.js.map +1 -1
  58. package/dist/widget-embedded.cjs.production.min.js +1790 -1357
  59. package/dist/widget-embedded.cjs.production.min.js.map +1 -1
  60. package/dist/widget-embedded.esm.js +1794 -1361
  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 +17 -6
  85. package/src/pages/SwapDetailsPage.tsx +9 -3
  86. package/src/pages/WalletsPage.tsx +43 -23
  87. package/src/store/bestRoute.ts +147 -28
  88. package/src/store/confirmSwap.ts +327 -0
  89. package/src/store/settings.ts +40 -28
  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 -12
  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 -234
@@ -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
+ infinitApprove: 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
+ toggleInfinitApprove: () => set(state => ({
142
+ infinitApprove: !state.infinitApprove
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,133 +398,6 @@ 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;
602
- }
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
401
  function getOutputRatio(inputUsdValue, outputUsdValue) {
618
402
  if (inputUsdValue.lte(ZERO) || outputUsdValue.lte(ZERO)) return 0;
619
403
  return outputUsdValue.div(inputUsdValue).minus(1).multipliedBy(100);
@@ -633,14 +417,90 @@ function hasLimitError(bestRoute) {
633
417
  }
634
418
  }).length > 0;
635
419
  }
636
- function getSwapButtonTitle(accounts, loading, hasLimitError, highValueLoss, priceImpactCanNotBeComputed, needsToWarnEthOnPath) {
637
- if (loading) return 'Finding Best Route...';
638
- 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';
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);
434
+ }
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
+ };
639
499
  }
640
500
  function canComputePriceImpact(bestRoute, inputAmount, inputUsdValue, outputUsdValue) {
641
- return !((inputUsdValue.lte(ZERO) || outputUsdValue.lte(ZERO)) && !!bestRoute?.result && !!inputAmount && inputAmount !== '0' && parseFloat(inputAmount || '0') !== 0);
501
+ return !((inputUsdValue.lte(ZERO) || outputUsdValue.lte(ZERO)) && !!bestRoute?.result && !!inputAmount && inputAmount !== '0' && parseFloat(inputAmount || '0') !== 0 && !!bestRoute.result);
642
502
  }
643
- function calculatePendingSwap(inputAmount, bestRoute, wallets, settings, validateBalanceOrFee) {
503
+ function calculatePendingSwap(inputAmount, bestRoute, wallets, settings, validateBalanceOrFee, meta) {
644
504
  const simulationResult = bestRoute.result;
645
505
  if (!simulationResult) throw Error('Simulation result should not be null');
646
506
  return {
@@ -658,52 +518,58 @@ function calculatePendingSwap(inputAmount, bestRoute, wallets, settings, validat
658
518
  networkStatusExtraMessage: null,
659
519
  networkStatusExtraMessageDetail: null,
660
520
  lastNotificationTime: null,
521
+ //@ts-ignore
661
522
  settings: settings,
662
523
  simulationResult: simulationResult,
663
524
  validateBalanceOrFee,
664
- //TODO: finalize PendingSwap type and remove ts-ignore
665
- //@ts-ignore
666
- steps: bestRoute.result?.swaps?.map((s, i) => ({
667
- id: i + 1,
668
- fromBlockchain: s.from.blockchain,
669
- fromSymbol: s.from.symbol,
670
- fromSymbolAddress: s.from.address,
671
- fromDecimals: s.from.decimals,
672
- fromAmountPrecision: s.fromAmountPrecision,
673
- fromAmountMinValue: s.fromAmountMinValue,
674
- fromAmountMaxValue: s.fromAmountMaxValue,
675
- toBlockchain: s.to.blockchain,
676
- fromLogo: s.from.logo,
677
- toSymbol: s.to.symbol,
678
- toSymbolAddress: s.to.address,
679
- toDecimals: s.to.decimals,
680
- toLogo: s.to.logo,
681
- startTransactionTime: new Date().getTime(),
682
- swapperId: s.swapperId,
683
- expectedOutputAmountHumanReadable: s.toAmount,
684
- outputAmount: null,
685
- status: 'created',
686
- networkStatus: null,
687
- executedTransactionId: null,
688
- externalTransactionId: null,
689
- explorerUrl: null,
690
- trackingCode: null,
691
- cosmosTransaction: null,
692
- solanaTransaction: null,
693
- starknetTransaction: null,
694
- starknetApprovalTransaction: null,
695
- tronTransaction: null,
696
- tronApprovalTransaction: null,
697
- evmTransaction: null,
698
- evmApprovalTransaction: null,
699
- transferTransaction: null,
700
- diagnosisUrl: null,
701
- internalSteps: null,
702
- fromBlockchainLogo: '',
703
- toBlockchainLogo: '',
704
- swapperLogo: '',
705
- swapperType: ''
706
- })) || []
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);
530
+ return {
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
571
+ };
572
+ }) || []
707
573
  };
708
574
  }
709
575
  function requiredWallets(route) {
@@ -718,399 +584,1207 @@ function requiredWallets(route) {
718
584
  });
719
585
  return wallets;
720
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]
624
+ });
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
+ }
721
684
 
722
- function useConfirmSwap() {
723
- const fromToken = useBestRouteStore.use.fromToken();
724
- const toToken = useBestRouteStore.use.toToken();
725
- const inputAmount = useBestRouteStore.use.inputAmount();
726
- const bestRoute = useBestRouteStore.use.bestRoute();
727
- const setBestRoute = useBestRouteStore.use.setBestRoute();
728
- const accounts = useWalletsStore.use.accounts();
729
- const selectedWallets = useWalletsStore.use.selectedWallets();
730
- const slippage = useSettingsStore.use.slippage();
731
- const disabledLiquiditySources = useSettingsStore.use.disabledLiquiditySources();
732
- const [loading, setLoading] = React.useState(false);
733
- const [error, setError] = React.useState('');
734
- const [warning, setWarning] = React.useState('');
735
- const [data, setData] = React.useState(null);
736
- const [feeStatus, setFeeStatus] = React.useState(null);
737
- const [bestRouteChanged, setBestRouteChanged] = React.useState(false);
738
- const [enoughBalance, setEnoughBalance] = React.useState(null);
739
- const hasEnoughBalanceOrProperSlippage = (route, selectedWallets, userSlippage, routeChanged) => {
740
- const fee = route.validationStatus;
741
- if (fee === null || fee.length === 0) return {
742
- balance: true,
743
- slippage: true,
744
- routeChanged
745
- };
746
- for (const wallet of selectedWallets) {
747
- const requiredAssets = getRequiredBalanceOfWallet(wallet, fee);
748
- if (!requiredAssets) continue;
749
- const hasEnoughBalance = requiredAssets?.map(it => it.ok).reduce((a, b) => a && b);
750
- if (!hasEnoughBalance) return {
751
- balance: false,
752
- slippage: true,
753
- routeChanged
754
- };
755
- }
756
- const slippages = route.result?.swaps?.map(s => s.recommendedSlippage);
757
- const slippageError = (slippages?.filter(s => !!s?.error)?.length || 0) > 0;
758
- const minSlippage = slippages?.map(s => parseFloat(s?.slippage.toString() || '0') || 0).filter(s => s > 0).sort((a, b) => b - a).find(() => true) || null;
759
- if (slippageError) {
760
- setError('Server cannot calculated required slippage for your swap');
761
- return {
762
- balance: true,
763
- slippage: false,
764
- routeChanged
765
- };
766
- } else if (minSlippage !== null && minSlippage > parseFloat(userSlippage)) {
767
- setError(`Your slippage should be ${minSlippage} at least`);
768
- return {
769
- balance: true,
770
- slippage: false,
771
- routeChanged
772
- };
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);
773
704
  }
774
705
  return {
775
- balance: true,
776
- slippage: true,
777
- routeChanged
706
+ bestRoute,
707
+ ...(!!bestRoute && {
708
+ outputAmount,
709
+ outputUsdValue
710
+ })
778
711
  };
779
- };
780
- const checkFeeAndBalance = async selectedWallets => {
781
- setLoading(true);
782
- setFeeStatus(null);
783
- const selectedWalletsMap = selectedWallets.reduce((selectedWalletsMap, selectedWallet) => (selectedWalletsMap[selectedWallet.chain] = selectedWallet.address, selectedWalletsMap), {});
784
- const connectedWallets = [];
785
- accounts.forEach(account => {
786
- const chainAndAccounts = connectedWallets.find(wallet => wallet.blockchain);
787
- if (!!chainAndAccounts) chainAndAccounts.addresses.push(account.address);else connectedWallets.push({
788
- blockchain: account.chain,
789
- addresses: [account.address]
790
- });
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
791
756
  });
792
- const r = await httpService.getBestRoute({
793
- amount: inputAmount.toString(),
794
- checkPrerequisites: true,
795
- from: {
796
- address: fromToken.address,
797
- blockchain: fromToken.blockchain,
798
- symbol: fromToken.symbol
799
- },
800
- to: {
801
- address: toToken.address,
802
- blockchain: toToken.blockchain,
803
- symbol: toToken.symbol
804
- },
805
- connectedWallets,
806
- selectedWallets: selectedWalletsMap,
807
- //@ts-ignore
808
- swapperGroups: disabledLiquiditySources,
809
- swappersGroupsExclude: true
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;
810
768
  }).catch(error => {
811
- setError(error.message);
812
- setLoading(false);
769
+ if (error.code === 'ERR_CANCELED') return;
770
+ bestRouteStore.setState({
771
+ error: error.message,
772
+ loading: false
773
+ });
813
774
  });
814
- setLoading(false);
815
- if (!r || !r.result || !bestRoute) return {
816
- bestRoute: null
817
- };
818
- if (!new BigNumber__default(r.requestAmount).isEqualTo(new BigNumber__default(inputAmount || '-1'))) return null;
819
- setFeeStatus(r.validationStatus);
820
- const routeChangeStatus = compareRoutes(bestRoute, r, inputAmount.toString(), fromToken.usdPrice, toToken.usdPrice);
821
- setBestRoute(r);
822
- const isChanged = routeChangeStatus.isChanged;
823
- setBestRouteChanged(isChanged);
824
- setWarning('Best route changed');
825
- setData(r);
826
- return {
827
- hasEnoughBalanceOrSlippage: hasEnoughBalanceOrProperSlippage(r, selectedWallets, slippage.toString(), isChanged),
828
- bestRoute: r
829
- };
830
775
  };
831
- const swap = () => {
832
- if (!bestRoute) return;
833
- if (inputAmount.toString() === '') return;
834
- const wallets = selectedWallets.reduce((selectedWalletsMap, selectedWallet) => (selectedWalletsMap[selectedWallet.chain] = {
835
- address: selectedWallet.address,
836
- walletType: selectedWallet.walletType
837
- }, selectedWalletsMap), {});
838
- const proceedAnyway = enoughBalance !== null;
839
- const settings = {
840
- slippage: slippage.toString(),
841
- disabledSwappersGroups: ['Osmosis'],
842
- disabledSwappersIds: []
843
- };
844
- if (proceedAnyway) {
845
- const newSwap = calculatePendingSwap(inputAmount.toString(), bestRoute, wallets, settings, false);
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;
846
785
  }
847
- !proceedAnyway && checkFeeAndBalance(selectedWallets).then(data => {
848
- if (!data) {
849
- setError('confirm swap error');
850
- return;
851
- }
852
- if (!data.bestRoute) {
853
- setError('confirm swap error');
854
- return;
855
- } else {
856
- const {
857
- hasEnoughBalanceOrSlippage,
858
- bestRoute: newBestRoute
859
- } = data;
860
- if (!hasEnoughBalanceOrSlippage) {
861
- return;
862
- }
863
- setEnoughBalance(hasEnoughBalanceOrSlippage.balance && hasEnoughBalanceOrSlippage.slippage);
864
- if (hasEnoughBalanceOrSlippage.balance && hasEnoughBalanceOrSlippage.slippage && !hasEnoughBalanceOrSlippage.routeChanged) {
865
- const newSwap = calculatePendingSwap(inputAmount.toString(), newBestRoute, wallets, settings, true);
866
- } else if (!hasEnoughBalanceOrSlippage.balance) {
867
- setError('not enough balance');
868
- }
869
- }
870
- }).catch(error => {
871
- console.log('unexpected error', error);
872
- });
873
- };
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
+ });
874
796
  return {
875
- loading,
876
- error,
877
- data,
878
- warning,
879
- feeStatus,
880
- bestRouteChanged,
881
- enoughBalance,
882
- swap
797
+ fetchBestRoute
883
798
  };
884
- }
799
+ };
800
+ const {
801
+ fetchBestRoute
802
+ } = /*#__PURE__*/bestRoute(useBestRouteStore, useSettingsStore);
885
803
 
886
- function ConfirmSwapPage() {
887
- const navigate = reactRouterDom.useNavigate();
888
- const bestRoute = useBestRouteStore.use.bestRoute();
889
- const {
890
- error,
891
- loading,
892
- warning,
893
- swap
894
- } = useConfirmSwap();
895
- return React__default.createElement(ui.ConfirmSwap, {
896
- onConfirm: swap.bind(null),
897
- onBack: navigate.bind(null, -1),
898
- bestRoute: bestRoute,
899
- loading: loading,
900
- error: error,
901
- warning: warning
902
- });
903
- }
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 = {}));
904
812
 
905
- const pendingSwap = [{
906
- creationTime: '1673164511955',
907
- finishTime: '1673164550137',
908
- requestId: '51e211d9-d61c-45d2-a4d4-1f9f7f90ee85',
909
- inputAmount: '1',
910
- wallets: {
911
- OSMOSIS: {
912
- walletType: 'keplr',
913
- address: 'osmo1unf2rcytjxfpz8x8ar63h4qeftadptg5t0nqcl'
914
- }
915
- },
916
- status: 'running',
917
- isPaused: false,
918
- extraMessage: null,
919
- extraMessageSeverity: 'info',
920
- extraMessageDetail: '',
921
- extraMessageErrorCode: null,
922
- networkStatusExtraMessage: null,
923
- networkStatusExtraMessageDetail: null,
924
- lastNotificationTime: null,
925
- settings: {
926
- slippage: '1.0',
927
- disabledSwappersIds: [],
928
- disabledSwappersGroups: []
929
- },
930
- simulationResult: {
931
- outputAmount: '1.540670',
932
- swaps: [{
933
- swapperId: 'Osmosis',
934
- swapperType: 'DEX',
935
- swapperLogo: '',
936
- // @ts-ignore
937
- result: null,
938
- from: {
939
- symbol: 'JUNO',
940
- logo: 'https://api.rango.exchange/tokens/COSMOS/JUNO.png',
941
- address: 'ibc/46b44899322f3cd854d2d46deef881958467cdd4b3b10086da49296bbed94bed',
942
- blockchain: 'OSMOSIS',
943
- blockchainLogo: '',
944
- decimals: 6,
945
- usdPrice: 1.1091996179668873
946
- },
947
- to: {
948
- symbol: 'OSMO',
949
- logo: 'https://api.rango.exchange/i/mJQPS2',
950
- address: null,
951
- blockchain: 'OSMOSIS',
952
- decimals: 6,
953
- blockchainLogo: '',
954
- usdPrice: 0.7192435454440882
955
- },
956
- fromAmount: '1.000000',
957
- fromAmountPrecision: null,
958
- fromAmountMinValue: null,
959
- fromAmountMaxValue: null,
960
- toAmount: '1.540670',
961
- fee: [{
962
- name: '',
963
- asset: {
964
- blockchain: 'OSMOSIS',
965
- symbol: 'OSMO',
966
- address: null
967
- },
968
- expenseType: 'FROM_SOURCE_WALLET',
969
- amount: '0'
970
- }],
971
- estimatedTimeInSeconds: 45,
972
- swapChainType: 'INTRA_CHAIN',
973
- routes: [{
974
- nodes: [{
975
- nodes: [{
976
- marketName: 'pool#498',
977
- marketId: null,
978
- percent: 1
979
- }],
980
- from: 'JUNO',
981
- fromLogo: 'https://api.rango.exchange/tokens/COSMOS/JUNO.png',
982
- fromAddress: 'ibc/46b44899322f3cd854d2d46deef881958467cdd4b3b10086da49296bbed94bed',
983
- fromBlockchain: 'OSMOSIS',
984
- to: 'ATOM',
985
- toLogo: 'https://api.rango.exchange/tokens/COSMOS/ATOM.png',
986
- toAddress: 'ibc/27394fb092d2eccd56123c74f36e4c1f926001ceada9ca97ea622b25f41e5eb2',
987
- toBlockchain: 'OSMOSIS'
988
- }, {
989
- nodes: [{
990
- marketName: 'pool#8',
991
- marketId: null,
992
- percent: 1
993
- }],
994
- from: 'ATOM',
995
- fromLogo: 'https://api.rango.exchange/tokens/COSMOS/ATOM.png',
996
- fromAddress: 'ibc/27394fb092d2eccd56123c74f36e4c1f926001ceada9ca97ea622b25f41e5eb2',
997
- fromBlockchain: 'OSMOSIS',
998
- to: 'IRIS',
999
- toLogo: 'https://api.rango.exchange/tokens/COSMOS/IRIS.png',
1000
- toAddress: 'ibc/7c4d60aa95e5a7558b0a364860979ca34b7ff8aaf255b87af9e879374470cec0',
1001
- 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
+ })
1002
915
  }, {
1003
- nodes: [{
1004
- marketName: 'pool#7',
1005
- marketId: null,
1006
- percent: 1
1007
- }],
1008
- from: 'IRIS',
1009
- fromLogo: 'https://api.rango.exchange/tokens/COSMOS/IRIS.png',
1010
- fromAddress: 'ibc/7c4d60aa95e5a7558b0a364860979ca34b7ff8aaf255b87af9e879374470cec0',
1011
- fromBlockchain: 'OSMOSIS',
1012
- to: 'OSMO',
1013
- toLogo: 'https://api.rango.exchange/tokens/COSMOS/OSMO.png',
1014
- toAddress: null,
1015
- toBlockchain: 'OSMOSIS'
1016
- }]
1017
- }],
1018
- recommendedSlippage: null,
1019
- timeStat: {
1020
- min: 6,
1021
- avg: 40,
1022
- max: 241
1023
- },
1024
- includesDestinationTx: false
1025
- }]
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
+ });
1026
1037
  },
1027
- validateBalanceOrFee: true,
1028
- steps: [{
1029
- id: 1,
1030
- fromBlockchain: 'OSMOSIS',
1031
- fromSymbol: 'JUNO',
1032
- fromSymbolAddress: 'ibc/46b44899322f3cd854d2d46deef881958467cdd4b3b10086da49296bbed94bed',
1033
- fromDecimals: 6,
1034
- fromAmountPrecision: null,
1035
- fromAmountMinValue: null,
1036
- swapperLogo: '',
1037
- swapperType: '',
1038
- fromAmountMaxValue: null,
1039
- toBlockchainLogo: 'https://api.rango.exchange/swappers/osmosis.png',
1040
- fromBlockchainLogo: 'https://api.rango.exchange/swappers/osmosis.png',
1041
- toBlockchain: 'OSMOSIS',
1042
- fromLogo: 'https://api.rango.exchange/tokens/COSMOS/JUNO.png',
1043
- toSymbol: 'OSMO',
1044
- toSymbolAddress: null,
1045
- toDecimals: 6,
1046
- toLogo: 'https://api.rango.exchange/i/mJQPS2',
1047
- startTransactionTime: 1673164519916,
1048
- swapperId: 'Osmosis',
1049
- expectedOutputAmountHumanReadable: '1.540670',
1050
- outputAmount: '1.540658',
1051
- status: 'running',
1052
- networkStatus: null,
1053
- executedTransactionId: '0f8f17eecc863c2d6be65ef52cfe3128ff3cd7baeddf133160bea8ccdfbf876b',
1054
- explorerUrl: [{
1055
- url: 'https://www.mintscan.io/osmosis/txs/0f8f17eecc863c2d6be65ef52cfe3128ff3cd7baeddf133160bea8ccdfbf876b',
1056
- description: null
1057
- }],
1058
- cosmosTransaction: {
1059
- type: rangoSdk.TransactionType.COSMOS,
1060
- fromWalletAddress: 'osmo1unf2rcytjxfpz8x8ar63h4qeftadptg5t0nqcl',
1061
- blockChain: 'OSMOSIS',
1062
- data: {
1063
- chainId: 'osmosis-1',
1064
- account_number: 102721,
1065
- sequence: '308',
1066
- msgs: [{
1067
- __type: 'OsmosisSwapMessage',
1068
- type: 'osmosis/gamm/swap-exact-amount-in',
1069
- value: {
1070
- sender: 'osmo1unf2rcytjxfpz8x8ar63h4qeftadptg5t0nqcl',
1071
- routes: [{
1072
- pool_id: '498',
1073
- token_out_denom: 'ibc/27394FB092D2ECCD56123C74F36E4C1F926001CEADA9CA97EA622B25F41E5EB2'
1074
- }, {
1075
- pool_id: '8',
1076
- token_out_denom: 'ibc/7C4D60AA95E5A7558B0A364860979CA34B7FF8AAF255B87AF9E879374470CEC0'
1077
- }, {
1078
- pool_id: '7',
1079
- token_out_denom: 'uosmo'
1080
- }],
1081
- token_in: {
1082
- denom: 'ibc/46B44899322F3CD854D2D46DEEF881958467CDD4B3B10086DA49296BBED94BED',
1083
- amount: '1000000'
1084
- },
1085
- token_out_min_amount: '1525264'
1086
- }
1087
- }],
1088
- protoMsgs: [{
1089
- type_url: '/osmosis.gamm.v1beta1.MsgSwapExactAmountIn',
1090
- 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]
1091
- }],
1092
- memo: '',
1093
- source: null,
1094
- fee: {
1095
- gas: '900000',
1096
- amount: [{
1097
- denom: 'uosmo',
1098
- amount: '0'
1099
- }]
1100
- },
1101
- signType: 'AMINO',
1102
- rpcUrl: ''
1103
- },
1104
- rawTransfer: null
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`);
1105
1162
  },
1106
- solanaTransaction: null,
1107
- evmTransaction: null,
1108
- evmApprovalTransaction: null,
1109
- transferTransaction: null,
1110
- diagnosisUrl: null,
1111
- internalSteps: null
1112
- }]
1113
- }, {
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 = [{
1114
1788
  creationTime: '1673164511955',
1115
1789
  finishTime: '1673164550137',
1116
1790
  requestId: '51e211d9-d61c-45d2-a4d4-1f9f7f90ee85',
@@ -1121,7 +1795,7 @@ const pendingSwap = [{
1121
1795
  address: 'osmo1unf2rcytjxfpz8x8ar63h4qeftadptg5t0nqcl'
1122
1796
  }
1123
1797
  },
1124
- status: 'failed',
1798
+ status: 'running',
1125
1799
  isPaused: false,
1126
1800
  extraMessage: null,
1127
1801
  extraMessageSeverity: 'info',
@@ -1139,10 +1813,10 @@ const pendingSwap = [{
1139
1813
  outputAmount: '1.540670',
1140
1814
  swaps: [{
1141
1815
  swapperId: 'Osmosis',
1816
+ swapperType: 'DEX',
1142
1817
  swapperLogo: '',
1143
1818
  // @ts-ignore
1144
1819
  result: null,
1145
- swapperType: 'DEX',
1146
1820
  from: {
1147
1821
  symbol: 'JUNO',
1148
1822
  logo: 'https://api.rango.exchange/tokens/COSMOS/JUNO.png',
@@ -1241,12 +1915,12 @@ const pendingSwap = [{
1241
1915
  fromDecimals: 6,
1242
1916
  fromAmountPrecision: null,
1243
1917
  fromAmountMinValue: null,
1918
+ swapperLogo: '',
1919
+ swapperType: '',
1244
1920
  fromAmountMaxValue: null,
1245
1921
  toBlockchainLogo: 'https://api.rango.exchange/swappers/osmosis.png',
1246
1922
  fromBlockchainLogo: 'https://api.rango.exchange/swappers/osmosis.png',
1247
1923
  toBlockchain: 'OSMOSIS',
1248
- swapperLogo: '',
1249
- swapperType: '',
1250
1924
  fromLogo: 'https://api.rango.exchange/tokens/COSMOS/JUNO.png',
1251
1925
  toSymbol: 'OSMO',
1252
1926
  toSymbolAddress: null,
@@ -1256,7 +1930,7 @@ const pendingSwap = [{
1256
1930
  swapperId: 'Osmosis',
1257
1931
  expectedOutputAmountHumanReadable: '1.540670',
1258
1932
  outputAmount: '1.540658',
1259
- status: 'failed',
1933
+ status: 'running',
1260
1934
  networkStatus: null,
1261
1935
  executedTransactionId: '0f8f17eecc863c2d6be65ef52cfe3128ff3cd7baeddf133160bea8ccdfbf876b',
1262
1936
  explorerUrl: [{
@@ -1329,7 +2003,7 @@ const pendingSwap = [{
1329
2003
  address: 'osmo1unf2rcytjxfpz8x8ar63h4qeftadptg5t0nqcl'
1330
2004
  }
1331
2005
  },
1332
- status: 'success',
2006
+ status: 'failed',
1333
2007
  isPaused: false,
1334
2008
  extraMessage: null,
1335
2009
  extraMessageSeverity: 'info',
@@ -1346,11 +2020,11 @@ const pendingSwap = [{
1346
2020
  simulationResult: {
1347
2021
  outputAmount: '1.540670',
1348
2022
  swaps: [{
1349
- // @ts-ignore
1350
- result: [],
1351
2023
  swapperId: 'Osmosis',
1352
- swapperType: 'DEX',
1353
2024
  swapperLogo: '',
2025
+ // @ts-ignore
2026
+ result: null,
2027
+ swapperType: 'DEX',
1354
2028
  from: {
1355
2029
  symbol: 'JUNO',
1356
2030
  logo: 'https://api.rango.exchange/tokens/COSMOS/JUNO.png',
@@ -1449,12 +2123,12 @@ const pendingSwap = [{
1449
2123
  fromDecimals: 6,
1450
2124
  fromAmountPrecision: null,
1451
2125
  fromAmountMinValue: null,
1452
- swapperLogo: '',
1453
- swapperType: '',
1454
2126
  fromAmountMaxValue: null,
1455
2127
  toBlockchainLogo: 'https://api.rango.exchange/swappers/osmosis.png',
1456
2128
  fromBlockchainLogo: 'https://api.rango.exchange/swappers/osmosis.png',
1457
2129
  toBlockchain: 'OSMOSIS',
2130
+ swapperLogo: '',
2131
+ swapperType: '',
1458
2132
  fromLogo: 'https://api.rango.exchange/tokens/COSMOS/JUNO.png',
1459
2133
  toSymbol: 'OSMO',
1460
2134
  toSymbolAddress: null,
@@ -1464,543 +2138,287 @@ const pendingSwap = [{
1464
2138
  swapperId: 'Osmosis',
1465
2139
  expectedOutputAmountHumanReadable: '1.540670',
1466
2140
  outputAmount: '1.540658',
1467
- status: 'success',
2141
+ status: 'failed',
1468
2142
  networkStatus: null,
1469
2143
  executedTransactionId: '0f8f17eecc863c2d6be65ef52cfe3128ff3cd7baeddf133160bea8ccdfbf876b',
1470
2144
  explorerUrl: [{
1471
2145
  url: 'https://www.mintscan.io/osmosis/txs/0f8f17eecc863c2d6be65ef52cfe3128ff3cd7baeddf133160bea8ccdfbf876b',
1472
2146
  description: null
1473
- }],
1474
- cosmosTransaction: {
1475
- type: rangoSdk.TransactionType.COSMOS,
1476
- fromWalletAddress: 'osmo1unf2rcytjxfpz8x8ar63h4qeftadptg5t0nqcl',
1477
- blockChain: 'OSMOSIS',
1478
- data: {
1479
- chainId: 'osmosis-1',
1480
- account_number: 102721,
1481
- sequence: '308',
1482
- msgs: [{
1483
- __type: 'OsmosisSwapMessage',
1484
- type: 'osmosis/gamm/swap-exact-amount-in',
1485
- value: {
1486
- sender: 'osmo1unf2rcytjxfpz8x8ar63h4qeftadptg5t0nqcl',
1487
- routes: [{
1488
- pool_id: '498',
1489
- token_out_denom: 'ibc/27394FB092D2ECCD56123C74F36E4C1F926001CEADA9CA97EA622B25F41E5EB2'
1490
- }, {
1491
- pool_id: '8',
1492
- token_out_denom: 'ibc/7C4D60AA95E5A7558B0A364860979CA34B7FF8AAF255B87AF9E879374470CEC0'
1493
- }, {
1494
- pool_id: '7',
1495
- token_out_denom: 'uosmo'
1496
- }],
1497
- token_in: {
1498
- denom: 'ibc/46B44899322F3CD854D2D46DEEF881958467CDD4B3B10086DA49296BBED94BED',
1499
- amount: '1000000'
1500
- },
1501
- token_out_min_amount: '1525264'
1502
- }
1503
- }],
1504
- protoMsgs: [{
1505
- type_url: '/osmosis.gamm.v1beta1.MsgSwapExactAmountIn',
1506
- 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]
1507
- }],
1508
- memo: '',
1509
- source: null,
1510
- fee: {
1511
- gas: '900000',
1512
- amount: [{
1513
- denom: 'uosmo',
1514
- amount: '0'
1515
- }]
1516
- },
1517
- signType: 'AMINO',
1518
- rpcUrl: ''
1519
- },
1520
- rawTransfer: null
1521
- },
1522
- solanaTransaction: null,
1523
- evmTransaction: null,
1524
- evmApprovalTransaction: null,
1525
- transferTransaction: null,
1526
- diagnosisUrl: null,
1527
- internalSteps: null
1528
- }]
1529
- }];
1530
- function HistoryPage() {
1531
- const navigate = reactRouterDom.useNavigate();
1532
- return React__default.createElement(ui.History, {
1533
- list: pendingSwap,
1534
- onSwapClick: () => navigate(navigationRoutes.swapDetails),
1535
- onBack: () => {
1536
- navigate(-1);
1537
- }
1538
- });
1539
- }
1540
-
1541
- const ButtonsContainer = /*#__PURE__*/ui.styled('div', {
1542
- display: 'flex'
1543
- });
1544
- function HeaderButtons(props) {
1545
- const {
1546
- onClickRefresh
1547
- } = props;
1548
- const navigate = reactRouterDom.useNavigate();
1549
- return React__default.createElement(ButtonsContainer, null, React__default.createElement(ui.Tooltip, {
1550
- content: "Retry"
1551
- }, React__default.createElement(ui.Button, {
1552
- variant: "ghost",
1553
- onClick: onClickRefresh.bind(null)
1554
- }, React__default.createElement(ui.RetryIcon, {
1555
- size: 28
1556
- }))), React__default.createElement(ui.Tooltip, {
1557
- content: "Transactions History"
1558
- }, React__default.createElement(ui.Button, {
1559
- variant: "ghost",
1560
- onClick: () => navigate(navigationRoutes.history)
1561
- }, React__default.createElement(ui.HistoryIcon, {
1562
- size: 24
1563
- }))), React__default.createElement(ui.Tooltip, {
1564
- content: "Settings"
1565
- }, React__default.createElement(ui.Button, {
1566
- variant: "ghost",
1567
- onClick: () => navigate(navigationRoutes.settings)
1568
- }, React__default.createElement(ui.SettingsIcon, {
1569
- size: 24
1570
- }))));
1571
- }
1572
-
1573
- const HeaderContainer = /*#__PURE__*/ui.styled('div', {
1574
- display: 'flex',
1575
- justifyContent: 'space-between',
1576
- alignItems: 'center',
1577
- width: '100%',
1578
- padding: '$16 0'
1579
- });
1580
- function Header(props) {
1581
- const {
1582
- onClickRefresh
1583
- } = props;
1584
- return React__default.createElement(HeaderContainer, null, React__default.createElement(ui.Typography, {
1585
- variant: "h4"
1586
- }, "SWAP"), React__default.createElement(HeaderButtons, {
1587
- onClickRefresh: onClickRefresh
1588
- }));
1589
- }
1590
-
1591
- const Box = /*#__PURE__*/ui.styled('div', {
1592
- display: 'flex',
1593
- flexDirection: 'column',
1594
- width: '100%'
1595
- });
1596
- const Container = /*#__PURE__*/ui.styled('div', {
1597
- boxSizing: 'border-box',
1598
- backgroundColor: '$neutrals300',
1599
- borderRadius: '$5',
1600
- padding: '$8 0',
1601
- '.form': {
1602
- display: 'flex',
1603
- width: '100%',
1604
- padding: '$8 $16'
1605
- }
1606
- });
1607
- const StyledImage = /*#__PURE__*/ui.styled('img', {
1608
- width: '$24',
1609
- maxHeight: '$24'
1610
- });
1611
- const Options = /*#__PURE__*/ui.styled('div', {
1612
- display: 'flex',
1613
- justifyContent: 'flex-end',
1614
- padding: '0 $8'
1615
- });
1616
- const ImagePlaceholder = /*#__PURE__*/ui.styled('span', {
1617
- width: '24px',
1618
- height: '24px',
1619
- backgroundColor: '$neutrals300',
1620
- borderRadius: '99999px'
1621
- });
1622
- const OutputContainer = /*#__PURE__*/ui.styled('div', {
1623
- height: '$48',
1624
- borderRadius: '$5',
1625
- flexGrow: 1,
1626
- width: '70%',
1627
- backgroundColor: '$background',
1628
- border: '1px solid transparent',
1629
- position: 'relative',
1630
- display: 'flex',
1631
- alignItems: 'center',
1632
- paddingLeft: '$8',
1633
- paddingRight: '$8'
1634
- });
1635
- function TokenInfo(props) {
1636
- const {
1637
- type,
1638
- chain,
1639
- token
1640
- } = props;
1641
- const loadingStatus = useMetaStore.use.loadingStatus();
1642
- const fromChain = useBestRouteStore.use.fromChain();
1643
- const toChain = useBestRouteStore.use.toChain();
1644
- const inputUsdValue = useBestRouteStore.use.inputUsdValue();
1645
- const fromToken = useBestRouteStore.use.fromToken();
1646
- const setInputAmount = useBestRouteStore.use.setInputAmount();
1647
- const bestRoute = useBestRouteStore.use.bestRoute();
1648
- const inputAmount = useBestRouteStore.use.inputAmount();
1649
- const balances = useWalletsStore.use.balances();
1650
- const navigate = reactRouterDom.useNavigate();
1651
- const tokenBalance = !!fromChain && !!fromToken ? numberToString(getBalanceFromWallet(balances, fromChain?.name, fromToken?.symbol, fromToken?.address)?.amount || '0', 8) : '0';
1652
- 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';
1653
- const ItemSuffix = React__default.createElement("div", {
1654
- style: {
1655
- display: 'flex',
1656
- justifyContent: 'center',
1657
- alignItems: 'center'
1658
- }
1659
- }, loadingStatus === 'failed' && React__default.createElement(ui.InfoCircleIcon, {
1660
- color: "error",
1661
- size: 24
1662
- }), React__default.createElement(ui.AngleDownIcon, null));
1663
- return React__default.createElement(Box, null, React__default.createElement("div", null, React__default.createElement(ui.Typography, {
1664
- variant: "body2"
1665
- }, type)), React__default.createElement(Container, null, props.type === 'From' && React__default.createElement(Options, null, React__default.createElement("div", {
1666
- className: "balance",
1667
- onClick: () => {
1668
- if (tokenBalance !== '0') setInputAmount(tokenBalanceReal.split(',').join(''));
1669
- }
1670
- }, React__default.createElement(ui.Button, {
1671
- variant: "ghost",
1672
- size: "small"
1673
- }, React__default.createElement(ui.Typography, {
1674
- variant: "body2"
1675
- }, `Max: ${tokenBalance} ${fromToken?.symbol || ''}`)))), React__default.createElement("div", {
1676
- className: "form"
1677
- }, React__default.createElement(ui.Button, {
1678
- onClick: () => {
1679
- navigate(`/${props.type.toLowerCase()}-chain`);
1680
- },
1681
- variant: "outlined",
1682
- disabled: loadingStatus === 'failed',
1683
- loading: loadingStatus === 'loading',
1684
- prefix: loadingStatus === 'success' && chain ? React__default.createElement(StyledImage, {
1685
- src: chain.logo
1686
- }) : React__default.createElement(ImagePlaceholder, null),
1687
- suffix: ItemSuffix,
1688
- align: "start",
1689
- size: "large",
1690
- style: {
1691
- marginRight: '.5rem'
1692
- }
1693
- }, loadingStatus === 'success' && chain ? chain.displayName : 'Chain'), React__default.createElement(ui.Button, {
1694
- onClick: () => {
1695
- navigate(`/${props.type.toLowerCase()}-token`);
1696
- },
1697
- variant: "outlined",
1698
- disabled: loadingStatus === 'failed' || type === 'From' && !fromChain || type === 'To' && !toChain,
1699
- loading: loadingStatus === 'loading',
1700
- prefix: loadingStatus === 'success' && token ? React__default.createElement(StyledImage, {
1701
- src: token.image
1702
- }) : React__default.createElement(ImagePlaceholder, null),
1703
- suffix: ItemSuffix,
1704
- size: "large",
1705
- align: "start",
1706
- style: {
1707
- marginRight: '.5rem'
1708
- }
1709
- }, loadingStatus === 'success' && token ? token.symbol : 'Token'), props.type === 'From' ? React__default.createElement(ui.TextField, {
1710
- type: "number",
1711
- size: "large",
1712
- autoFocus: true,
1713
- placeholder: "0",
1714
- style: {
1715
- width: '70%',
1716
- position: 'relative',
1717
- backgroundColor: '$background !important'
2147
+ }],
2148
+ cosmosTransaction: {
2149
+ type: rangoSdk.TransactionType.COSMOS,
2150
+ fromWalletAddress: 'osmo1unf2rcytjxfpz8x8ar63h4qeftadptg5t0nqcl',
2151
+ blockChain: 'OSMOSIS',
2152
+ data: {
2153
+ chainId: 'osmosis-1',
2154
+ account_number: 102721,
2155
+ sequence: '308',
2156
+ msgs: [{
2157
+ __type: 'OsmosisSwapMessage',
2158
+ type: 'osmosis/gamm/swap-exact-amount-in',
2159
+ value: {
2160
+ sender: 'osmo1unf2rcytjxfpz8x8ar63h4qeftadptg5t0nqcl',
2161
+ routes: [{
2162
+ pool_id: '498',
2163
+ token_out_denom: 'ibc/27394FB092D2ECCD56123C74F36E4C1F926001CEADA9CA97EA622B25F41E5EB2'
2164
+ }, {
2165
+ pool_id: '8',
2166
+ token_out_denom: 'ibc/7C4D60AA95E5A7558B0A364860979CA34B7FF8AAF255B87AF9E879374470CEC0'
2167
+ }, {
2168
+ pool_id: '7',
2169
+ token_out_denom: 'uosmo'
2170
+ }],
2171
+ token_in: {
2172
+ denom: 'ibc/46B44899322F3CD854D2D46DEEF881958467CDD4B3B10086DA49296BBED94BED',
2173
+ amount: '1000000'
2174
+ },
2175
+ token_out_min_amount: '1525264'
2176
+ }
2177
+ }],
2178
+ protoMsgs: [{
2179
+ type_url: '/osmosis.gamm.v1beta1.MsgSwapExactAmountIn',
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]
2181
+ }],
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
1718
2195
  },
1719
- suffix: React__default.createElement("span", {
1720
- style: {
1721
- position: 'absolute',
1722
- right: '4px',
1723
- bottom: '2px'
1724
- }
1725
- }, React__default.createElement(ui.Typography, {
1726
- variant: "caption"
1727
- }, `$${numberToString(inputUsdValue)}`)),
1728
- value: props.inputAmount || '',
1729
- onChange: props.type === 'From' ? event => {
1730
- props.onAmountChange(event.target.value);
1731
- } : undefined
1732
- }) : React__default.createElement(OutputContainer, null, React__default.createElement(ui.Typography, {
1733
- variant: "body1"
1734
- }, bestRoute ? `≈ ${numberToString(props.outputAmount)}` : inputAmount ? '?' : '0'), React__default.createElement("span", {
1735
- style: {
1736
- position: 'absolute',
1737
- right: '4px',
1738
- bottom: '2px'
1739
- }
1740
- }, React__default.createElement(ui.Typography, {
1741
- variant: "caption"
1742
- }, `$${numberToString(props.outputUsdValue)}`))))));
1743
- }
1744
-
1745
- const Container$1 = /*#__PURE__*/theme.styled('div', {
1746
- display: 'flex',
1747
- width: '100%',
1748
- justifyContent: 'end',
1749
- alignItems: 'center',
1750
- paddingTop: '$16'
1751
- });
1752
- const Logo = /*#__PURE__*/theme.styled('svg', {
1753
- fill: '$foreground',
1754
- width: '$24',
1755
- margin: '0 $8 0 $16'
1756
- });
1757
- const StyledAnchor = /*#__PURE__*/theme.styled('a', {
1758
- display: 'flex',
1759
- justifyContent: 'center',
1760
- alignItems: 'center',
1761
- textDecoration: 'none'
1762
- });
1763
- function BottomLogo() {
1764
- return React__default.createElement(Container$1, null, React__default.createElement(ui.Typography, {
1765
- variant: "caption"
1766
- }, "Powered By"), React__default.createElement(StyledAnchor, {
1767
- href: "https://rango.exchange",
1768
- target: "_blank"
1769
- }, React__default.createElement(Logo, {
1770
- xmlns: "http://www.w3.org/2000/svg",
1771
- viewBox: "0 0 33.68 29"
1772
- }, React__default.createElement("defs", null), React__default.createElement("g", {
1773
- id: "Layer_2",
1774
- "data-name": "Layer 2"
1775
- }, React__default.createElement("g", {
1776
- id: "Layer_1-2",
1777
- "data-name": "Layer 1"
1778
- }, React__default.createElement("path", {
1779
- 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"
1780
- }), React__default.createElement("path", {
1781
- 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"
1782
- })))), React__default.createElement(ui.Typography, {
1783
- variant: "body2"
1784
- }, "RANGO")));
1785
- }
1786
-
1787
- function SwithFromAndTo(_ref) {
1788
- let {
1789
- count
1790
- } = _ref;
1791
- const firstRender = React.useRef(true);
1792
- const [searchParams, setSearchParams] = reactRouterDom.useSearchParams();
1793
- const outputAmount = useBestRouteStore.use.outputAmount();
1794
- React.useEffect(() => {
1795
- if (!firstRender.current) {
1796
- const fromChainString = searchParams.get(SearchParams.FROM_CHAIN);
1797
- const fromTokenString = searchParams.get(SearchParams.FROM_TOKEN);
1798
- const toChainString = searchParams.get(SearchParams.TO_CHAIN);
1799
- const toTokenString = searchParams.get(SearchParams.TO_TOKEN);
1800
- setSearchParams({
1801
- ...(toChainString && {
1802
- [SearchParams.FROM_CHAIN]: toChainString
1803
- }),
1804
- ...(toTokenString && {
1805
- [SearchParams.FROM_TOKEN]: toTokenString
1806
- }),
1807
- ...(fromChainString && {
1808
- [SearchParams.TO_CHAIN]: fromChainString
1809
- }),
1810
- ...(fromTokenString && {
1811
- [SearchParams.TO_TOKEN]: fromTokenString
1812
- }),
1813
- ...(outputAmount && {
1814
- [SearchParams.FROM_AMOUNT]: outputAmount.toString()
1815
- })
1816
- });
1817
- } else {
1818
- 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'
1819
2212
  }
1820
- }, [count]);
1821
- return null;
1822
- }
1823
-
1824
- const Footer = /*#__PURE__*/ui.styled('div', {
1825
- display: 'flex',
1826
- flexDirection: 'column',
1827
- width: '100%',
1828
- paddingTop: '$16'
1829
- });
1830
-
1831
- function useBestRoute() {
1832
- const fromToken = useBestRouteStore.use.fromToken();
1833
- const toToken = useBestRouteStore.use.toToken();
1834
- const inputAmount = useBestRouteStore.use.inputAmount();
1835
- const slippage = useSettingsStore.use.slippage();
1836
- const customSlippage = useSettingsStore.use.customSlippage();
1837
- const disabledLiquiditySources = useSettingsStore.use.disabledLiquiditySources();
1838
- const [count, setCount] = React.useState(0);
1839
- const [loading, setLoading] = React.useState(false);
1840
- const [error, setError] = React.useState('');
1841
- const [data, setData] = React.useState(null);
1842
- const abortControllerRef = React.useRef(null);
1843
- const retry = () => {
1844
- setCount(prev => prev + 1);
1845
- };
1846
- React.useEffect(() => {
1847
- if (abortControllerRef.current) abortControllerRef.current.abort();
1848
- const abortController = new AbortController();
1849
- abortControllerRef.current = abortController;
1850
- if (!!fromToken && !!toToken && !!inputAmount) {
1851
- if (!!data) setData(null);
1852
- const requestBody = {
1853
- amount: inputAmount?.toString(),
1854
- connectedWallets: [],
1855
- selectedWallets: {},
1856
- checkPrerequisites: false,
1857
- swapperGroups: disabledLiquiditySources,
1858
- swappersGroupsExclude: true,
1859
- from: {
1860
- address: fromToken.address,
1861
- blockchain: fromToken.blockchain,
1862
- 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
+ }]
1863
2398
  },
1864
- to: {
1865
- address: toToken.address,
1866
- blockchain: toToken.blockchain,
1867
- symbol: toToken.symbol
1868
- }
1869
- };
1870
- setLoading(true);
1871
- httpService.getBestRoute(requestBody, {
1872
- signal: abortControllerRef.current.signal
1873
- }).then(res => {
1874
- setData(res);
1875
- setLoading(false);
1876
- abortControllerRef.current = null;
1877
- }).catch(error => {
1878
- if (error.code === 'ERR_CANCELED') return;
1879
- setError(error.message);
1880
- setLoading(false);
1881
- });
1882
- }
1883
- }, [fromToken, toToken, inputAmount, count, slippage, customSlippage, disabledLiquiditySources.length]);
1884
- return {
1885
- loading,
1886
- error,
1887
- data,
1888
- retry
1889
- };
1890
- }
1891
-
1892
- const errorMessages = {
1893
- genericServerError: 'Error connecting server, please reload the app and try again'
1894
- };
1895
-
1896
- const Container$2 = /*#__PURE__*/ui.styled('div', {
1897
- display: 'flex',
1898
- flexDirection: 'column',
1899
- justifyContent: 'center',
1900
- alignItems: 'center'
1901
- });
1902
- const SwitchButtonContainer = /*#__PURE__*/ui.styled('div', {
1903
- display: 'flex',
1904
- justifyContent: 'center',
1905
- alignItems: 'center',
1906
- position: 'relative',
1907
- top: '11px'
1908
- });
1909
- const BestRouteContainer = /*#__PURE__*/ui.styled('div', {
1910
- width: '100%',
1911
- paddingTop: '$16'
1912
- });
1913
- const Alerts = /*#__PURE__*/ui.styled('div', {
1914
- paddingTop: '$16'
1915
- });
1916
- function Home() {
1917
- const waningMessage = '';
1918
- 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() {
1919
2413
  const navigate = reactRouterDom.useNavigate();
1920
- const [count, setCount] = React.useState(0);
1921
- const fromChain = useBestRouteStore.use.fromChain();
1922
- const fromToken = useBestRouteStore.use.fromToken();
1923
- const toChain = useBestRouteStore.use.toChain();
1924
- const toToken = useBestRouteStore.use.toToken();
1925
- const setFromChain = useBestRouteStore.use.setFromChain();
1926
- const setFromToken = useBestRouteStore.use.setFromToken();
1927
- const setToChain = useBestRouteStore.use.setToChain();
1928
- const setToToken = useBestRouteStore.use.setToToken();
1929
- const setBestRoute = useBestRouteStore.use.setBestRoute();
1930
- const inputUsdValue = useBestRouteStore.use.inputUsdValue();
1931
- const inputAmount = useBestRouteStore.use.inputAmount();
1932
- const setInputAmount = useBestRouteStore.use.setInputAmount();
1933
- const outputAmount = useBestRouteStore.use.outputAmount();
1934
- const outputUsdValue = useBestRouteStore.use.outputUsdValue();
1935
- const bestRoute = useBestRouteStore.use.bestRoute();
1936
- const loadingMetaStatus = useMetaStore.use.loadingStatus();
1937
- const accounts = useWalletsStore.use.accounts();
1938
- const swithFromAndTo = () => {
1939
- setFromChain(toChain);
1940
- setFromToken(toToken);
1941
- setToChain(fromChain);
1942
- setToToken(fromToken);
1943
- setInputAmount(outputAmount?.toString() || '');
1944
- setCount(prev => prev + 1);
1945
- };
1946
2414
  const {
1947
- data,
1948
- loading: fetchingBestRoute,
1949
- error: bestRouteError,
1950
- retry
1951
- } = useBestRoute();
1952
- const noConnectedWallet = accounts.length > 0;
1953
- const noRoutesFound = !bestRoute?.result;
1954
- const errorMessage = loadingMetaStatus === 'failed' ? errorMessages.genericServerError : bestRouteError;
1955
- const needsToWarnEthOnPath = false;
1956
- const showBestRoute = inputAmount && (!!data || fetchingBestRoute || bestRouteError);
1957
- const outToInRatio = getOutputRatio(inputUsdValue, outputUsdValue);
1958
- const highValueLoss = outputRatioHasWarning(inputUsdValue, outToInRatio);
1959
- const priceImpactCanNotBeComputed = !canComputePriceImpact(bestRoute, inputAmount, inputUsdValue, outputUsdValue);
1960
- const buttonTitle = getSwapButtonTitle(accounts, fetchingBestRoute, hasLimitError(bestRoute), highValueLoss, priceImpactCanNotBeComputed, needsToWarnEthOnPath);
1961
- const buttonDisabled = loadingMetaStatus != 'success' || fetchingBestRoute || highValueLoss || noConnectedWallet && noRoutesFound || hasLimitError(bestRoute);
1962
- React.useEffect(() => {
1963
- setBestRoute(data);
1964
- }, [data]);
1965
- return React__default.createElement(Container$2, null, React__default.createElement(Header, {
1966
- onClickRefresh: retry
1967
- }), React__default.createElement(TokenInfo, {
1968
- type: "From",
1969
- chain: fromChain,
1970
- token: fromToken,
1971
- onAmountChange: setInputAmount,
1972
- inputAmount: inputAmount
1973
- }), React__default.createElement(SwitchButtonContainer, null, React__default.createElement(ui.Button, {
1974
- variant: "ghost",
1975
- onClick: swithFromAndTo
1976
- }, React__default.createElement(ui.VerticalSwapIcon, {
1977
- size: 36
1978
- }), isRouterInContext && React__default.createElement(SwithFromAndTo, {
1979
- count: count
1980
- }))), React__default.createElement(TokenInfo, {
1981
- type: "To",
1982
- chain: toChain,
1983
- token: toToken,
1984
- outputAmount: outputAmount,
1985
- outputUsdValue: outputUsdValue
1986
- }), showBestRoute && React__default.createElement(BestRouteContainer, null, React__default.createElement(ui.BestRoute, {
1987
- error: bestRouteError,
1988
- loading: fetchingBestRoute,
1989
- data: data
1990
- })), (errorMessage || waningMessage) && React__default.createElement(Alerts, null, errorMessage && React__default.createElement(ui.Alert, {
1991
- description: errorMessage,
1992
- type: "error"
1993
- }), waningMessage ), React__default.createElement(Footer, null, React__default.createElement(ui.Button, {
1994
- type: "primary",
1995
- align: "grow",
1996
- size: "large",
1997
- disabled: buttonDisabled,
1998
- onClick: () => {
1999
- if (buttonTitle === 'Connect Wallet') navigate(navigationRoutes.wallets);else {
2000
- navigate(navigationRoutes.confirmWallets);
2001
- }
2002
- }
2003
- }, 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
+ });
2004
2422
  }
2005
2423
 
2006
2424
  function LiquiditySourcePage() {
@@ -2010,7 +2428,9 @@ function LiquiditySourcePage() {
2010
2428
  const toggleLiquiditySource = useSettingsStore.use.toggleLiquiditySource();
2011
2429
  const disabledLiquiditySources = useSettingsStore.use.disabledLiquiditySources();
2012
2430
  const toggleAllLiquiditySources = useSettingsStore.use.toggleAllLiquiditySources();
2013
- const navigate = reactRouterDom.useNavigate();
2431
+ const {
2432
+ navigateBackFrom
2433
+ } = useNavigateBack();
2014
2434
  const uniqueSwappersGroups = [];
2015
2435
  removeDuplicateFrom(swappers.map(s => s.swapperGroup)).map(swapperGroup => {
2016
2436
  return swappers.find(s => s.swapperGroup === swapperGroup);
@@ -2030,9 +2450,7 @@ function LiquiditySourcePage() {
2030
2450
  toggleAll: toggleAllLiquiditySources,
2031
2451
  list: uniqueSwappersGroups,
2032
2452
  onChange: liquiditySource => toggleLiquiditySource(liquiditySource.title),
2033
- onBack: () => {
2034
- navigate(-1);
2035
- }
2453
+ onBack: navigateBackFrom.bind(null, navigationRoutes.liquiditySources)
2036
2454
  });
2037
2455
  }
2038
2456
 
@@ -2040,7 +2458,6 @@ function SelectChainPage(props) {
2040
2458
  const {
2041
2459
  type
2042
2460
  } = props;
2043
- const accounts = useWalletsStore.use.accounts();
2044
2461
  const {
2045
2462
  blockchains
2046
2463
  } = useMetaStore.use.meta();
@@ -2051,30 +2468,21 @@ function SelectChainPage(props) {
2051
2468
  const setToChain = useBestRouteStore.use.setToChain();
2052
2469
  const setFromToken = useBestRouteStore.use.setFromToken();
2053
2470
  const setToToken = useBestRouteStore.use.setToToken();
2054
- const navigate = reactRouterDom.useNavigate();
2055
- const [list, setList] = React.useState(blockchains);
2056
- React.useEffect(() => {
2057
- let chainSortedByConnectedWallets = [];
2058
- if (accounts.length !== 0) {
2059
- const connectedChains = removeDuplicateFrom(accounts.map(account => account.chain));
2060
- chainSortedByConnectedWallets = blockchains.sort((blockchainA, blockchainB) => connectedChains.lastIndexOf(blockchainA.name) - connectedChains.lastIndexOf(blockchainB.name));
2061
- } else {
2062
- chainSortedByConnectedWallets = blockchains;
2063
- }
2064
- setList(chainSortedByConnectedWallets);
2065
- }, [blockchains.length, accounts.length]);
2471
+ const {
2472
+ navigateBackFrom
2473
+ } = useNavigateBack();
2066
2474
  return React__default.createElement(ui.BlockchainSelector, {
2067
2475
  type: type === 'from' ? 'Source' : 'Destination',
2068
- list: list,
2476
+ list: blockchains,
2069
2477
  selected: type === 'from' ? fromChain : toChain,
2070
2478
  loadingStatus: loadingStatus,
2071
2479
  onChange: chain => {
2072
2480
  if (type === 'from') setFromChain(chain);else setToChain(chain);
2073
2481
  if (type === 'from' && fromChain?.name != chain.name) setFromToken(null);
2074
2482
  if (type === 'to' && toChain?.name != chain.name) setToToken(null);
2075
- navigate(-1);
2483
+ navigateBackFrom(navigationRoutes.fromChain);
2076
2484
  },
2077
- onBack: navigate.bind(null, -1)
2485
+ onBack: navigateBackFrom.bind(null, navigationRoutes.fromChain)
2078
2486
  });
2079
2487
  }
2080
2488
 
@@ -2082,7 +2490,9 @@ function SelectTokenPage(props) {
2082
2490
  const {
2083
2491
  type
2084
2492
  } = props;
2085
- const navigate = reactRouterDom.useNavigate();
2493
+ const {
2494
+ navigateBackFrom
2495
+ } = useNavigateBack();
2086
2496
  const {
2087
2497
  tokens
2088
2498
  } = useMetaStore.use.meta();
@@ -2116,9 +2526,9 @@ function SelectTokenPage(props) {
2116
2526
  selected: type === 'from' ? fromToken : toToken,
2117
2527
  onChange: token => {
2118
2528
  if (type === 'from') setFromToken(token);else setToToken(token);
2119
- navigate(-1);
2529
+ navigateBackFrom(navigationRoutes.fromToken);
2120
2530
  },
2121
- onBack: navigate.bind(null, -1)
2531
+ onBack: navigateBackFrom.bind(null, navigationRoutes.fromToken)
2122
2532
  });
2123
2533
  }
2124
2534
 
@@ -2134,6 +2544,9 @@ function SettingsPage() {
2134
2544
  swappers
2135
2545
  } = useMetaStore.use.meta();
2136
2546
  const navigate = reactRouterDom.useNavigate();
2547
+ const {
2548
+ navigateBackFrom
2549
+ } = useNavigateBack();
2137
2550
  const uniqueSwappersGroups = [];
2138
2551
  removeDuplicateFrom(swappers.map(s => s.swapperGroup)).map(swapperGroup => {
2139
2552
  return swappers.find(s => s.swapperGroup === swapperGroup);
@@ -2150,17 +2563,17 @@ function SettingsPage() {
2150
2563
  }
2151
2564
  });
2152
2565
  return React__default.createElement(ui.Settings, {
2153
- slippages: [1, 2, 3, 4],
2566
+ slippages: SLIPPAGES,
2154
2567
  selectedSlippage: slippage,
2155
2568
  onSlippageChange: slippage => setSlippage(slippage),
2156
2569
  liquiditySources: uniqueSwappersGroups,
2157
2570
  selectedLiquiditySources: uniqueSwappersGroups.filter(s => s.selected),
2158
- onLiquiditySourcesClick: () => navigate(navigationRoutes.liquiditySources),
2159
- onBack: navigate.bind(null, -1),
2571
+ onLiquiditySourcesClick: navigate.bind(null, navigationRoutes.liquiditySources),
2572
+ onBack: navigateBackFrom.bind(null, navigationRoutes.settings),
2160
2573
  customSlippage: customSlippage || NaN,
2161
2574
  onCustomSlippageChange: setCustomSlippage,
2162
- minSlippage: 1,
2163
- maxSlippage: 10,
2575
+ minSlippage: MIN_SLIPPGAE,
2576
+ maxSlippage: MAX_SLIPPAGE,
2164
2577
  selectedTheme: theme,
2165
2578
  onThemeChange: setTheme
2166
2579
  });
@@ -2171,13 +2584,16 @@ const ListContainer = /*#__PURE__*/ui.styled('div', {
2171
2584
  gap: '.5rem',
2172
2585
  gridTemplateColumns: ' repeat(2, minmax(0, 1fr))',
2173
2586
  height: '450px',
2174
- alignContent: 'baseline'
2587
+ alignContent: 'baseline',
2588
+ padding: '0 0.5rem'
2175
2589
  });
2176
2590
  const AlertContainer = /*#__PURE__*/ui.styled('div', {
2177
2591
  paddingBottom: '$16'
2178
2592
  });
2179
2593
  function WalletsPage() {
2180
- const navigate = reactRouterDom.useNavigate();
2594
+ const {
2595
+ navigateBackFrom
2596
+ } = useNavigateBack();
2181
2597
  const {
2182
2598
  state,
2183
2599
  disconnect,
@@ -2186,6 +2602,7 @@ function WalletsPage() {
2186
2602
  } = walletsCore.useWallets();
2187
2603
  const wallets = getlistWallet(state, getWalletInfo, Object.values(walletsShared.WalletType));
2188
2604
  const [walletErrorMessage, setWalletErrorMessage] = React.useState('');
2605
+ const toggleConnectWalletsButton = useUiStore.use.toggleConnectWalletsButton();
2189
2606
  const onSelectWallet = async type => {
2190
2607
  const wallet = state(type);
2191
2608
  try {
@@ -2199,24 +2616,29 @@ function WalletsPage() {
2199
2616
  setWalletErrorMessage('Error: ' + e.message);
2200
2617
  }
2201
2618
  };
2619
+ React.useEffect(() => {
2620
+ toggleConnectWalletsButton();
2621
+ return () => toggleConnectWalletsButton();
2622
+ }, []);
2202
2623
  return React__default.createElement(ui.SecondaryPage, {
2203
2624
  title: "Select Wallet",
2204
2625
  textField: false,
2205
- onBack: () => {
2206
- navigate(-1);
2207
- },
2208
- Content: React__default.createElement(React__default.Fragment, null, walletErrorMessage && React__default.createElement(AlertContainer, null, React__default.createElement(ui.Alert, {
2209
- type: "error",
2210
- description: walletErrorMessage
2211
- })), React__default.createElement(ListContainer, null, wallets.map((info, index) => React__default.createElement(ui.Wallet, Object.assign({}, info, {
2212
- key: index,
2213
- onClick: onSelectWallet
2214
- })))))
2215
- });
2626
+ onBack: navigateBackFrom.bind(null, navigationRoutes.wallets)
2627
+ }, React__default.createElement(React__default.Fragment, null, walletErrorMessage && React__default.createElement(AlertContainer, null, React__default.createElement(ui.Alert, {
2628
+ type: "error"
2629
+ }, React__default.createElement(ui.Typography, {
2630
+ variant: "body2"
2631
+ }, walletErrorMessage))), React__default.createElement(ListContainer, null, wallets.map((info, index) => React__default.createElement(ui.Wallet, Object.assign({}, info, {
2632
+ key: index,
2633
+ onClick: onSelectWallet
2634
+ }))))));
2216
2635
  }
2217
2636
 
2218
2637
  function ConfirmWalletsPage() {
2219
2638
  const navigate = reactRouterDom.useNavigate();
2639
+ const {
2640
+ navigateBackFrom
2641
+ } = useNavigateBack();
2220
2642
  const bestRoute = useBestRouteStore.use.bestRoute();
2221
2643
  const {
2222
2644
  blockchains
@@ -2230,10 +2652,14 @@ function ConfirmWalletsPage() {
2230
2652
  connect
2231
2653
  } = walletsCore.useWallets();
2232
2654
  const confirmDisabled = !requiredWallets(bestRoute).every(chain => selectedWallets.map(wallet => wallet.chain).includes(chain));
2655
+ const firstStep = bestRoute?.result?.swaps[0];
2656
+ const lastStep = bestRoute?.result?.swaps[bestRoute?.result?.swaps.length - 1];
2657
+ const fromAmount = decimalNumber(firstStep?.fromAmount, 3);
2658
+ const toAmount = decimalNumber(lastStep?.toAmount, 3);
2233
2659
  React.useEffect(() => {
2234
2660
  initSelectedWallets();
2235
2661
  }, []);
2236
- const selectableWallets = getSelectableWallets(accounts, selectedWallets, getWalletInfo, getRequiredChains(bestRoute));
2662
+ const selectableWallets = getSelectableWallets(accounts, selectedWallets, getWalletInfo);
2237
2663
  const handleConnectChain = wallet => {
2238
2664
  const network = wallet;
2239
2665
  getKeplrCompatibleConnectedWallets(selectableWallets).forEach(compatibleWallet => connect?.(compatibleWallet, network));
@@ -2241,9 +2667,11 @@ function ConfirmWalletsPage() {
2241
2667
  return React__default.createElement(ui.ConfirmWallets, {
2242
2668
  requiredWallets: getRequiredChains(bestRoute),
2243
2669
  selectableWallets: selectableWallets,
2244
- onBack: () => navigate(-1),
2670
+ onBack: navigateBackFrom.bind(null, navigationRoutes.confirmWallets),
2245
2671
  swap: bestRoute,
2246
- onConfirm: () => navigate(navigationRoutes.confirmSwap),
2672
+ fromAmount: fromAmount,
2673
+ toAmount: toAmount,
2674
+ onConfirm: navigate.bind(null, navigationRoutes.confirmSwap),
2247
2675
  onChange: wallet => setSelectedWallet(wallet),
2248
2676
  confirmDisabled: confirmDisabled,
2249
2677
  handleConnectChain: wallet => handleConnectChain(wallet),
@@ -2714,9 +3142,11 @@ const pendingSwap$1 = {
2714
3142
  };
2715
3143
 
2716
3144
  function SwapDetailsPage() {
2717
- const navigate = reactRouterDom.useNavigate();
3145
+ const {
3146
+ navigateBackFrom
3147
+ } = useNavigateBack();
2718
3148
  return React__default.createElement(ui.SwapHistory, {
2719
- onBack: navigate.bind(null, -1),
3149
+ onBack: navigateBackFrom.bind(null, navigationRoutes.swapDetails),
2720
3150
  pendingSwap: pendingSwap$1
2721
3151
  });
2722
3152
  }
@@ -2789,8 +3219,9 @@ function Layout() {
2789
3219
  const {
2790
3220
  getWalletInfo
2791
3221
  } = walletsCore.useWallets();
2792
- const filterSelelectedWallets = getSelectableWallets(accounts, selectedWallets, getWalletInfo);
3222
+ const connectedWalletsImages = removeDuplicateFrom(getSelectableWallets(accounts, selectedWallets, getWalletInfo).map(w => w.image));
2793
3223
  const totalBalance = calculateWalletUsdValue(balances);
3224
+ const connectWalletsButtonDisabled = useUiStore.use.connectWalletsButtonDisabled();
2794
3225
  return React__default.createElement(React__default.Fragment, null, React__default.createElement(Header$1, null, React__default.createElement(ui.Button, {
2795
3226
  size: "small",
2796
3227
  suffix: React__default.createElement(ui.AddWalletIcon, {
@@ -2798,10 +3229,12 @@ function Layout() {
2798
3229
  }),
2799
3230
  variant: "ghost",
2800
3231
  flexContent: true,
2801
- onClick: () => navigate(navigationRoutes.wallets)
2802
- }, accounts?.length ? filterSelelectedWallets.map((selectedWallet, index) => React__default.createElement(WalletImage, {
3232
+ onClick: () => {
3233
+ if (!connectWalletsButtonDisabled) navigate(navigationRoutes.wallets);
3234
+ }
3235
+ }, connectedWalletsImages?.length ? connectedWalletsImages.map((walletImage, index) => React__default.createElement(WalletImage, {
2803
3236
  key: index,
2804
- src: selectedWallet.image
3237
+ src: walletImage
2805
3238
  })) : React__default.createElement(React__default.Fragment, null), React__default.createElement(ui.Typography, {
2806
3239
  variant: "body2"
2807
3240
  }, !accounts?.length ? 'Connect Wallet' : `$${totalBalance || 0}`))), React__default.createElement(AppRoutes, null));