@rango-dev/widget-embedded 0.1.10-next.69
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/CHANGELOG.md +12 -0
- package/package.json +29 -0
- package/public/index.html +11 -0
- package/readme.md +2 -0
- package/src/App.tsx +78 -0
- package/src/app.css +28 -0
- package/src/components/AppRouter.tsx +15 -0
- package/src/components/AppRoutes.tsx +32 -0
- package/src/components/BottomLogo.tsx +44 -0
- package/src/components/Footer.tsx +8 -0
- package/src/components/Header.tsx +25 -0
- package/src/components/HeaderButtons.tsx +34 -0
- package/src/components/Layout.tsx +55 -0
- package/src/components/SwitchFromAndTo.tsx +30 -0
- package/src/components/TokenInfo.tsx +218 -0
- package/src/components/UpdateUrl.tsx +85 -0
- package/src/constants/errors.ts +3 -0
- package/src/constants/navigationRoutes.ts +14 -0
- package/src/constants/numbers.ts +3 -0
- package/src/constants/searchParams.ts +7 -0
- package/src/globalStyles.ts +16 -0
- package/src/hooks/useBestRoute.ts +70 -0
- package/src/hooks/useConfirmSwap.ts +234 -0
- package/src/hooks/useTheme.ts +37 -0
- package/src/index.tsx +12 -0
- package/src/mockData/pendingSwap.ts +607 -0
- package/src/pages/ConfirmSwapPage.tsx +24 -0
- package/src/pages/ConfirmWalletsPage.tsx +51 -0
- package/src/pages/HistoryPage.tsx +793 -0
- package/src/pages/Home.tsx +176 -0
- package/src/pages/LiquiditySourcesPage.tsx +49 -0
- package/src/pages/SelectChainPage.tsx +62 -0
- package/src/pages/SelectTokenPage.tsx +84 -0
- package/src/pages/SettingsPage.tsx +60 -0
- package/src/pages/SwapDetailsPage.tsx +9 -0
- package/src/pages/WalletsPage.tsx +61 -0
- package/src/services/httpService.ts +3 -0
- package/src/store/bestRoute.ts +82 -0
- package/src/store/meta.ts +35 -0
- package/src/store/selectors.ts +19 -0
- package/src/store/settings.ts +72 -0
- package/src/store/wallets.ts +144 -0
- package/src/utils/common.ts +3 -0
- package/src/utils/numbers.ts +94 -0
- package/src/utils/routing.ts +108 -0
- package/src/utils/swap.ts +155 -0
- package/src/utils/wallets.ts +345 -0
|
@@ -0,0 +1,345 @@
|
|
|
1
|
+
import {
|
|
2
|
+
isEvmAddress,
|
|
3
|
+
Network,
|
|
4
|
+
WalletInfo,
|
|
5
|
+
WalletState,
|
|
6
|
+
WalletType,
|
|
7
|
+
} from '@rango-dev/wallets-shared';
|
|
8
|
+
|
|
9
|
+
import { WalletInfo as ModalWalletInfo, WalletState as WalletStatus } from '@rango-dev/ui';
|
|
10
|
+
import { BestRouteResponse, BlockchainMeta, Token, WalletDetail } from 'rango-sdk';
|
|
11
|
+
import { readAccountAddress } from '@rango-dev/wallets-core';
|
|
12
|
+
import { SelectableWallet } from '../pages/ConfirmWalletsPage';
|
|
13
|
+
import { Account, Balance, TokenBalance } from '../store/wallets';
|
|
14
|
+
import { numberToString } from './numbers';
|
|
15
|
+
import BigNumber from 'bignumber.js';
|
|
16
|
+
import { TokenWithBalance } from '../pages/SelectTokenPage';
|
|
17
|
+
import { ZERO } from '../constants/numbers';
|
|
18
|
+
|
|
19
|
+
export function getStateWallet(state: WalletState): WalletStatus {
|
|
20
|
+
switch (true) {
|
|
21
|
+
case state.connected:
|
|
22
|
+
return WalletStatus.CONNECTED;
|
|
23
|
+
case state.connecting:
|
|
24
|
+
return WalletStatus.CONNECTING;
|
|
25
|
+
case !state.installed:
|
|
26
|
+
return WalletStatus.NOT_INSTALLED;
|
|
27
|
+
default:
|
|
28
|
+
return WalletStatus.DISCONNECTED;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function getlistWallet(
|
|
33
|
+
getState: (type: WalletType) => WalletState,
|
|
34
|
+
getWalletInfo: (type: WalletType) => WalletInfo,
|
|
35
|
+
list: WalletType[],
|
|
36
|
+
): ModalWalletInfo[] {
|
|
37
|
+
const excludedWallets = [WalletType.UNKNOWN, WalletType.TERRA_STATION, WalletType.LEAP];
|
|
38
|
+
|
|
39
|
+
return list
|
|
40
|
+
.filter((wallet) => !excludedWallets.includes(wallet))
|
|
41
|
+
.map((type) => {
|
|
42
|
+
const { name, img: image, installLink } = getWalletInfo(type);
|
|
43
|
+
const state = getStateWallet(getState(type));
|
|
44
|
+
return {
|
|
45
|
+
name,
|
|
46
|
+
image,
|
|
47
|
+
installLink,
|
|
48
|
+
state,
|
|
49
|
+
type,
|
|
50
|
+
};
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function walletAndSupportedChainsNames(supportedChains: BlockchainMeta[]): Network[] | null {
|
|
55
|
+
if (!supportedChains) return null;
|
|
56
|
+
let walletAndSupportedChainsNames: Network[] = [];
|
|
57
|
+
walletAndSupportedChainsNames = supportedChains.map(
|
|
58
|
+
(blockchainMeta) => blockchainMeta.name as Network,
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
return walletAndSupportedChainsNames;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function prepareAccountsForWalletStore(
|
|
65
|
+
wallet: WalletType,
|
|
66
|
+
accounts: string[],
|
|
67
|
+
evmBasedChains: string[],
|
|
68
|
+
supportedChainNames: Network[] | null,
|
|
69
|
+
): Account[] {
|
|
70
|
+
const result: Account[] = [];
|
|
71
|
+
|
|
72
|
+
function addAccount(network: Network, address: string) {
|
|
73
|
+
const newAccount: Account = {
|
|
74
|
+
address,
|
|
75
|
+
chain: network,
|
|
76
|
+
walletType: wallet,
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
result.push(newAccount);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const supportedChains = supportedChainNames || [];
|
|
83
|
+
|
|
84
|
+
accounts.forEach((account) => {
|
|
85
|
+
const { address, network } = readAccountAddress(account);
|
|
86
|
+
|
|
87
|
+
const hasLimitation = supportedChains.length > 0;
|
|
88
|
+
const isSupported = supportedChains.includes(network);
|
|
89
|
+
const isUnknown = network === Network.Unknown;
|
|
90
|
+
const notSupportedNetworkByWallet = hasLimitation && !isSupported && !isUnknown;
|
|
91
|
+
|
|
92
|
+
// Here we check given `network` is not supported by wallet
|
|
93
|
+
// And also the network is known.
|
|
94
|
+
if (notSupportedNetworkByWallet) return;
|
|
95
|
+
|
|
96
|
+
// In some cases we can handle unknown network by checking its address
|
|
97
|
+
// pattern and act on it.
|
|
98
|
+
// Example: showing our evm compatible netwrok when the uknown network is evem.
|
|
99
|
+
// Otherwise, we stop executing this function.
|
|
100
|
+
const isUknownAndEvmBased = network === Network.Unknown && isEvmAddress(address);
|
|
101
|
+
if (isUnknown && !isUknownAndEvmBased) return;
|
|
102
|
+
|
|
103
|
+
const isEvmBasedChain = evmBasedChains.includes(network);
|
|
104
|
+
|
|
105
|
+
// If it's an evm network, we will add the address to all the evm chains.
|
|
106
|
+
if (isEvmBasedChain || isUknownAndEvmBased) {
|
|
107
|
+
// all evm chains are not supported in wallets, so we are adding
|
|
108
|
+
// only to those that are supported by wallet.
|
|
109
|
+
const evmChainsSupportedByWallet = supportedChains.filter((chain) =>
|
|
110
|
+
evmBasedChains.includes(chain),
|
|
111
|
+
);
|
|
112
|
+
|
|
113
|
+
evmChainsSupportedByWallet.forEach((network) => {
|
|
114
|
+
// EVM addresses are not case sensetive.
|
|
115
|
+
// Some wallets like Binance-chain return some letters in uppercase which produces bugs in our wallet state.
|
|
116
|
+
addAccount(network, address.toLowerCase());
|
|
117
|
+
});
|
|
118
|
+
} else {
|
|
119
|
+
addAccount(network, address);
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
return result;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export function getRequiredChains(route: BestRouteResponse | null) {
|
|
127
|
+
const wallets: string[] = [];
|
|
128
|
+
|
|
129
|
+
route?.result?.swaps.forEach((swap) => {
|
|
130
|
+
const currentStepFromBlockchain = swap.from.blockchain;
|
|
131
|
+
const currentStepToBlockchain = swap.to.blockchain;
|
|
132
|
+
let lastAddedWallet = wallets[wallets.length - 1];
|
|
133
|
+
if (currentStepFromBlockchain != lastAddedWallet) wallets.push(currentStepFromBlockchain);
|
|
134
|
+
lastAddedWallet = wallets[wallets.length - 1];
|
|
135
|
+
if (currentStepToBlockchain != lastAddedWallet) wallets.push(currentStepToBlockchain);
|
|
136
|
+
});
|
|
137
|
+
return wallets;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export interface SelectedWallet extends Account {}
|
|
141
|
+
type Blockchain = { name: string; accounts: Balance[] };
|
|
142
|
+
|
|
143
|
+
export function getSelectableWallets(
|
|
144
|
+
accounts: Account[],
|
|
145
|
+
selectedWallets: SelectedWallet[],
|
|
146
|
+
getWalletInfo: (type: WalletType) => WalletInfo,
|
|
147
|
+
requiredChains?: string[],
|
|
148
|
+
) {
|
|
149
|
+
const connectedWallets: SelectableWallet[] = accounts.map((account) => ({
|
|
150
|
+
address: account.address,
|
|
151
|
+
walletType: account.walletType,
|
|
152
|
+
chain: account.chain,
|
|
153
|
+
image: getWalletInfo(account.walletType).img,
|
|
154
|
+
selected: !!selectedWallets.find((wallet) => wallet.chain === account.chain),
|
|
155
|
+
}));
|
|
156
|
+
|
|
157
|
+
return requiredChains
|
|
158
|
+
? connectedWallets.filter((wallet) => requiredChains.includes(wallet.chain))
|
|
159
|
+
: removeDuplicateWallets(connectedWallets, 'walletType');
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const removeDuplicateWallets = (arr: SelectableWallet[], key: string): SelectableWallet[] => {
|
|
163
|
+
return [...new Map(arr.map((item) => [item[key], item])).values()];
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
export function getBalanceFromWallet(
|
|
167
|
+
balances: Balance[],
|
|
168
|
+
chain: string,
|
|
169
|
+
symbol: string,
|
|
170
|
+
address: string | null,
|
|
171
|
+
): TokenBalance | null {
|
|
172
|
+
if (balances.length === 0) return null;
|
|
173
|
+
|
|
174
|
+
const selectedChainBalances = balances.filter((balance) => balance.chain === chain);
|
|
175
|
+
if (selectedChainBalances.length === 0) return null;
|
|
176
|
+
|
|
177
|
+
return (
|
|
178
|
+
selectedChainBalances
|
|
179
|
+
.map(
|
|
180
|
+
(a) =>
|
|
181
|
+
a.balances?.find(
|
|
182
|
+
(bl) =>
|
|
183
|
+
(address !== null && bl.address === address) ||
|
|
184
|
+
(address === null && bl.address === address && bl.symbol === symbol),
|
|
185
|
+
) || null,
|
|
186
|
+
)
|
|
187
|
+
.filter((b) => b !== null)
|
|
188
|
+
.sort((a, b) => parseFloat(b?.amount || '0') - parseFloat(a?.amount || '1'))
|
|
189
|
+
.find(() => true) || null
|
|
190
|
+
);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
export function isAccountAndBalanceMatched(account: Account, balance: Balance) {
|
|
194
|
+
return (
|
|
195
|
+
account.address === balance.address &&
|
|
196
|
+
account.chain === balance.chain &&
|
|
197
|
+
account.walletType === balance.walletType
|
|
198
|
+
);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
export function makeBalanceFor(
|
|
202
|
+
account: Account,
|
|
203
|
+
retrivedBalance: WalletDetail,
|
|
204
|
+
tokens: Token[],
|
|
205
|
+
): Balance {
|
|
206
|
+
const { address, blockChain: chain, explorerUrl, balances = [] } = retrivedBalance;
|
|
207
|
+
return {
|
|
208
|
+
address,
|
|
209
|
+
chain,
|
|
210
|
+
loading: false,
|
|
211
|
+
error: false,
|
|
212
|
+
explorerUrl,
|
|
213
|
+
walletType: account.walletType,
|
|
214
|
+
balances:
|
|
215
|
+
balances?.map((tokenBalance) => ({
|
|
216
|
+
chain,
|
|
217
|
+
symbol: tokenBalance.asset.symbol,
|
|
218
|
+
ticker: tokenBalance.asset.symbol,
|
|
219
|
+
address: tokenBalance.asset.address || null,
|
|
220
|
+
rawAmount: tokenBalance.amount.amount,
|
|
221
|
+
decimal: tokenBalance.amount.decimals,
|
|
222
|
+
amount: new BigNumber(tokenBalance.amount.amount)
|
|
223
|
+
.shiftedBy(-tokenBalance.amount.decimals)
|
|
224
|
+
.toFixed(),
|
|
225
|
+
logo: '',
|
|
226
|
+
usdPrice:
|
|
227
|
+
getUsdPrice(chain, tokenBalance.asset.symbol, tokenBalance.asset.address, tokens) || null,
|
|
228
|
+
})) || [],
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
export function resetBalanceState(balance: Balance): Balance {
|
|
233
|
+
return { ...balance, loading: false, error: true };
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
export const calculateWalletUsdValue = (balance: Balance[]) => {
|
|
237
|
+
const uniqueAccountAddresses = new Set<string | null>();
|
|
238
|
+
const uniqueBalane: Balance[] = balance?.reduce((acc: Balance[], current: Balance) => {
|
|
239
|
+
return acc.findIndex((i) => i.address === current.address && i.chain === current.chain) === -1
|
|
240
|
+
? [...acc, current]
|
|
241
|
+
: acc;
|
|
242
|
+
}, []);
|
|
243
|
+
|
|
244
|
+
const modifiedWalletBlockchains = uniqueBalane?.map((chain) => {
|
|
245
|
+
const modifiedWalletBlockchain: Blockchain = { name: chain.chain, accounts: [] };
|
|
246
|
+
if (!uniqueAccountAddresses.has(chain.address)) {
|
|
247
|
+
uniqueAccountAddresses.add(chain.address);
|
|
248
|
+
}
|
|
249
|
+
uniqueAccountAddresses.forEach((accountAddress) => {
|
|
250
|
+
if (chain.address === accountAddress) modifiedWalletBlockchain.accounts.push(chain);
|
|
251
|
+
});
|
|
252
|
+
return modifiedWalletBlockchain;
|
|
253
|
+
});
|
|
254
|
+
const total = numberToString(
|
|
255
|
+
modifiedWalletBlockchains
|
|
256
|
+
?.flatMap((b) => b.accounts)
|
|
257
|
+
?.flatMap((a) => a?.balances)
|
|
258
|
+
?.map((b) => new BigNumber(b?.amount || ZERO).multipliedBy(b?.usdPrice || 0))
|
|
259
|
+
?.reduce((a, b) => a.plus(b), ZERO) || ZERO,
|
|
260
|
+
).toString();
|
|
261
|
+
|
|
262
|
+
console.log('total');
|
|
263
|
+
console.log(total);
|
|
264
|
+
|
|
265
|
+
return numberWithThousandSeperator(total);
|
|
266
|
+
};
|
|
267
|
+
|
|
268
|
+
function numberWithThousandSeperator(number: string | number): string {
|
|
269
|
+
var parts = number.toString().split('.');
|
|
270
|
+
parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ',');
|
|
271
|
+
return parts.join('.');
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
export const sortedTokens = (
|
|
275
|
+
tokens: TokenWithBalance[],
|
|
276
|
+
position: 'from' | 'to',
|
|
277
|
+
balance: Balance[],
|
|
278
|
+
): TokenWithBalance[] => {
|
|
279
|
+
if (!tokens) return [];
|
|
280
|
+
const walletSymbols = new Set(
|
|
281
|
+
(balance || [])
|
|
282
|
+
.flatMap((a) => a.balances || [])
|
|
283
|
+
.filter((b) => (new BigNumber(b?.rawAmount) || ZERO).gt(0))
|
|
284
|
+
.map((b) => `${b?.chain}.${b?.symbol}.${b?.address}`),
|
|
285
|
+
);
|
|
286
|
+
let sortedList = [
|
|
287
|
+
...tokens.filter((t) => !t.address && walletSymbols.size && position === 'to'),
|
|
288
|
+
...tokens
|
|
289
|
+
.filter(
|
|
290
|
+
(t) =>
|
|
291
|
+
!(position === 'to' && !t.address) &&
|
|
292
|
+
walletSymbols.has(`${t.blockchain}.${t.symbol}.${t.address}`),
|
|
293
|
+
)
|
|
294
|
+
.sort((tokenA, tokenB) => compareBalance(tokenA, tokenB, balance)),
|
|
295
|
+
...tokens.filter(
|
|
296
|
+
(t) =>
|
|
297
|
+
!walletSymbols.has(`${t.blockchain}.${t.symbol}.${t.address}`) &&
|
|
298
|
+
!t.address &&
|
|
299
|
+
(!walletSymbols.size || position === 'from'),
|
|
300
|
+
),
|
|
301
|
+
...tokens.filter(
|
|
302
|
+
(t) =>
|
|
303
|
+
!walletSymbols.has(`${t.blockchain}.${t.symbol}.${t.address}`) &&
|
|
304
|
+
t.address &&
|
|
305
|
+
!t.isSecondaryCoin,
|
|
306
|
+
),
|
|
307
|
+
...tokens.filter(
|
|
308
|
+
(t) => !walletSymbols.has(`${t.blockchain}.${t.symbol}.${t.address}`) && t.isSecondaryCoin,
|
|
309
|
+
),
|
|
310
|
+
];
|
|
311
|
+
|
|
312
|
+
return sortedList;
|
|
313
|
+
};
|
|
314
|
+
|
|
315
|
+
const compareBalance = (
|
|
316
|
+
tokenA: TokenWithBalance,
|
|
317
|
+
tokenB: TokenWithBalance,
|
|
318
|
+
wallet: Balance[],
|
|
319
|
+
): number => {
|
|
320
|
+
if (!tokenA.usdPrice || !tokenB.usdPrice) return 0;
|
|
321
|
+
|
|
322
|
+
const tokenAUsdValue = new BigNumber(
|
|
323
|
+
getBalanceFromWallet(wallet, tokenA.blockchain, tokenA.symbol, tokenA.address)?.amount || ZERO,
|
|
324
|
+
).multipliedBy(tokenA.usdPrice);
|
|
325
|
+
const tokenBUsdValue = new BigNumber(
|
|
326
|
+
getBalanceFromWallet(wallet, tokenB.blockchain, tokenB.symbol, tokenB.address)?.amount || ZERO,
|
|
327
|
+
).multipliedBy(tokenB.usdPrice);
|
|
328
|
+
if (tokenAUsdValue.gt(tokenBUsdValue)) return -1;
|
|
329
|
+
return 1;
|
|
330
|
+
};
|
|
331
|
+
|
|
332
|
+
export const getUsdPrice = (
|
|
333
|
+
blockchain: string,
|
|
334
|
+
symbol: string,
|
|
335
|
+
address: string | null,
|
|
336
|
+
allTokens: Token[],
|
|
337
|
+
): number | null => {
|
|
338
|
+
const token = allTokens?.find(
|
|
339
|
+
(t) =>
|
|
340
|
+
t.blockchain === blockchain &&
|
|
341
|
+
t.symbol?.toUpperCase() === symbol?.toUpperCase() &&
|
|
342
|
+
t.address === address,
|
|
343
|
+
);
|
|
344
|
+
return token?.usdPrice || null;
|
|
345
|
+
};
|