@rango-dev/widget-embedded 0.40.2-next.1 → 0.40.2-next.11
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/CustomTokenModal/CustomTokenModal.constants.d.ts +2 -0
- package/dist/components/CustomTokenModal/CustomTokenModal.constants.d.ts.map +1 -0
- package/dist/components/CustomTokenModal/CustomTokenModal.d.ts.map +1 -1
- package/dist/components/CustomTokenModal/CustomTokenModal.types.d.ts +1 -0
- package/dist/components/CustomTokenModal/CustomTokenModal.types.d.ts.map +1 -1
- package/dist/components/ImportCustomToken/ImportCustomToken.d.ts +4 -0
- package/dist/components/ImportCustomToken/ImportCustomToken.d.ts.map +1 -0
- package/dist/components/ImportCustomToken/ImportCustomToken.types.d.ts +15 -0
- package/dist/components/ImportCustomToken/ImportCustomToken.types.d.ts.map +1 -0
- package/dist/components/ImportCustomToken/index.d.ts +2 -0
- package/dist/components/ImportCustomToken/index.d.ts.map +1 -0
- package/dist/components/Layout/Layout.d.ts.map +1 -1
- package/dist/components/Layout/Layout.styles.d.ts +161 -0
- package/dist/components/Layout/Layout.styles.d.ts.map +1 -1
- package/dist/components/Quote/Quote.styles.d.ts +2 -2
- package/dist/components/SearchInput/SearchInput.d.ts.map +1 -1
- package/dist/components/SearchInput/SearchInput.types.d.ts +4 -2
- package/dist/components/SearchInput/SearchInput.types.d.ts.map +1 -1
- package/dist/components/SwapDetailsModal/SwapDetailsModal.types.d.ts +2 -2
- package/dist/components/SwapDetailsModal/SwapDetailsModal.types.d.ts.map +1 -1
- package/dist/components/TokenList/TokenList.d.ts.map +1 -1
- package/dist/components/TokenList/TokenList.styles.d.ts +323 -1
- package/dist/components/TokenList/TokenList.styles.d.ts.map +1 -1
- package/dist/components/TokenList/TokenList.types.d.ts +6 -1
- package/dist/components/TokenList/TokenList.types.d.ts.map +1 -1
- package/dist/constants/customTokens.d.ts +1 -0
- package/dist/constants/customTokens.d.ts.map +1 -1
- package/dist/containers/Inputs/Inputs.d.ts.map +1 -1
- package/dist/hooks/useFetchCustomToken.d.ts +8 -4
- package/dist/hooks/useFetchCustomToken.d.ts.map +1 -1
- package/dist/hooks/usePrepareBlockchainList/usePrepareBlockchainList.helpers.d.ts +2 -2
- package/dist/hooks/useSearchCustomTokens/index.d.ts +2 -0
- package/dist/hooks/useSearchCustomTokens/index.d.ts.map +1 -0
- package/dist/hooks/useSearchCustomTokens/types.d.ts +9 -0
- package/dist/hooks/useSearchCustomTokens/types.d.ts.map +1 -0
- package/dist/hooks/useSearchCustomTokens/useSearchCustomTokens.constants.d.ts +2 -0
- package/dist/hooks/useSearchCustomTokens/useSearchCustomTokens.constants.d.ts.map +1 -0
- package/dist/hooks/useSearchCustomTokens/useSearchCustomTokens.d.ts +3 -0
- package/dist/hooks/useSearchCustomTokens/useSearchCustomTokens.d.ts.map +1 -0
- package/dist/hooks/useSwapInput.d.ts.map +1 -1
- package/dist/hooks/useSyncStoresWithConfig.d.ts.map +1 -1
- package/dist/hooks/useSyncUrlAndStore/useSyncUrlAndStore.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +4 -4
- package/dist/pages/AddCustomTokenPage.d.ts.map +1 -1
- package/dist/pages/CustomTokensPage.d.ts.map +1 -1
- package/dist/pages/SelectSwapItemPage/SelectSwapItemPage.constants.d.ts +3 -0
- package/dist/pages/SelectSwapItemPage/SelectSwapItemPage.constants.d.ts.map +1 -0
- package/dist/pages/SelectSwapItemPage/SelectSwapItemPage.helpers.d.ts +4 -0
- package/dist/pages/SelectSwapItemPage/SelectSwapItemPage.helpers.d.ts.map +1 -0
- package/dist/pages/SelectSwapItemPage/SelectSwapItemsPage.d.ts.map +1 -0
- package/dist/pages/SelectSwapItemPage/index.d.ts +2 -0
- package/dist/pages/SelectSwapItemPage/index.d.ts.map +1 -0
- package/dist/store/app.d.ts +1 -1
- package/dist/store/app.d.ts.map +1 -1
- package/dist/store/quote.d.ts +9 -6
- package/dist/store/quote.d.ts.map +1 -1
- package/dist/store/slices/settings.d.ts +4 -2
- package/dist/store/slices/settings.d.ts.map +1 -1
- package/dist/store/slices/wallets.d.ts +5 -1
- package/dist/store/slices/wallets.d.ts.map +1 -1
- package/dist/store/utils/wallets.d.ts +2 -1
- package/dist/store/utils/wallets.d.ts.map +1 -1
- package/dist/types/config.d.ts +5 -0
- package/dist/types/config.d.ts.map +1 -1
- package/dist/types/wallets.d.ts +1 -0
- package/dist/types/wallets.d.ts.map +1 -1
- package/dist/utils/quote.d.ts +1 -1
- package/dist/utils/quote.d.ts.map +1 -1
- package/dist/utils/settings.d.ts +1 -1
- package/dist/utils/swap.d.ts +1 -0
- package/dist/utils/swap.d.ts.map +1 -1
- package/dist/utils/wallets.d.ts.map +1 -1
- package/dist/widget-embedded.build.json +1 -1
- package/package.json +12 -12
- package/src/components/AppRoutes.tsx +1 -1
- package/src/components/CustomTokenModal/CustomTokenModal.constants.ts +2 -0
- package/src/components/CustomTokenModal/CustomTokenModal.tsx +26 -5
- package/src/components/CustomTokenModal/CustomTokenModal.types.ts +1 -0
- package/src/components/ImportCustomToken/ImportCustomToken.tsx +121 -0
- package/src/components/ImportCustomToken/ImportCustomToken.types.ts +18 -0
- package/src/components/ImportCustomToken/index.ts +1 -0
- package/src/components/Layout/Layout.styles.ts +12 -0
- package/src/components/Layout/Layout.tsx +37 -5
- package/src/components/NotificationContent/NotificationContent.tsx +2 -2
- package/src/components/Quote/QuoteTrigger.tsx +5 -5
- package/src/components/QuoteSkeleton/QuoteSummarySkeleton.tsx +2 -2
- package/src/components/QuoteSkeleton/StepSkeleton.tsx +2 -2
- package/src/components/SearchInput/SearchInput.tsx +13 -10
- package/src/components/SearchInput/SearchInput.types.ts +4 -2
- package/src/components/SwapDetailsModal/SwapDetailsModal.types.ts +2 -2
- package/src/components/TokenList/TokenList.styles.ts +40 -0
- package/src/components/TokenList/TokenList.tsx +134 -22
- package/src/components/TokenList/TokenList.types.ts +5 -1
- package/src/constants/customTokens.ts +3 -0
- package/src/containers/Inputs/Inputs.tsx +6 -4
- package/src/hooks/useFetchCustomToken.ts +39 -16
- package/src/hooks/useSearchCustomTokens/index.ts +1 -0
- package/src/hooks/useSearchCustomTokens/types.ts +9 -0
- package/src/hooks/useSearchCustomTokens/useSearchCustomTokens.constants.ts +1 -0
- package/src/hooks/useSearchCustomTokens/useSearchCustomTokens.ts +81 -0
- package/src/hooks/useSwapInput.ts +9 -2
- package/src/hooks/useSyncStoresWithConfig.ts +2 -3
- package/src/hooks/useSyncUrlAndStore/useSyncUrlAndStore.ts +1 -3
- package/src/pages/AddCustomTokenPage.tsx +24 -94
- package/src/pages/CustomTokensPage.tsx +1 -0
- package/src/pages/SelectSwapItemPage/SelectSwapItemPage.constants.ts +2 -0
- package/src/pages/SelectSwapItemPage/SelectSwapItemPage.helpers.ts +51 -0
- package/src/pages/{SelectSwapItemsPage.tsx → SelectSwapItemPage/SelectSwapItemsPage.tsx} +54 -13
- package/src/pages/SelectSwapItemPage/index.ts +1 -0
- package/src/store/app.ts +12 -1
- package/src/store/quote.ts +6 -3
- package/src/store/slices/settings.ts +11 -4
- package/src/store/slices/wallets.ts +106 -2
- package/src/store/utils/wallets.ts +31 -2
- package/src/types/config.ts +5 -0
- package/src/types/wallets.ts +1 -0
- package/src/utils/quote.ts +1 -1
- package/src/utils/swap.ts +3 -0
- package/src/utils/wallets.ts +9 -2
- package/dist/pages/SelectSwapItemsPage.d.ts.map +0 -1
- /package/dist/pages/{SelectSwapItemsPage.d.ts → SelectSwapItemPage/SelectSwapItemsPage.d.ts} +0 -0
|
@@ -5,25 +5,21 @@ import {
|
|
|
5
5
|
darkTheme,
|
|
6
6
|
Divider,
|
|
7
7
|
DoneIcon,
|
|
8
|
-
MessageBox,
|
|
9
8
|
styled,
|
|
10
9
|
TextField,
|
|
11
10
|
Typography,
|
|
12
11
|
} from '@rango-dev/ui';
|
|
13
|
-
import {
|
|
14
|
-
import React, { useEffect, useState } from 'react';
|
|
12
|
+
import React, { useState } from 'react';
|
|
15
13
|
import { useNavigate, useSearchParams } from 'react-router-dom';
|
|
16
14
|
|
|
17
15
|
import { BlockchainSelectorButton } from '../components/BlockchainSelectorButton';
|
|
18
|
-
import {
|
|
19
|
-
import { CustomTokenModal } from '../components/CustomTokenModal';
|
|
16
|
+
import { ImportCustomToken } from '../components/ImportCustomToken';
|
|
20
17
|
import { Layout, PageContainer } from '../components/Layout';
|
|
21
18
|
import { navigationRoutes } from '../constants/navigationRoutes';
|
|
22
19
|
import { SearchParams } from '../constants/searchParams';
|
|
23
20
|
import { useFetchCustomToken } from '../hooks/useFetchCustomToken';
|
|
24
21
|
import { useNavigateBack } from '../hooks/useNavigateBack';
|
|
25
22
|
import { useAppStore } from '../store/AppStore';
|
|
26
|
-
import { getContainer } from '../utils/common';
|
|
27
23
|
import { findBlockchain, isValidTokenAddress } from '../utils/meta';
|
|
28
24
|
|
|
29
25
|
const Content = styled('div', {
|
|
@@ -41,68 +37,31 @@ const Content = styled('div', {
|
|
|
41
37
|
height: '$40',
|
|
42
38
|
},
|
|
43
39
|
});
|
|
44
|
-
const CUSTOM_TOKEN_REFRESH_DELAY = 1000;
|
|
45
40
|
|
|
46
41
|
export function AddCustomTokenPage() {
|
|
47
42
|
const navigate = useNavigate();
|
|
48
43
|
const [searchParams] = useSearchParams();
|
|
49
44
|
const navigateBack = useNavigateBack();
|
|
50
|
-
const { setCustomToken } = useAppStore();
|
|
51
45
|
const blockchains = useAppStore().blockchains();
|
|
52
46
|
|
|
53
47
|
const blockchainName = searchParams.get(SearchParams.BLOCKCHAIN) || '';
|
|
54
48
|
const blockchain = findBlockchain(blockchainName, blockchains);
|
|
55
49
|
const [address, setAddress] = useState('');
|
|
56
|
-
const
|
|
57
|
-
|
|
58
|
-
const { fetchCustomToken, loading, error } = useFetchCustomToken();
|
|
59
|
-
const [networkError, setNetworkError] = useState('');
|
|
50
|
+
const { fetchCustomToken, token, loading, error, resetState } =
|
|
51
|
+
useFetchCustomToken();
|
|
60
52
|
const isValidAddress =
|
|
61
53
|
!!blockchain && isValidTokenAddress(blockchain, address);
|
|
62
54
|
const isImportDisabled = !blockchain || !address || !isValidAddress;
|
|
63
55
|
|
|
64
|
-
const getCustomToken =
|
|
56
|
+
const getCustomToken = () => {
|
|
65
57
|
if (blockchain) {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
});
|
|
71
|
-
setNetworkError('');
|
|
72
|
-
if (!!res) {
|
|
73
|
-
setToken(res);
|
|
74
|
-
}
|
|
75
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
76
|
-
} catch (error: any) {
|
|
77
|
-
if (error.message === 'Failed to fetch') {
|
|
78
|
-
setNetworkError(i18n.t('Network Error'));
|
|
79
|
-
setIsOpenErrorModal(true);
|
|
80
|
-
}
|
|
81
|
-
}
|
|
58
|
+
void fetchCustomToken({
|
|
59
|
+
blockchain: blockchainName,
|
|
60
|
+
tokenAddress: address,
|
|
61
|
+
});
|
|
82
62
|
}
|
|
83
63
|
};
|
|
84
64
|
|
|
85
|
-
const closeErrorModal = () => {
|
|
86
|
-
if (!!error) {
|
|
87
|
-
setAddress('');
|
|
88
|
-
}
|
|
89
|
-
setIsOpenErrorModal(false);
|
|
90
|
-
};
|
|
91
|
-
|
|
92
|
-
const handleErrorModalButtonClick = async () => {
|
|
93
|
-
if (!!networkError) {
|
|
94
|
-
setTimeout(async () => {
|
|
95
|
-
await getCustomToken();
|
|
96
|
-
}, CUSTOM_TOKEN_REFRESH_DELAY);
|
|
97
|
-
}
|
|
98
|
-
closeErrorModal();
|
|
99
|
-
};
|
|
100
|
-
|
|
101
|
-
useEffect(() => {
|
|
102
|
-
if (!!error) {
|
|
103
|
-
setIsOpenErrorModal(true);
|
|
104
|
-
}
|
|
105
|
-
}, [error]);
|
|
106
65
|
return (
|
|
107
66
|
<Layout
|
|
108
67
|
header={{
|
|
@@ -164,50 +123,21 @@ export function AddCustomTokenPage() {
|
|
|
164
123
|
{i18n.t('Import')}
|
|
165
124
|
</Button>
|
|
166
125
|
</Content>
|
|
167
|
-
<
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
type
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
id={`widget-add-custom-token-${
|
|
183
|
-
networkError ? 'retry' : 'add-another'
|
|
184
|
-
}-btn`}
|
|
185
|
-
variant="contained"
|
|
186
|
-
size="large"
|
|
187
|
-
type="primary"
|
|
188
|
-
fullWidth
|
|
189
|
-
onClick={handleErrorModalButtonClick}>
|
|
190
|
-
{networkError
|
|
191
|
-
? i18n.t('Retry')
|
|
192
|
-
: i18n.t('Add another custom token')}
|
|
193
|
-
</Button>
|
|
194
|
-
</MessageBox>
|
|
195
|
-
</WatermarkedModal>
|
|
196
|
-
{blockchain && token && (
|
|
197
|
-
<CustomTokenModal
|
|
198
|
-
blockchain={blockchain}
|
|
199
|
-
token={token}
|
|
200
|
-
onSubmitClick={() => {
|
|
201
|
-
if (token) {
|
|
202
|
-
setCustomToken(token);
|
|
203
|
-
setToken(undefined);
|
|
204
|
-
navigateBack();
|
|
205
|
-
}
|
|
206
|
-
}}
|
|
207
|
-
onClose={() => setToken(undefined)}
|
|
208
|
-
open={!!blockchain && !!token}
|
|
209
|
-
/>
|
|
210
|
-
)}
|
|
126
|
+
<ImportCustomToken
|
|
127
|
+
token={token}
|
|
128
|
+
blockchain={blockchain ?? undefined}
|
|
129
|
+
address={address}
|
|
130
|
+
error={error ?? undefined}
|
|
131
|
+
fetchCustomToken={fetchCustomToken}
|
|
132
|
+
onCloseErrorModal={() => {
|
|
133
|
+
if (error?.type !== 'network-error') {
|
|
134
|
+
setAddress('');
|
|
135
|
+
}
|
|
136
|
+
}}
|
|
137
|
+
onImport={navigateBack}
|
|
138
|
+
onExitErrorModal={resetState}
|
|
139
|
+
onExitImportModal={resetState}
|
|
140
|
+
/>
|
|
211
141
|
</PageContainer>
|
|
212
142
|
</Layout>
|
|
213
143
|
);
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { TokenList } from '../../components/TokenList';
|
|
2
|
+
import type { Token } from 'rango-sdk';
|
|
3
|
+
import type { ComponentProps } from 'react';
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
MAX_TOKENS_BEFORE_FETCH,
|
|
7
|
+
MIN_SEARCH_LENGTH,
|
|
8
|
+
} from './SelectSwapItemPage.constants';
|
|
9
|
+
|
|
10
|
+
export function shouldSearchForCustomTokens(
|
|
11
|
+
metaSearchResultTokens: Token[],
|
|
12
|
+
query: string,
|
|
13
|
+
blockchain?: string
|
|
14
|
+
) {
|
|
15
|
+
if (
|
|
16
|
+
blockchain &&
|
|
17
|
+
metaSearchResultTokens.length === 1 &&
|
|
18
|
+
metaSearchResultTokens[0].address === query
|
|
19
|
+
) {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
return (
|
|
23
|
+
metaSearchResultTokens.length < MAX_TOKENS_BEFORE_FETCH &&
|
|
24
|
+
query.trim().length >= MIN_SEARCH_LENGTH
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function prepareTokensList(
|
|
29
|
+
tokens: Token[],
|
|
30
|
+
customTokens: Token[],
|
|
31
|
+
query: string,
|
|
32
|
+
loading: boolean,
|
|
33
|
+
blockchain?: string
|
|
34
|
+
) {
|
|
35
|
+
let modifiedList: ComponentProps<typeof TokenList>['list'] = [...tokens];
|
|
36
|
+
|
|
37
|
+
if (shouldSearchForCustomTokens(tokens, query, blockchain)) {
|
|
38
|
+
modifiedList = loading
|
|
39
|
+
? [...modifiedList, 'skeleton', 'skeleton', 'skeleton']
|
|
40
|
+
: [
|
|
41
|
+
...modifiedList,
|
|
42
|
+
...customTokens.map((customToken) => ({
|
|
43
|
+
...customToken,
|
|
44
|
+
customToken: true,
|
|
45
|
+
warning: true,
|
|
46
|
+
})),
|
|
47
|
+
];
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return modifiedList;
|
|
51
|
+
}
|
|
@@ -1,18 +1,24 @@
|
|
|
1
1
|
import type { BlockchainMeta, Token } from 'rango-sdk';
|
|
2
2
|
|
|
3
3
|
import { i18n } from '@lingui/core';
|
|
4
|
-
import { Divider } from '@rango-dev/ui';
|
|
5
|
-
import React, { useState } from 'react';
|
|
4
|
+
import { Divider, Spinner } from '@rango-dev/ui';
|
|
5
|
+
import React, { useEffect, useState } from 'react';
|
|
6
6
|
import { useNavigate } from 'react-router-dom';
|
|
7
7
|
|
|
8
|
-
import { BlockchainsSection } from '
|
|
9
|
-
import { Layout, PageContainer } from '
|
|
10
|
-
import { SearchInput } from '
|
|
11
|
-
import { TokenList } from '
|
|
12
|
-
import { navigationRoutes } from '
|
|
13
|
-
import { useNavigateBack } from '
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
8
|
+
import { BlockchainsSection } from '../../components/BlockchainsSection';
|
|
9
|
+
import { Layout, PageContainer } from '../../components/Layout';
|
|
10
|
+
import { SearchInput } from '../../components/SearchInput';
|
|
11
|
+
import { TokenList } from '../../components/TokenList';
|
|
12
|
+
import { navigationRoutes } from '../../constants/navigationRoutes';
|
|
13
|
+
import { useNavigateBack } from '../../hooks/useNavigateBack';
|
|
14
|
+
import { useSearchCustomTokens } from '../../hooks/useSearchCustomTokens';
|
|
15
|
+
import { useAppStore } from '../../store/AppStore';
|
|
16
|
+
import { useQuoteStore } from '../../store/quote';
|
|
17
|
+
|
|
18
|
+
import {
|
|
19
|
+
prepareTokensList,
|
|
20
|
+
shouldSearchForCustomTokens,
|
|
21
|
+
} from './SelectSwapItemPage.helpers';
|
|
16
22
|
|
|
17
23
|
interface PropTypes {
|
|
18
24
|
type: 'source' | 'destination';
|
|
@@ -31,6 +37,12 @@ export function SelectSwapItemsPage(props: PropTypes) {
|
|
|
31
37
|
setToBlockchain,
|
|
32
38
|
} = useQuoteStore();
|
|
33
39
|
const { getBalanceFor } = useAppStore();
|
|
40
|
+
const {
|
|
41
|
+
fetch,
|
|
42
|
+
loading,
|
|
43
|
+
tokens: customTokens,
|
|
44
|
+
cancel,
|
|
45
|
+
} = useSearchCustomTokens();
|
|
34
46
|
const [searchedFor, setSearchedFor] = useState<string>('');
|
|
35
47
|
|
|
36
48
|
const selectedBlockchain = type === 'source' ? fromBlockchain : toBlockchain;
|
|
@@ -47,6 +59,14 @@ export function SelectSwapItemsPage(props: PropTypes) {
|
|
|
47
59
|
getBalanceFor: getBalanceFor,
|
|
48
60
|
});
|
|
49
61
|
|
|
62
|
+
const modifiedTokens = prepareTokensList(
|
|
63
|
+
tokens,
|
|
64
|
+
customTokens,
|
|
65
|
+
searchedFor,
|
|
66
|
+
loading,
|
|
67
|
+
selectedBlockchain?.name
|
|
68
|
+
);
|
|
69
|
+
|
|
50
70
|
const updateBlockchain = (blockchain: BlockchainMeta) => {
|
|
51
71
|
if (type === 'source') {
|
|
52
72
|
setFromBlockchain(blockchain);
|
|
@@ -57,9 +77,9 @@ export function SelectSwapItemsPage(props: PropTypes) {
|
|
|
57
77
|
|
|
58
78
|
const updateToken = (token: Token) => {
|
|
59
79
|
if (type === 'source') {
|
|
60
|
-
setFromToken({ token, meta: { blockchains
|
|
80
|
+
setFromToken({ token, meta: { blockchains } });
|
|
61
81
|
} else {
|
|
62
|
-
setToToken({ token, meta: { blockchains
|
|
82
|
+
setToToken({ token, meta: { blockchains } });
|
|
63
83
|
}
|
|
64
84
|
};
|
|
65
85
|
const types = {
|
|
@@ -67,6 +87,18 @@ export function SelectSwapItemsPage(props: PropTypes) {
|
|
|
67
87
|
destination: i18n.t('Destination'),
|
|
68
88
|
};
|
|
69
89
|
|
|
90
|
+
useEffect(() => {
|
|
91
|
+
if (
|
|
92
|
+
shouldSearchForCustomTokens(tokens, searchedFor, selectedBlockchain?.name)
|
|
93
|
+
) {
|
|
94
|
+
fetch(searchedFor, selectedBlockchain?.name ?? undefined);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return () => {
|
|
98
|
+
cancel();
|
|
99
|
+
};
|
|
100
|
+
}, [tokens.length, searchedFor, selectedBlockchain?.name]);
|
|
101
|
+
|
|
70
102
|
return (
|
|
71
103
|
<Layout
|
|
72
104
|
header={{
|
|
@@ -92,10 +124,19 @@ export function SelectSwapItemsPage(props: PropTypes) {
|
|
|
92
124
|
size="large"
|
|
93
125
|
setValue={() => setSearchedFor('')}
|
|
94
126
|
onChange={(event) => setSearchedFor(event.target.value)}
|
|
127
|
+
suffix={
|
|
128
|
+
shouldSearchForCustomTokens(
|
|
129
|
+
tokens,
|
|
130
|
+
searchedFor,
|
|
131
|
+
selectedBlockchain?.name
|
|
132
|
+
) && loading ? (
|
|
133
|
+
<Spinner size={12} color="secondary" />
|
|
134
|
+
) : undefined
|
|
135
|
+
}
|
|
95
136
|
/>
|
|
96
137
|
<Divider size={16} />
|
|
97
138
|
<TokenList
|
|
98
|
-
list={
|
|
139
|
+
list={modifiedTokens}
|
|
99
140
|
selectedBlockchain={selectedBlockchainName}
|
|
100
141
|
searchedFor={searchedFor}
|
|
101
142
|
type={type}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { SelectSwapItemsPage } from './SelectSwapItemsPage';
|
package/src/store/app.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { AppStoreState } from './slices/types';
|
|
2
1
|
import type { WidgetConfig } from '../types';
|
|
2
|
+
import type { AppStoreState } from './slices/types';
|
|
3
3
|
import type { StateCreator } from 'zustand';
|
|
4
4
|
|
|
5
5
|
import { create } from 'zustand';
|
|
@@ -48,6 +48,17 @@ export function createAppStore(initialData?: WidgetConfig) {
|
|
|
48
48
|
disabledLiquiditySources: state.disabledLiquiditySources,
|
|
49
49
|
};
|
|
50
50
|
},
|
|
51
|
+
version: 1,
|
|
52
|
+
migrate: (persistedState, version) => {
|
|
53
|
+
const state = persistedState as AppStoreState;
|
|
54
|
+
if (version === 0) {
|
|
55
|
+
state._customTokens = state._customTokens.map((token) => ({
|
|
56
|
+
...token,
|
|
57
|
+
warning: true,
|
|
58
|
+
}));
|
|
59
|
+
}
|
|
60
|
+
return state;
|
|
61
|
+
},
|
|
51
62
|
}
|
|
52
63
|
)
|
|
53
64
|
);
|
package/src/store/quote.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { TokenData } from '../components/TokenList/TokenList.types';
|
|
1
2
|
import type {
|
|
2
3
|
BlockchainMeta,
|
|
3
4
|
MetaResponse,
|
|
@@ -35,7 +36,9 @@ export const getUsdValue = (
|
|
|
35
36
|
|
|
36
37
|
export type Meta = Pick<MetaResponse, 'blockchains' | 'tokens'>;
|
|
37
38
|
|
|
38
|
-
export type SetTokenParams =
|
|
39
|
+
export type SetTokenParams =
|
|
40
|
+
| { token: TokenData; meta: { blockchains: BlockchainMeta[] } }
|
|
41
|
+
| { token: null };
|
|
39
42
|
|
|
40
43
|
type SomeQuoteState = {
|
|
41
44
|
quotes: MultiRouteResponse | null;
|
|
@@ -58,9 +61,9 @@ export interface QuoteState {
|
|
|
58
61
|
inputUsdValue: BigNumber | null;
|
|
59
62
|
outputAmount: BigNumber | null;
|
|
60
63
|
outputUsdValue: BigNumber | null;
|
|
61
|
-
fromToken:
|
|
64
|
+
fromToken: TokenData | null;
|
|
62
65
|
sortStrategy: PreferenceType;
|
|
63
|
-
toToken:
|
|
66
|
+
toToken: TokenData | null;
|
|
64
67
|
quoteWalletsConfirmed: boolean;
|
|
65
68
|
selectedWallets: Wallet[];
|
|
66
69
|
quoteWarningsConfirmed: boolean;
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import type { ConfigSlice } from './config';
|
|
2
2
|
import type { DataSlice } from './data';
|
|
3
|
+
import type { WalletsSlice } from './wallets';
|
|
4
|
+
import type { TokenData } from '../../components/TokenList/TokenList.types';
|
|
3
5
|
import type { WidgetConfig } from '../../types';
|
|
4
6
|
import type { SwapperMeta, Token } from 'rango-sdk';
|
|
5
7
|
import type { StateCreator } from 'zustand';
|
|
@@ -46,13 +48,13 @@ export interface SettingsSlice {
|
|
|
46
48
|
) => void;
|
|
47
49
|
addPreferredBlockchain: (blockchain: string) => void;
|
|
48
50
|
updateSettings: (config: WidgetConfig) => void;
|
|
49
|
-
setCustomToken: (token:
|
|
51
|
+
setCustomToken: (token: TokenData) => void;
|
|
50
52
|
deleteCustomToken: (token: Token) => void;
|
|
51
53
|
customTokens: () => Token[];
|
|
52
54
|
}
|
|
53
55
|
|
|
54
56
|
export const createSettingsSlice: StateCreator<
|
|
55
|
-
SettingsSlice & DataSlice & ConfigSlice,
|
|
57
|
+
SettingsSlice & DataSlice & ConfigSlice & WalletsSlice,
|
|
56
58
|
[],
|
|
57
59
|
[],
|
|
58
60
|
SettingsSlice
|
|
@@ -186,10 +188,15 @@ export const createSettingsSlice: StateCreator<
|
|
|
186
188
|
}),
|
|
187
189
|
});
|
|
188
190
|
},
|
|
189
|
-
setCustomToken: (token) =>
|
|
191
|
+
setCustomToken: (token) => {
|
|
192
|
+
void get().fetchCustomTokensBalance({
|
|
193
|
+
tokens: [token],
|
|
194
|
+
connectedWallets: get().connectedWallets,
|
|
195
|
+
});
|
|
190
196
|
set((state) => ({
|
|
191
197
|
_customTokens: [token, ...state._customTokens],
|
|
192
|
-
}))
|
|
198
|
+
}));
|
|
199
|
+
},
|
|
193
200
|
deleteCustomToken: (token) =>
|
|
194
201
|
set((state) => ({
|
|
195
202
|
_customTokens: state._customTokens.filter(
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { AppStoreState } from './types';
|
|
2
2
|
import type { Namespace } from '@rango-dev/wallets-core/namespaces/common';
|
|
3
|
-
import type { Token, WalletDetail } from 'rango-sdk';
|
|
3
|
+
import type { Asset, Token, WalletDetail } from 'rango-sdk';
|
|
4
4
|
|
|
5
5
|
import BigNumber from 'bignumber.js';
|
|
6
6
|
|
|
@@ -24,6 +24,7 @@ import {
|
|
|
24
24
|
extractAssetFromBalanceKey,
|
|
25
25
|
removeBalanceFromAggregatedBalance,
|
|
26
26
|
updateAggregatedBalanceStateForNewAccount,
|
|
27
|
+
updateBalancesWithNewPrices,
|
|
27
28
|
} from '../utils/wallets';
|
|
28
29
|
|
|
29
30
|
type WalletAddress = string;
|
|
@@ -124,6 +125,10 @@ export interface WalletsSlice {
|
|
|
124
125
|
accounts: Wallet[],
|
|
125
126
|
options?: { retryOnFailedBalances?: boolean }
|
|
126
127
|
) => Promise<void>;
|
|
128
|
+
fetchCustomTokensBalance: (params: {
|
|
129
|
+
tokens: Asset[];
|
|
130
|
+
connectedWallets: Wallet[];
|
|
131
|
+
}) => Promise<void>;
|
|
127
132
|
getBalanceFor: (token: Token) => Balance | null;
|
|
128
133
|
getBalances: () => BalanceState;
|
|
129
134
|
getBalancesForWalletAddress: (address: string) => BalanceState;
|
|
@@ -259,6 +264,7 @@ export const createWalletsSlice = keepLastUpdated<AppStoreState, WalletsSlice>(
|
|
|
259
264
|
return {
|
|
260
265
|
address: account.address,
|
|
261
266
|
chain: account.chain,
|
|
267
|
+
isContractWallet: account.isContractWallet,
|
|
262
268
|
explorerUrl: null,
|
|
263
269
|
walletType: account.walletType,
|
|
264
270
|
selected: shouldMarkWalletAsSelected,
|
|
@@ -294,6 +300,98 @@ export const createWalletsSlice = keepLastUpdated<AppStoreState, WalletsSlice>(
|
|
|
294
300
|
});
|
|
295
301
|
}
|
|
296
302
|
},
|
|
303
|
+
fetchCustomTokensBalance: async (params) => {
|
|
304
|
+
const { tokens, connectedWallets } = params;
|
|
305
|
+
|
|
306
|
+
const tokensByBlockchain = tokens.reduce<{ [key: string]: Asset[] }>(
|
|
307
|
+
(acc, asset) => {
|
|
308
|
+
(acc[asset.blockchain] ||= []).push(asset);
|
|
309
|
+
return acc;
|
|
310
|
+
},
|
|
311
|
+
{}
|
|
312
|
+
);
|
|
313
|
+
|
|
314
|
+
const addedWallets = new Set<string>();
|
|
315
|
+
|
|
316
|
+
const tokensByWalletAddress = connectedWallets.reduce<{
|
|
317
|
+
[key: string]: Asset[];
|
|
318
|
+
}>((acc, wallet) => {
|
|
319
|
+
const key = `${wallet.address}-${wallet.chain}`;
|
|
320
|
+
if (addedWallets.has(key)) {
|
|
321
|
+
return acc;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
addedWallets.add(key);
|
|
325
|
+
if (tokensByBlockchain[wallet.chain]) {
|
|
326
|
+
if (!acc[wallet.address]) {
|
|
327
|
+
acc[wallet.address] = [];
|
|
328
|
+
}
|
|
329
|
+
acc[wallet.address].push(...tokensByBlockchain[wallet.chain]);
|
|
330
|
+
}
|
|
331
|
+
return acc;
|
|
332
|
+
}, {});
|
|
333
|
+
|
|
334
|
+
Object.entries(tokensByWalletAddress).forEach(
|
|
335
|
+
async ([walletAddress, tokens]) => {
|
|
336
|
+
try {
|
|
337
|
+
const { balances } = await httpService().getMultipleTokenBalance({
|
|
338
|
+
assets: tokens.map(({ symbol, address, blockchain }) => ({
|
|
339
|
+
symbol,
|
|
340
|
+
address,
|
|
341
|
+
blockchain,
|
|
342
|
+
})),
|
|
343
|
+
walletAddress,
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
if (balances) {
|
|
347
|
+
let nextBalances: BalanceState = get()._balances;
|
|
348
|
+
let nextAggregatedBalances: AggregatedBalanceState =
|
|
349
|
+
get()._aggregatedBalances;
|
|
350
|
+
|
|
351
|
+
balances.forEach((balance) => {
|
|
352
|
+
if (parseFloat(balance.amount.amount) === 0) {
|
|
353
|
+
return;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
const WalletDetail = {
|
|
357
|
+
blockChain: balance.asset.blockchain,
|
|
358
|
+
balances: [balance],
|
|
359
|
+
address: walletAddress,
|
|
360
|
+
};
|
|
361
|
+
|
|
362
|
+
updateBalancesWithNewPrices(WalletDetail, nextBalances, get);
|
|
363
|
+
|
|
364
|
+
const balancesForWallet = createBalanceStateForNewAccount(
|
|
365
|
+
WalletDetail,
|
|
366
|
+
get
|
|
367
|
+
);
|
|
368
|
+
|
|
369
|
+
nextAggregatedBalances =
|
|
370
|
+
updateAggregatedBalanceStateForNewAccount(
|
|
371
|
+
nextAggregatedBalances,
|
|
372
|
+
balancesForWallet
|
|
373
|
+
);
|
|
374
|
+
|
|
375
|
+
nextBalances = {
|
|
376
|
+
...nextBalances,
|
|
377
|
+
...balancesForWallet,
|
|
378
|
+
};
|
|
379
|
+
});
|
|
380
|
+
|
|
381
|
+
set((state) => ({
|
|
382
|
+
_balances: {
|
|
383
|
+
...state._balances,
|
|
384
|
+
...nextBalances,
|
|
385
|
+
},
|
|
386
|
+
_aggregatedBalances: nextAggregatedBalances,
|
|
387
|
+
}));
|
|
388
|
+
}
|
|
389
|
+
} catch (error) {
|
|
390
|
+
console.error(error);
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
);
|
|
394
|
+
},
|
|
297
395
|
setWalletsAsSelected: (wallets) => {
|
|
298
396
|
const nextConnectedWalletsWithUpdatedSelectedStatus =
|
|
299
397
|
get().connectedWallets.map((connectedWallet) => {
|
|
@@ -331,6 +429,10 @@ export const createWalletsSlice = keepLastUpdated<AppStoreState, WalletsSlice>(
|
|
|
331
429
|
get().addConnectedWallet(accounts, namespace);
|
|
332
430
|
|
|
333
431
|
void get().fetchBalances(accounts);
|
|
432
|
+
void get().fetchCustomTokensBalance({
|
|
433
|
+
tokens: get().customTokens(),
|
|
434
|
+
connectedWallets: accounts,
|
|
435
|
+
});
|
|
334
436
|
},
|
|
335
437
|
removeBalancesForWallet: (walletType, options) => {
|
|
336
438
|
let walletsNeedsToBeRemoved = get().connectedWallets.filter(
|
|
@@ -561,7 +663,7 @@ export const createWalletsSlice = keepLastUpdated<AppStoreState, WalletsSlice>(
|
|
|
561
663
|
}
|
|
562
664
|
}
|
|
563
665
|
|
|
564
|
-
let nextBalances: BalanceState =
|
|
666
|
+
let nextBalances: BalanceState = get()._balances;
|
|
565
667
|
let nextAggregatedBalances: AggregatedBalanceState =
|
|
566
668
|
get()._aggregatedBalances;
|
|
567
669
|
walletsDetails.forEach((wallet) => {
|
|
@@ -569,6 +671,8 @@ export const createWalletsSlice = keepLastUpdated<AppStoreState, WalletsSlice>(
|
|
|
569
671
|
return;
|
|
570
672
|
}
|
|
571
673
|
|
|
674
|
+
updateBalancesWithNewPrices(wallet, nextBalances, get);
|
|
675
|
+
|
|
572
676
|
// Remove old balances for current wallet and blockchain
|
|
573
677
|
get().removeBalancesForWallet(walletType, {
|
|
574
678
|
chains: [wallet.blockChain],
|
|
@@ -44,8 +44,36 @@ export function extractAssetFromBalanceKey(key: BalanceKey): Asset {
|
|
|
44
44
|
};
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
+
export function updateBalancesWithNewPrices(
|
|
48
|
+
wallet: Omit<WalletDetail, 'failed' | 'explorerUrl'>,
|
|
49
|
+
balanceState: BalanceState,
|
|
50
|
+
store: () => AppStoreState
|
|
51
|
+
): BalanceState {
|
|
52
|
+
wallet.balances?.forEach((balance) => {
|
|
53
|
+
const usdPrice =
|
|
54
|
+
balance.price ?? store().findToken(balance.asset)?.usdPrice;
|
|
55
|
+
const balancesToUpdate =
|
|
56
|
+
store()._aggregatedBalances[createAssetKey(balance.asset)];
|
|
57
|
+
|
|
58
|
+
balancesToUpdate?.forEach((balanceKey) => {
|
|
59
|
+
if (balanceState[balanceKey]) {
|
|
60
|
+
balanceState[balanceKey] = {
|
|
61
|
+
...balanceState[balanceKey],
|
|
62
|
+
usdValue: usdPrice
|
|
63
|
+
? new BigNumber(usdPrice ?? ZERO)
|
|
64
|
+
.multipliedBy(balanceState[balanceKey].amount)
|
|
65
|
+
.toString()
|
|
66
|
+
: '',
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
return balanceState;
|
|
73
|
+
}
|
|
74
|
+
|
|
47
75
|
export function createBalanceStateForNewAccount(
|
|
48
|
-
account: WalletDetail,
|
|
76
|
+
account: Omit<WalletDetail, 'failed' | 'explorerUrl'>,
|
|
49
77
|
store: () => AppStoreState
|
|
50
78
|
): BalanceState {
|
|
51
79
|
const state: BalanceState = {};
|
|
@@ -55,7 +83,8 @@ export function createBalanceStateForNewAccount(
|
|
|
55
83
|
const amount = accountBalance.amount.amount;
|
|
56
84
|
const decimals = accountBalance.amount.decimals;
|
|
57
85
|
|
|
58
|
-
const usdPrice =
|
|
86
|
+
const usdPrice =
|
|
87
|
+
accountBalance.price ?? store().findToken(accountBalance.asset)?.usdPrice;
|
|
59
88
|
const usdValue = usdPrice
|
|
60
89
|
? new BigNumber(usdPrice ?? ZERO).multipliedBy(amount).toString()
|
|
61
90
|
: '';
|
package/src/types/config.ts
CHANGED
|
@@ -2,6 +2,7 @@ import type { Language, theme } from '@rango-dev/ui';
|
|
|
2
2
|
import type { LegacyProviderInterface } from '@rango-dev/wallets-core/dist/legacy/mod';
|
|
3
3
|
import type { WalletType } from '@rango-dev/wallets-shared';
|
|
4
4
|
import type { Asset } from 'rango-sdk';
|
|
5
|
+
import type { ReactElement } from 'react';
|
|
5
6
|
|
|
6
7
|
export type WidgetVariant = 'default' | 'expanded' | 'full-expanded';
|
|
7
8
|
|
|
@@ -273,6 +274,10 @@ export type WidgetConfig = {
|
|
|
273
274
|
__UNSTABLE_OR_INTERNAL__?: {
|
|
274
275
|
walletConnectListedDesktopWalletLink?: string;
|
|
275
276
|
autoUpdateSettings?: boolean; // If true, settings will be updated automatically based on the configuration.
|
|
277
|
+
swapBoxBanner?: {
|
|
278
|
+
element: ReactElement;
|
|
279
|
+
routes?: string[];
|
|
280
|
+
};
|
|
276
281
|
};
|
|
277
282
|
routing?: Routing;
|
|
278
283
|
};
|