@rango-dev/widget-embedded 0.1.10-next.80 → 0.1.10-next.82
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/AppRouter.d.ts.map +1 -1
- package/dist/components/AppRoutes.d.ts.map +1 -1
- package/dist/components/ChangeSlippageButton.d.ts +2 -0
- package/dist/components/ChangeSlippageButton.d.ts.map +1 -0
- package/dist/components/ConfirmSwapErrors.d.ts +3 -0
- package/dist/components/ConfirmSwapErrors.d.ts.map +1 -0
- package/dist/components/ConfirmSwapWarnings.d.ts +3 -0
- package/dist/components/ConfirmSwapWarnings.d.ts.map +1 -0
- package/dist/components/Layout.d.ts.map +1 -1
- package/dist/components/UpdateUrl.d.ts.map +1 -1
- package/dist/components/warnings/BalanceWarnings.d.ts +6 -0
- package/dist/components/warnings/BalanceWarnings.d.ts.map +1 -0
- package/dist/components/warnings/ConfirmSwapExtraMessages.d.ts +6 -0
- package/dist/components/warnings/ConfirmSwapExtraMessages.d.ts.map +1 -0
- package/dist/components/warnings/HighSlippageWarning.d.ts +6 -0
- package/dist/components/warnings/HighSlippageWarning.d.ts.map +1 -0
- package/dist/components/warnings/MinRequiredSlippage.d.ts +6 -0
- package/dist/components/warnings/MinRequiredSlippage.d.ts.map +1 -0
- package/dist/constants/swapSettings.d.ts +6 -0
- package/dist/constants/swapSettings.d.ts.map +1 -0
- package/dist/hooks/useNavigateBack.d.ts +4 -0
- package/dist/hooks/useNavigateBack.d.ts.map +1 -0
- package/dist/pages/ConfirmSwapPage.d.ts.map +1 -1
- package/dist/pages/ConfirmWalletsPage.d.ts +0 -5
- package/dist/pages/ConfirmWalletsPage.d.ts.map +1 -1
- package/dist/pages/HistoryPage.d.ts.map +1 -1
- package/dist/pages/Home.d.ts.map +1 -1
- package/dist/pages/LiquiditySourcesPage.d.ts.map +1 -1
- package/dist/pages/SelectChainPage.d.ts.map +1 -1
- package/dist/pages/SelectTokenPage.d.ts.map +1 -1
- package/dist/pages/SettingsPage.d.ts.map +1 -1
- package/dist/pages/SwapDetailsPage.d.ts.map +1 -1
- package/dist/pages/WalletsPage.d.ts.map +1 -1
- package/dist/store/bestRoute.d.ts +1 -0
- package/dist/store/bestRoute.d.ts.map +1 -1
- package/dist/store/confirmSwap.d.ts +35 -0
- package/dist/store/confirmSwap.d.ts.map +1 -0
- package/dist/store/settings.d.ts.map +1 -1
- package/dist/store/ui.d.ts +2 -0
- package/dist/store/ui.d.ts.map +1 -0
- package/dist/store/wallets.d.ts.map +1 -1
- package/dist/types/index.d.ts +2 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/swap.d.ts +11 -0
- package/dist/types/swap.d.ts.map +1 -0
- package/dist/utils/common.d.ts +1 -0
- package/dist/utils/common.d.ts.map +1 -1
- package/dist/utils/numbers.d.ts +5 -0
- package/dist/utils/numbers.d.ts.map +1 -1
- package/dist/utils/routing.d.ts +5 -7
- package/dist/utils/routing.d.ts.map +1 -1
- package/dist/utils/swap.d.ts +31 -3
- package/dist/utils/swap.d.ts.map +1 -1
- package/dist/utils/wallets.d.ts +2 -3
- package/dist/utils/wallets.d.ts.map +1 -1
- package/dist/widget-embedded.cjs.development.js +1814 -1327
- package/dist/widget-embedded.cjs.development.js.map +1 -1
- package/dist/widget-embedded.cjs.production.min.js +1814 -1327
- package/dist/widget-embedded.cjs.production.min.js.map +1 -1
- package/dist/widget-embedded.esm.js +1818 -1331
- package/dist/widget-embedded.esm.js.map +1 -1
- package/package.json +1 -1
- package/src/components/AppRouter.tsx +38 -3
- package/src/components/AppRoutes.tsx +8 -2
- package/src/components/ChangeSlippageButton.tsx +23 -0
- package/src/components/ConfirmSwapErrors.tsx +38 -0
- package/src/components/ConfirmSwapWarnings.tsx +38 -0
- package/src/components/Layout.tsx +22 -6
- package/src/components/UpdateUrl.tsx +100 -18
- package/src/components/warnings/BalanceWarnings.tsx +16 -0
- package/src/components/warnings/ConfirmSwapExtraMessages.tsx +14 -0
- package/src/components/warnings/HighSlippageWarning.tsx +21 -0
- package/src/components/warnings/MinRequiredSlippage.tsx +18 -0
- package/src/constants/navigationRoutes.ts +2 -2
- package/src/constants/swapSettings.ts +9 -0
- package/src/hooks/useNavigateBack.ts +37 -0
- package/src/pages/ConfirmSwapPage.tsx +30 -8
- package/src/pages/ConfirmWalletsPage.tsx +30 -17
- package/src/pages/HistoryPage.tsx +4 -4
- package/src/pages/Home.tsx +79 -36
- package/src/pages/LiquiditySourcesPage.tsx +11 -8
- package/src/pages/SelectChainPage.tsx +9 -28
- package/src/pages/SelectTokenPage.tsx +38 -27
- package/src/pages/SettingsPage.tsx +26 -11
- package/src/pages/SwapDetailsPage.tsx +9 -3
- package/src/pages/WalletsPage.tsx +37 -22
- package/src/store/bestRoute.ts +147 -28
- package/src/store/confirmSwap.ts +327 -0
- package/src/store/settings.ts +44 -32
- package/src/store/ui.ts +15 -0
- package/src/store/wallets.ts +93 -80
- package/src/swapBox.tsx +5 -5
- package/src/types/index.ts +1 -0
- package/src/types/swap.ts +13 -0
- package/src/utils/common.ts +4 -0
- package/src/utils/numbers.ts +17 -0
- package/src/utils/routing.ts +28 -77
- package/src/utils/swap.ts +445 -67
- package/src/utils/wallets.ts +4 -19
- package/dist/hooks/useBestRoute.d.ts +0 -8
- package/dist/hooks/useBestRoute.d.ts.map +0 -1
- package/dist/hooks/useConfirmSwap.d.ts +0 -2
- package/dist/hooks/useConfirmSwap.d.ts.map +0 -1
- package/src/hooks/useBestRoute.ts +0 -70
- package/src/hooks/useConfirmSwap.ts +0 -268
package/src/utils/swap.ts
CHANGED
|
@@ -1,27 +1,55 @@
|
|
|
1
1
|
import { PendingSwap } from '@rango-dev/ui/dist/containers/History/types';
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
WalletTypeAndAddress,
|
|
4
|
+
SwapSavedSettings,
|
|
5
|
+
} from '@rango-dev/ui/dist/types/swaps';
|
|
3
6
|
import BigNumber from 'bignumber.js';
|
|
4
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
BestRouteRequest,
|
|
9
|
+
BestRouteResponse,
|
|
10
|
+
RecommendedSlippage,
|
|
11
|
+
SwapResult,
|
|
12
|
+
MetaResponse,
|
|
13
|
+
Token,
|
|
14
|
+
} from 'rango-sdk';
|
|
5
15
|
import { Account } from '../store/wallets';
|
|
6
16
|
import { ZERO } from '../constants/numbers';
|
|
17
|
+
import { numberToString } from './numbers';
|
|
18
|
+
import { WalletType } from '@rango-dev/wallets-shared';
|
|
19
|
+
import { getRequiredBalanceOfWallet } from './routing';
|
|
20
|
+
import { getRequiredChains, SelectedWallet } from './wallets';
|
|
21
|
+
import { SwapButtonState } from '../types';
|
|
22
|
+
import { LoadingStatus } from '../store/meta';
|
|
7
23
|
|
|
8
|
-
export function getOutputRatio(
|
|
24
|
+
export function getOutputRatio(
|
|
25
|
+
inputUsdValue: BigNumber,
|
|
26
|
+
outputUsdValue: BigNumber
|
|
27
|
+
) {
|
|
9
28
|
if (inputUsdValue.lte(ZERO) || outputUsdValue.lte(ZERO)) return 0;
|
|
10
29
|
return outputUsdValue.div(inputUsdValue).minus(1).multipliedBy(100);
|
|
11
30
|
}
|
|
12
31
|
|
|
13
|
-
export function outputRatioHasWarning(
|
|
32
|
+
export function outputRatioHasWarning(
|
|
33
|
+
inputUsdValue: BigNumber,
|
|
34
|
+
outputRatio: BigNumber | 0
|
|
35
|
+
) {
|
|
14
36
|
return (
|
|
15
|
-
(parseInt(outputRatio.toFixed(2) || '0') <= -10 &&
|
|
16
|
-
|
|
37
|
+
(parseInt(outputRatio.toFixed(2) || '0') <= -10 &&
|
|
38
|
+
inputUsdValue.gte(new BigNumber(400))) ||
|
|
39
|
+
(parseInt(outputRatio.toFixed(2) || '0') <= -5 &&
|
|
40
|
+
inputUsdValue.gte(new BigNumber(1000)))
|
|
17
41
|
);
|
|
18
42
|
}
|
|
19
43
|
|
|
20
44
|
export function hasLimitError(bestRoute: BestRouteResponse | null): boolean {
|
|
21
45
|
return (
|
|
22
46
|
(bestRoute?.result?.swaps || []).filter((swap) => {
|
|
23
|
-
const minimum = !!swap.fromAmountMinValue
|
|
24
|
-
|
|
47
|
+
const minimum = !!swap.fromAmountMinValue
|
|
48
|
+
? new BigNumber(swap.fromAmountMinValue)
|
|
49
|
+
: null;
|
|
50
|
+
const maximum = !!swap.fromAmountMaxValue
|
|
51
|
+
? new BigNumber(swap.fromAmountMaxValue)
|
|
52
|
+
: null;
|
|
25
53
|
const isExclusive = swap.fromAmountRestrictionType === 'EXCLUSIVE';
|
|
26
54
|
if (isExclusive) {
|
|
27
55
|
return minimum?.gte(swap.fromAmount) || maximum?.lte(swap.fromAmount);
|
|
@@ -32,36 +60,112 @@ export function hasLimitError(bestRoute: BestRouteResponse | null): boolean {
|
|
|
32
60
|
);
|
|
33
61
|
}
|
|
34
62
|
|
|
35
|
-
export function
|
|
63
|
+
export function LimitErrorMessage(bestRoute: BestRouteResponse | null): {
|
|
64
|
+
swap: SwapResult | null;
|
|
65
|
+
fromAmountRangeError: string;
|
|
66
|
+
recommendation: string;
|
|
67
|
+
} {
|
|
68
|
+
if (!bestRoute)
|
|
69
|
+
return { swap: null, fromAmountRangeError: '', recommendation: '' };
|
|
70
|
+
const swap = (bestRoute?.result?.swaps || []).filter((swap) => {
|
|
71
|
+
const minimum = !!swap.fromAmountMinValue
|
|
72
|
+
? new BigNumber(swap.fromAmountMinValue)
|
|
73
|
+
: null;
|
|
74
|
+
const maximum = !!swap.fromAmountMaxValue
|
|
75
|
+
? new BigNumber(swap.fromAmountMaxValue)
|
|
76
|
+
: null;
|
|
77
|
+
const isExclusive = swap.fromAmountRestrictionType === 'EXCLUSIVE';
|
|
78
|
+
if (isExclusive) {
|
|
79
|
+
return minimum?.gte(swap.fromAmount) || maximum?.lte(swap.fromAmount);
|
|
80
|
+
} else {
|
|
81
|
+
return minimum?.gt(swap.fromAmount) || maximum?.lt(swap.fromAmount);
|
|
82
|
+
}
|
|
83
|
+
})[0];
|
|
84
|
+
if (!swap)
|
|
85
|
+
return { swap: null, fromAmountRangeError: '', recommendation: '' };
|
|
86
|
+
const minimum = !!swap.fromAmountMinValue
|
|
87
|
+
? new BigNumber(swap.fromAmountMinValue)
|
|
88
|
+
: null;
|
|
89
|
+
const maximum = !!swap.fromAmountMaxValue
|
|
90
|
+
? new BigNumber(swap.fromAmountMaxValue)
|
|
91
|
+
: null;
|
|
92
|
+
const isExclusive = swap.fromAmountRestrictionType === 'EXCLUSIVE';
|
|
93
|
+
|
|
94
|
+
let fromAmountRangeError = '';
|
|
95
|
+
let recommendation = '';
|
|
96
|
+
if (!isExclusive && !!minimum && minimum.gt(swap.fromAmount)) {
|
|
97
|
+
fromAmountRangeError = `Required: >= ${numberToString(minimum)} ${
|
|
98
|
+
swap.from.symbol
|
|
99
|
+
}`;
|
|
100
|
+
recommendation = 'Increase your swap amount';
|
|
101
|
+
} else if (isExclusive && !!minimum && minimum.gte(swap.fromAmount)) {
|
|
102
|
+
fromAmountRangeError = `Required: > ${numberToString(minimum)} ${
|
|
103
|
+
swap.from.symbol
|
|
104
|
+
}`;
|
|
105
|
+
recommendation = 'Increase your swap amount';
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (!isExclusive && !!maximum && maximum.lt(swap.fromAmount)) {
|
|
109
|
+
fromAmountRangeError = `Required: <= ${numberToString(maximum)} ${
|
|
110
|
+
swap.from.symbol
|
|
111
|
+
}`;
|
|
112
|
+
recommendation = 'Decrease your swap amount';
|
|
113
|
+
} else if (isExclusive && !!maximum && maximum.lte(swap.fromAmount)) {
|
|
114
|
+
fromAmountRangeError = `Required: < ${numberToString(maximum)} ${
|
|
115
|
+
swap.from.symbol
|
|
116
|
+
}`;
|
|
117
|
+
recommendation = 'Decrease your swap amount';
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return { swap, fromAmountRangeError, recommendation };
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export function getSwapButtonState(
|
|
124
|
+
loadingMetaStatus: LoadingStatus,
|
|
36
125
|
accounts: Account[],
|
|
37
126
|
loading: boolean,
|
|
127
|
+
bestRoute: BestRouteResponse | null,
|
|
38
128
|
hasLimitError: boolean,
|
|
39
129
|
highValueLoss: boolean,
|
|
40
130
|
priceImpactCanNotBeComputed: boolean,
|
|
41
|
-
needsToWarnEthOnPath: boolean
|
|
42
|
-
):
|
|
43
|
-
if (
|
|
44
|
-
|
|
45
|
-
if (accounts.length == 0) return 'Connect Wallet';
|
|
46
|
-
|
|
47
|
-
else if (
|
|
48
|
-
else if (
|
|
49
|
-
else if (
|
|
50
|
-
|
|
131
|
+
needsToWarnEthOnPath: boolean
|
|
132
|
+
): SwapButtonState {
|
|
133
|
+
if (loadingMetaStatus !== 'success')
|
|
134
|
+
return { title: 'Connect Wallet', disabled: true };
|
|
135
|
+
if (accounts.length == 0) return { title: 'Connect Wallet', disabled: false };
|
|
136
|
+
if (loading) return { title: 'Finding Best Route...', disabled: true };
|
|
137
|
+
else if (!bestRoute) return { title: 'Swap', disabled: true };
|
|
138
|
+
else if (hasLimitError) return { title: 'Limit Error', disabled: true };
|
|
139
|
+
else if (highValueLoss)
|
|
140
|
+
return { title: 'Price impact is too high!', disabled: true };
|
|
141
|
+
else if (priceImpactCanNotBeComputed)
|
|
142
|
+
return {
|
|
143
|
+
title: 'USD price is unknown, price impact might be high!',
|
|
144
|
+
disabled: false,
|
|
145
|
+
hasWarning: true,
|
|
146
|
+
};
|
|
147
|
+
else if (needsToWarnEthOnPath)
|
|
148
|
+
return {
|
|
149
|
+
title: 'The route goes through Ethereum. Continue?',
|
|
150
|
+
disabled: false,
|
|
151
|
+
hasWarning: true,
|
|
152
|
+
};
|
|
153
|
+
else return { title: 'Swap', disabled: false };
|
|
51
154
|
}
|
|
52
155
|
|
|
53
156
|
export function canComputePriceImpact(
|
|
54
157
|
bestRoute: BestRouteResponse | null,
|
|
55
158
|
inputAmount: string,
|
|
56
159
|
inputUsdValue: BigNumber,
|
|
57
|
-
outputUsdValue: BigNumber
|
|
160
|
+
outputUsdValue: BigNumber
|
|
58
161
|
) {
|
|
59
162
|
return !(
|
|
60
163
|
(inputUsdValue.lte(ZERO) || outputUsdValue.lte(ZERO)) &&
|
|
61
164
|
!!bestRoute?.result &&
|
|
62
165
|
!!inputAmount &&
|
|
63
166
|
inputAmount !== '0' &&
|
|
64
|
-
parseFloat(inputAmount || '0') !== 0
|
|
167
|
+
parseFloat(inputAmount || '0') !== 0 &&
|
|
168
|
+
!!bestRoute.result
|
|
65
169
|
);
|
|
66
170
|
}
|
|
67
171
|
|
|
@@ -69,8 +173,9 @@ export function calculatePendingSwap(
|
|
|
69
173
|
inputAmount: string,
|
|
70
174
|
bestRoute: BestRouteResponse,
|
|
71
175
|
wallets: { [p: string]: WalletTypeAndAddress },
|
|
72
|
-
settings: SwapSavedSettings,
|
|
176
|
+
settings: Omit<SwapSavedSettings, 'disabledSwappersIds'>,
|
|
73
177
|
validateBalanceOrFee: boolean,
|
|
178
|
+
meta: MetaResponse
|
|
74
179
|
): PendingSwap {
|
|
75
180
|
const simulationResult = bestRoute.result;
|
|
76
181
|
if (!simulationResult) throw Error('Simulation result should not be null');
|
|
@@ -90,53 +195,65 @@ export function calculatePendingSwap(
|
|
|
90
195
|
networkStatusExtraMessage: null,
|
|
91
196
|
networkStatusExtraMessageDetail: null,
|
|
92
197
|
lastNotificationTime: null,
|
|
198
|
+
//@ts-ignore
|
|
93
199
|
settings: settings,
|
|
94
200
|
simulationResult: simulationResult,
|
|
95
201
|
validateBalanceOrFee,
|
|
96
|
-
//TODO: finalize PendingSwap type and remove ts-ignore
|
|
97
|
-
//@ts-ignore
|
|
98
202
|
steps:
|
|
99
|
-
bestRoute.result?.swaps?.map((
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
203
|
+
bestRoute.result?.swaps?.map((swap, index) => {
|
|
204
|
+
const swapper = meta.swappers.find(
|
|
205
|
+
(swapper) => swapper.id === swap.swapperId
|
|
206
|
+
);
|
|
207
|
+
const swapperType = swapper?.types[0];
|
|
208
|
+
const fromBlockchain = meta.blockchains.find(
|
|
209
|
+
(blockchain) => blockchain.name === swap.from.blockchain
|
|
210
|
+
);
|
|
211
|
+
const toBlockchain = meta.blockchains.find(
|
|
212
|
+
(blockchain) => blockchain.name === swap.to.blockchain
|
|
213
|
+
);
|
|
214
|
+
return {
|
|
215
|
+
id: index + 1,
|
|
216
|
+
fromBlockchain: swap.from.blockchain,
|
|
217
|
+
fromSymbol: swap.from.symbol,
|
|
218
|
+
fromSymbolAddress: swap.from.address,
|
|
219
|
+
fromDecimals: swap.from.decimals,
|
|
220
|
+
fromAmountPrecision: swap.fromAmountPrecision,
|
|
221
|
+
fromAmountMinValue: swap.fromAmountMinValue,
|
|
222
|
+
fromAmountMaxValue: swap.fromAmountMaxValue,
|
|
223
|
+
toBlockchain: swap.to.blockchain,
|
|
224
|
+
fromLogo: swap.from.logo,
|
|
225
|
+
toSymbol: swap.to.symbol,
|
|
226
|
+
toSymbolAddress: swap.to.address,
|
|
227
|
+
toDecimals: swap.to.decimals,
|
|
228
|
+
toLogo: swap.to.logo,
|
|
229
|
+
startTransactionTime: new Date().getTime(),
|
|
230
|
+
swapperId: swap.swapperId,
|
|
231
|
+
feeInUsd: numberToString(getUsdFeeOfStep(swap, meta.tokens), null, 2),
|
|
232
|
+
expectedOutputAmountHumanReadable: swap.toAmount,
|
|
233
|
+
outputAmount: '',
|
|
234
|
+
status: 'created',
|
|
235
|
+
networkStatus: null,
|
|
236
|
+
executedTransactionId: null,
|
|
237
|
+
externalTransactionId: null,
|
|
238
|
+
explorerUrl: null,
|
|
239
|
+
trackingCode: null,
|
|
240
|
+
cosmosTransaction: null,
|
|
241
|
+
solanaTransaction: null,
|
|
242
|
+
starknetTransaction: null,
|
|
243
|
+
starknetApprovalTransaction: null,
|
|
244
|
+
tronTransaction: null,
|
|
245
|
+
tronApprovalTransaction: null,
|
|
246
|
+
evmTransaction: null,
|
|
247
|
+
evmApprovalTransaction: null,
|
|
248
|
+
transferTransaction: null,
|
|
249
|
+
diagnosisUrl: null,
|
|
250
|
+
internalSteps: null,
|
|
251
|
+
fromBlockchainLogo: fromBlockchain.logo,
|
|
252
|
+
toBlockchainLogo: toBlockchain.logo,
|
|
253
|
+
swapperLogo: swapper?.logo,
|
|
254
|
+
swapperType: swapperType,
|
|
255
|
+
};
|
|
256
|
+
}) || [],
|
|
140
257
|
};
|
|
141
258
|
}
|
|
142
259
|
|
|
@@ -147,9 +264,270 @@ export function requiredWallets(route: BestRouteResponse | null) {
|
|
|
147
264
|
const currentStepFromBlockchain = swap.from.blockchain;
|
|
148
265
|
const currentStepToBlockchain = swap.to.blockchain;
|
|
149
266
|
let lastAddedWallet = wallets[wallets.length - 1];
|
|
150
|
-
if (currentStepFromBlockchain != lastAddedWallet)
|
|
267
|
+
if (currentStepFromBlockchain != lastAddedWallet)
|
|
268
|
+
wallets.push(currentStepFromBlockchain);
|
|
151
269
|
lastAddedWallet = wallets[wallets.length - 1];
|
|
152
|
-
if (currentStepToBlockchain != lastAddedWallet)
|
|
270
|
+
if (currentStepToBlockchain != lastAddedWallet)
|
|
271
|
+
wallets.push(currentStepToBlockchain);
|
|
272
|
+
});
|
|
273
|
+
return wallets;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
export const getUsdPrice = (
|
|
277
|
+
blockchain: string,
|
|
278
|
+
symbol: string,
|
|
279
|
+
address: string | null,
|
|
280
|
+
allTokens: Token[]
|
|
281
|
+
): number | null => {
|
|
282
|
+
const token = allTokens?.find(
|
|
283
|
+
(t) =>
|
|
284
|
+
t.blockchain === blockchain &&
|
|
285
|
+
t.symbol?.toUpperCase() === symbol?.toUpperCase() &&
|
|
286
|
+
t.address === address
|
|
287
|
+
);
|
|
288
|
+
return token?.usdPrice || null;
|
|
289
|
+
};
|
|
290
|
+
|
|
291
|
+
function getUsdFeeOfStep(step: SwapResult, allTokens: Token[]): BigNumber {
|
|
292
|
+
let totalFeeInUsd = ZERO;
|
|
293
|
+
for (let i = 0; i < step.fee.length; i++) {
|
|
294
|
+
const fee = step.fee[i];
|
|
295
|
+
if (fee.expenseType === 'DECREASE_FROM_OUTPUT') continue;
|
|
296
|
+
|
|
297
|
+
const unitPrice = getUsdPrice(
|
|
298
|
+
fee.asset.blockchain,
|
|
299
|
+
fee.asset.symbol,
|
|
300
|
+
fee.asset.address,
|
|
301
|
+
allTokens
|
|
302
|
+
);
|
|
303
|
+
totalFeeInUsd = totalFeeInUsd.plus(
|
|
304
|
+
new BigNumber(fee.amount).multipliedBy(unitPrice || 0)
|
|
305
|
+
);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
return totalFeeInUsd;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
export function getTotalFeeInUsd(
|
|
312
|
+
bestRoute: BestRouteResponse | null,
|
|
313
|
+
allTokens: Token[]
|
|
314
|
+
): BigNumber | null {
|
|
315
|
+
return (
|
|
316
|
+
bestRoute?.result?.swaps.reduce(
|
|
317
|
+
(totalFee: BigNumber, step) =>
|
|
318
|
+
totalFee.plus(getUsdFeeOfStep(step, allTokens)),
|
|
319
|
+
ZERO
|
|
320
|
+
) || null
|
|
321
|
+
);
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
export function hasHighFee(totalFeeInUsd: BigNumber | null) {
|
|
325
|
+
if (!totalFeeInUsd) return false;
|
|
326
|
+
return !totalFeeInUsd.lt(new BigNumber(30));
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
export function hasSlippageError(
|
|
330
|
+
slippages: (RecommendedSlippage | null)[] | undefined
|
|
331
|
+
) {
|
|
332
|
+
return (slippages?.filter((s) => !!s?.error)?.length || 0) > 0;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
export function getMinRequiredSlippage(route: BestRouteResponse) {
|
|
336
|
+
const slippages = route.result?.swaps.map(
|
|
337
|
+
(slippage) => slippage.recommendedSlippage
|
|
338
|
+
);
|
|
339
|
+
return (
|
|
340
|
+
slippages
|
|
341
|
+
?.map((s) => s?.slippage || 0)
|
|
342
|
+
?.filter((s) => s > 0)
|
|
343
|
+
?.sort((a, b) => b - a)
|
|
344
|
+
?.find(() => true) || null
|
|
345
|
+
);
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
export function hasProperSlippage(
|
|
349
|
+
userSlippage: string,
|
|
350
|
+
minRequiredSlippage: number | null
|
|
351
|
+
) {
|
|
352
|
+
if (!minRequiredSlippage) return true;
|
|
353
|
+
return parseFloat(userSlippage) > minRequiredSlippage;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
export function hasEnoughBalance(
|
|
357
|
+
route: BestRouteResponse,
|
|
358
|
+
selectedWallets: SelectedWallet[]
|
|
359
|
+
) {
|
|
360
|
+
const fee = route.validationStatus;
|
|
361
|
+
|
|
362
|
+
if (fee === null || fee.length === 0) return true;
|
|
363
|
+
|
|
364
|
+
for (const wallet of selectedWallets) {
|
|
365
|
+
const requiredAssets = getRequiredBalanceOfWallet(wallet, fee);
|
|
366
|
+
if (!requiredAssets) continue;
|
|
367
|
+
|
|
368
|
+
const enoughBalanceInWallet = requiredAssets
|
|
369
|
+
.map((asset) => asset.ok)
|
|
370
|
+
.reduce((previous, current) => previous && current);
|
|
371
|
+
if (!enoughBalanceInWallet) return false;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
return true;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
export function hasEnoughBalanceAndProperSlippage(
|
|
378
|
+
route: BestRouteResponse,
|
|
379
|
+
selectedWallets: SelectedWallet[],
|
|
380
|
+
userSlippage: string,
|
|
381
|
+
minRequiredSlippage: number | null
|
|
382
|
+
): boolean {
|
|
383
|
+
return (
|
|
384
|
+
hasEnoughBalance(route, selectedWallets) &&
|
|
385
|
+
hasProperSlippage(userSlippage, minRequiredSlippage)
|
|
386
|
+
);
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
export function createBestRouteRequestBody(
|
|
390
|
+
fromToken: Token,
|
|
391
|
+
toToken: Token,
|
|
392
|
+
inputAmount: string,
|
|
393
|
+
wallets: Account[],
|
|
394
|
+
selectedWallets: SelectedWallet[],
|
|
395
|
+
disabledLiquiditySources: string[],
|
|
396
|
+
slippage: number,
|
|
397
|
+
checkPrerequisites: boolean
|
|
398
|
+
): BestRouteRequest {
|
|
399
|
+
const selectedWalletsMap = selectedWallets.reduce(
|
|
400
|
+
(
|
|
401
|
+
selectedWalletsMap: BestRouteRequest['selectedWallets'],
|
|
402
|
+
selectedWallet
|
|
403
|
+
) => (
|
|
404
|
+
(selectedWalletsMap[selectedWallet.chain] = selectedWallet.address),
|
|
405
|
+
selectedWalletsMap
|
|
406
|
+
),
|
|
407
|
+
{}
|
|
408
|
+
);
|
|
409
|
+
|
|
410
|
+
const connectedWallets: BestRouteRequest['connectedWallets'] = [];
|
|
411
|
+
|
|
412
|
+
wallets.forEach((wallet) => {
|
|
413
|
+
const chainAndAccounts = connectedWallets.find(
|
|
414
|
+
(connectedWallet) => connectedWallet.blockchain === wallet.chain
|
|
415
|
+
);
|
|
416
|
+
if (!!chainAndAccounts) chainAndAccounts.addresses.push(wallet.address);
|
|
417
|
+
else
|
|
418
|
+
connectedWallets.push({
|
|
419
|
+
blockchain: wallet.chain,
|
|
420
|
+
addresses: [wallet.address],
|
|
421
|
+
});
|
|
153
422
|
});
|
|
423
|
+
|
|
424
|
+
const requestBody: BestRouteRequest = {
|
|
425
|
+
amount: inputAmount.toString(),
|
|
426
|
+
checkPrerequisites,
|
|
427
|
+
from: {
|
|
428
|
+
address: fromToken.address,
|
|
429
|
+
blockchain: fromToken.blockchain,
|
|
430
|
+
symbol: fromToken.symbol,
|
|
431
|
+
},
|
|
432
|
+
to: {
|
|
433
|
+
address: toToken.address,
|
|
434
|
+
blockchain: toToken.blockchain,
|
|
435
|
+
symbol: toToken.symbol,
|
|
436
|
+
},
|
|
437
|
+
connectedWallets,
|
|
438
|
+
selectedWallets: selectedWalletsMap,
|
|
439
|
+
swapperGroups: disabledLiquiditySources,
|
|
440
|
+
swappersGroupsExclude: true,
|
|
441
|
+
//@ts-ignore
|
|
442
|
+
slippage: slippage.toString(),
|
|
443
|
+
};
|
|
444
|
+
|
|
445
|
+
return requestBody;
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
export function getWalletsForNewSwap(selectedWallets: SelectedWallet[]) {
|
|
449
|
+
const wallets = selectedWallets.reduce(
|
|
450
|
+
(
|
|
451
|
+
selectedWalletsMap: {
|
|
452
|
+
[p: string]: { address: string; walletType: WalletType };
|
|
453
|
+
},
|
|
454
|
+
selectedWallet
|
|
455
|
+
) => (
|
|
456
|
+
(selectedWalletsMap[selectedWallet.chain] = {
|
|
457
|
+
address: selectedWallet.address,
|
|
458
|
+
walletType: selectedWallet.walletType,
|
|
459
|
+
}),
|
|
460
|
+
selectedWalletsMap
|
|
461
|
+
),
|
|
462
|
+
{}
|
|
463
|
+
);
|
|
464
|
+
|
|
154
465
|
return wallets;
|
|
155
466
|
}
|
|
467
|
+
|
|
468
|
+
export function getRouteOutputAmount(route: BestRouteResponse) {
|
|
469
|
+
return route.result?.outputAmount || null;
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
export function getPercentageChange(
|
|
473
|
+
oldValue: string | number,
|
|
474
|
+
newValue: string | number
|
|
475
|
+
) {
|
|
476
|
+
return new BigNumber(newValue)
|
|
477
|
+
.div(new BigNumber(oldValue))
|
|
478
|
+
.minus(1)
|
|
479
|
+
.multipliedBy(100);
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
export function isOutputAmountChangedALot(
|
|
483
|
+
oldRoute: BestRouteResponse,
|
|
484
|
+
newRoute: BestRouteResponse
|
|
485
|
+
) {
|
|
486
|
+
const oldOutputAmount = getRouteOutputAmount(oldRoute);
|
|
487
|
+
const newOutputAmount = getRouteOutputAmount(newRoute);
|
|
488
|
+
if (!oldOutputAmount || !newOutputAmount) return false;
|
|
489
|
+
const percentageChange = getPercentageChange(
|
|
490
|
+
oldOutputAmount,
|
|
491
|
+
newOutputAmount
|
|
492
|
+
);
|
|
493
|
+
|
|
494
|
+
return percentageChange.toNumber() <= -1;
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
export function getBalanceWarnings(
|
|
498
|
+
route: BestRouteResponse,
|
|
499
|
+
selectedWallets: SelectedWallet[]
|
|
500
|
+
) {
|
|
501
|
+
const fee = route.validationStatus;
|
|
502
|
+
const requiredWallets = getRequiredChains(route);
|
|
503
|
+
const walletsSortedByRequiredWallets = selectedWallets.sort(
|
|
504
|
+
(selectedWallet1, selectedWallet2) =>
|
|
505
|
+
requiredWallets.indexOf(selectedWallet1.chain) -
|
|
506
|
+
requiredWallets.indexOf(selectedWallet2.chain)
|
|
507
|
+
);
|
|
508
|
+
return walletsSortedByRequiredWallets
|
|
509
|
+
.flatMap((wallet) => getRequiredBalanceOfWallet(wallet, fee) || [])
|
|
510
|
+
.filter((asset) => !asset.ok)
|
|
511
|
+
.map((asset) => {
|
|
512
|
+
const symbol = asset.asset.symbol;
|
|
513
|
+
const currentAmount = numberToString(
|
|
514
|
+
new BigNumber(asset.currentAmount.amount).shiftedBy(
|
|
515
|
+
-asset.currentAmount.decimals
|
|
516
|
+
),
|
|
517
|
+
8
|
|
518
|
+
);
|
|
519
|
+
const requiredAmount = numberToString(
|
|
520
|
+
new BigNumber(asset.requiredAmount.amount).shiftedBy(
|
|
521
|
+
-asset.requiredAmount.decimals
|
|
522
|
+
),
|
|
523
|
+
8
|
|
524
|
+
);
|
|
525
|
+
let reason = '';
|
|
526
|
+
if (asset.reason === 'FEE') reason = ' for network fee';
|
|
527
|
+
if (asset.reason === 'INPUT_ASSET') reason = ' for swap';
|
|
528
|
+
if (asset.reason === 'FEE_AND_INPUT_ASSET')
|
|
529
|
+
reason = ' for input and network fee';
|
|
530
|
+
const warningMessage = `Needs ≈ ${requiredAmount} ${symbol}${reason}, but you have ${currentAmount} ${symbol} in your ${asset.asset.blockchain} wallet.`;
|
|
531
|
+
return warningMessage;
|
|
532
|
+
});
|
|
533
|
+
}
|
package/src/utils/wallets.ts
CHANGED
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
import {
|
|
13
13
|
WalletInfo as ModalWalletInfo,
|
|
14
14
|
WalletState as WalletStatus,
|
|
15
|
+
SelectableWallet,
|
|
15
16
|
} from '@rango-dev/ui';
|
|
16
17
|
import {
|
|
17
18
|
BestRouteResponse,
|
|
@@ -20,7 +21,6 @@ import {
|
|
|
20
21
|
WalletDetail,
|
|
21
22
|
} from 'rango-sdk';
|
|
22
23
|
import { readAccountAddress } from '@rango-dev/wallets-core';
|
|
23
|
-
import { SelectableWallet } from '../pages/ConfirmWalletsPage';
|
|
24
24
|
import { Account, Balance, TokenBalance } from '../store/wallets';
|
|
25
25
|
import { numberToString } from './numbers';
|
|
26
26
|
import BigNumber from 'bignumber.js';
|
|
@@ -170,9 +170,8 @@ type Blockchain = { name: string; accounts: Balance[] };
|
|
|
170
170
|
export function getSelectableWallets(
|
|
171
171
|
accounts: Account[],
|
|
172
172
|
selectedWallets: SelectedWallet[],
|
|
173
|
-
getWalletInfo: (type: WalletType) => WalletInfo
|
|
174
|
-
|
|
175
|
-
) {
|
|
173
|
+
getWalletInfo: (type: WalletType) => WalletInfo
|
|
174
|
+
): SelectableWallet[] {
|
|
176
175
|
const connectedWallets: SelectableWallet[] = accounts.map((account) => ({
|
|
177
176
|
address: account.address,
|
|
178
177
|
walletType: account.walletType,
|
|
@@ -186,23 +185,9 @@ export function getSelectableWallets(
|
|
|
186
185
|
),
|
|
187
186
|
}));
|
|
188
187
|
|
|
189
|
-
return
|
|
190
|
-
? connectedWallets.filter(
|
|
191
|
-
(wallet, index, array) =>
|
|
192
|
-
requiredChains.includes(wallet.chain) &&
|
|
193
|
-
array.findIndex((w) => w.address === wallet.address) === index
|
|
194
|
-
)
|
|
195
|
-
: removeDuplicateWallets(connectedWallets, 'walletType');
|
|
188
|
+
return connectedWallets;
|
|
196
189
|
}
|
|
197
190
|
|
|
198
|
-
const removeDuplicateWallets = (
|
|
199
|
-
arr: SelectableWallet[],
|
|
200
|
-
key: string
|
|
201
|
-
): SelectableWallet[] => {
|
|
202
|
-
const map = new Map(arr.map((item) => [item[key], item]));
|
|
203
|
-
return Array.from(map.values());
|
|
204
|
-
};
|
|
205
|
-
|
|
206
191
|
export function getBalanceFromWallet(
|
|
207
192
|
balances: Balance[],
|
|
208
193
|
chain: string,
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"useBestRoute.d.ts","sourceRoot":"","sources":["../src/hooks/useBestRoute.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoB,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAMhE,wBAAgB,YAAY;;;;;EA+D3B"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"useConfirmSwap.d.ts","sourceRoot":"","sources":["../src/hooks/useConfirmSwap.ts"],"names":[],"mappings":"AA2BA,wBAAgB,cAAc,QAgP7B"}
|