@dodoex/wallet-web3-react 0.0.1-beta.0

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 (78) hide show
  1. package/babel.config.js +9 -0
  2. package/dist/index.js +72 -0
  3. package/dist/types/ClientProvider.d.ts +2 -0
  4. package/dist/types/LangProvider.d.ts +11 -0
  5. package/dist/types/WalletConnect/AccountPage.d.ts +11 -0
  6. package/dist/types/WalletConnect/ActivityList.d.ts +20 -0
  7. package/dist/types/WalletConnect/ConnectAlchemy/index.d.ts +6 -0
  8. package/dist/types/WalletConnect/ConnectAlchemy/useConnectAlchemy.d.ts +12 -0
  9. package/dist/types/WalletConnect/ConnectLedger/ErrorDialog.d.ts +4 -0
  10. package/dist/types/WalletConnect/ConnectLedger/LoadingDialog.d.ts +3 -0
  11. package/dist/types/WalletConnect/ConnectLedger/LockedDialog.d.ts +4 -0
  12. package/dist/types/WalletConnect/ConnectLedger/ProtocolDialog.d.ts +6 -0
  13. package/dist/types/WalletConnect/ConnectLedger/SelectAddressDialog.d.ts +8 -0
  14. package/dist/types/WalletConnect/ConnectLedger/SelectPathDialog.d.ts +5 -0
  15. package/dist/types/WalletConnect/ConnectLedger/helper.d.ts +2 -0
  16. package/dist/types/WalletConnect/ConnectLedger/index.d.ts +6 -0
  17. package/dist/types/WalletConnect/ConnectPage.d.ts +9 -0
  18. package/dist/types/WalletConnect/HasBalanceTokenList.d.ts +4 -0
  19. package/dist/types/WalletConnect/ReceiveTokenPage.d.ts +4 -0
  20. package/dist/types/WalletConnect/SendTokenPage.d.ts +5 -0
  21. package/dist/types/WalletConnect/WalletDialog.d.ts +6 -0
  22. package/dist/types/WalletConnectProvider.d.ts +72 -0
  23. package/dist/types/components/AddressWithLinkAndCopy.d.ts +28 -0
  24. package/dist/types/components/Dialog.d.ts +15 -0
  25. package/dist/types/components/TokenLogo.d.ts +26 -0
  26. package/dist/types/components/WalletTag.d.ts +7 -0
  27. package/dist/types/constants/localstorage.d.ts +6 -0
  28. package/dist/types/hooks/useConnectWalet.d.ts +30 -0
  29. package/dist/types/hooks/useFetchFiatPrice.d.ts +3 -0
  30. package/dist/types/hooks/useFetchTokensBalance.d.ts +14 -0
  31. package/dist/types/hooks/useHasBalanceTokenList.d.ts +21 -0
  32. package/dist/types/hooks/useTransactionList.d.ts +272 -0
  33. package/dist/types/index.d.ts +4 -0
  34. package/dist/types/utils/formatter.d.ts +20 -0
  35. package/dist/types/utils/time.d.ts +3 -0
  36. package/dist/types/utils/utils.d.ts +2 -0
  37. package/lingui.config.ts +13 -0
  38. package/locales/en.po +251 -0
  39. package/locales/en.ts +1 -0
  40. package/locales/zh.po +249 -0
  41. package/locales/zh.ts +1 -0
  42. package/package.json +68 -0
  43. package/rollup.config.mjs +64 -0
  44. package/src/ClientProvider.tsx +15 -0
  45. package/src/LangProvider.tsx +32 -0
  46. package/src/WalletConnect/AccountPage.tsx +535 -0
  47. package/src/WalletConnect/ActivityList.tsx +597 -0
  48. package/src/WalletConnect/ConnectAlchemy/index.tsx +246 -0
  49. package/src/WalletConnect/ConnectAlchemy/useConnectAlchemy.ts +101 -0
  50. package/src/WalletConnect/ConnectLedger/ErrorDialog.tsx +61 -0
  51. package/src/WalletConnect/ConnectLedger/LoadingDialog.tsx +106 -0
  52. package/src/WalletConnect/ConnectLedger/LockedDialog.tsx +54 -0
  53. package/src/WalletConnect/ConnectLedger/ProtocolDialog.tsx +61 -0
  54. package/src/WalletConnect/ConnectLedger/SelectAddressDialog.tsx +326 -0
  55. package/src/WalletConnect/ConnectLedger/SelectPathDialog.tsx +68 -0
  56. package/src/WalletConnect/ConnectLedger/helper.ts +14 -0
  57. package/src/WalletConnect/ConnectLedger/index.tsx +89 -0
  58. package/src/WalletConnect/ConnectPage.tsx +459 -0
  59. package/src/WalletConnect/HasBalanceTokenList.tsx +201 -0
  60. package/src/WalletConnect/ReceiveTokenPage.tsx +143 -0
  61. package/src/WalletConnect/SendTokenPage.tsx +249 -0
  62. package/src/WalletConnect/WalletDialog.tsx +72 -0
  63. package/src/WalletConnectProvider.tsx +54 -0
  64. package/src/components/AddressWithLinkAndCopy.tsx +200 -0
  65. package/src/components/Dialog.tsx +155 -0
  66. package/src/components/TokenLogo.tsx +165 -0
  67. package/src/components/WalletTag.tsx +113 -0
  68. package/src/constants/localstorage.ts +22 -0
  69. package/src/hooks/useConnectWalet.ts +144 -0
  70. package/src/hooks/useFetchFiatPrice.ts +51 -0
  71. package/src/hooks/useFetchTokensBalance.ts +52 -0
  72. package/src/hooks/useHasBalanceTokenList.ts +157 -0
  73. package/src/hooks/useTransactionList.ts +87 -0
  74. package/src/index.tsx +4 -0
  75. package/src/utils/formatter.ts +102 -0
  76. package/src/utils/time.ts +21 -0
  77. package/src/utils/utils.ts +8 -0
  78. package/tsconfig.json +22 -0
@@ -0,0 +1,326 @@
1
+ import {
2
+ Box,
3
+ Button,
4
+ LoadingSkeleton,
5
+ Radio,
6
+ useTheme,
7
+ alpha,
8
+ } from '@dodoex/components';
9
+ import { ArrowRight } from '@dodoex/icons';
10
+ import { t, Trans } from '@lingui/macro';
11
+ import BigNumber from 'bignumber.js';
12
+ import { useEffect, useState } from 'react';
13
+ import { AddressWithLink } from '../../components/AddressWithLinkAndCopy';
14
+ import Dialog, { DialogTitle } from '../../components/Dialog';
15
+ import { formatReadableNumber } from '../../utils/formatter';
16
+ import { useWalletConnectContext } from '../../WalletConnectProvider';
17
+ import { getAccountList } from './helper';
18
+
19
+ function SwitchPageBtn({
20
+ left,
21
+ disabled,
22
+ onClick,
23
+ }: {
24
+ left?: boolean;
25
+ disabled?: boolean;
26
+ onClick: () => void;
27
+ }) {
28
+ const theme = useTheme();
29
+ const backgroundColor = theme.palette.border.main;
30
+ const isLight = theme.palette.mode === 'light';
31
+ return (
32
+ <Box
33
+ sx={{
34
+ display: 'flex',
35
+ alignItems: 'center',
36
+ justifyContent: 'center',
37
+ width: 36,
38
+ height: 36,
39
+ borderRadius: 8,
40
+ backgroundColor,
41
+ cursor: disabled ? 'disabled' : 'pointer',
42
+ color: disabled ? 'background.paperDarkContrast' : 'text.secondary',
43
+ '&:hover': {
44
+ backgroundColor: disabled
45
+ ? backgroundColor
46
+ : alpha(backgroundColor, isLight ? 0.3 : 0.5),
47
+ },
48
+ }}
49
+ onClick={() => {
50
+ if (disabled) return;
51
+ onClick();
52
+ }}
53
+ >
54
+ <Box
55
+ component={ArrowRight}
56
+ sx={
57
+ left
58
+ ? {
59
+ transform: 'rotate(180deg)',
60
+ }
61
+ : undefined
62
+ }
63
+ />
64
+ </Box>
65
+ );
66
+ }
67
+
68
+ export default function SelectAddressDialog({
69
+ on,
70
+ path,
71
+ chainId = 1,
72
+ onClose,
73
+ onNext,
74
+ onError,
75
+ }: {
76
+ on: boolean;
77
+ path: string;
78
+ chainId: number;
79
+ onClose: () => void;
80
+ onNext: (path: string, address: string) => void;
81
+ onError: (error: any) => void;
82
+ }) {
83
+ const { loadAccountListEthBalance, getChain } = useWalletConnectContext();
84
+ const theme = useTheme();
85
+ const [accountMap, setAccountMap] = useState<Map<number, string[]>>(
86
+ new Map(),
87
+ );
88
+ const [activeAddress, setActiveAddress] = useState('');
89
+ const [page, setPage] = useState(0);
90
+ const [loading, setLoading] = useState(false);
91
+ const [pathMap, setPathMap] = useState<Map<string, string>>(new Map());
92
+ const [balanceMap, setBalanceMap] = useState<Map<string, number | null>>(
93
+ new Map(),
94
+ );
95
+ const pageSize = 5;
96
+
97
+ useEffect(() => {
98
+ if (on) {
99
+ if (!path) {
100
+ throw new Error('path is not valid.');
101
+ }
102
+ setAccountMap(new Map());
103
+ setBalanceMap(new Map());
104
+ setPage(1);
105
+ } else {
106
+ setPage(0);
107
+ }
108
+ }, [path, on, onError]);
109
+
110
+ useEffect(() => {
111
+ if (on && page) {
112
+ if (accountMap.get(page)) return;
113
+ setLoading(true);
114
+ if (!path) {
115
+ throw new Error('path is not valid.');
116
+ }
117
+ const computed = async () => {
118
+ let accountList = [] as Awaited<ReturnType<typeof getAccountList>>;
119
+ try {
120
+ accountList = await getAccountList(path, page, pageSize);
121
+ setLoading(false);
122
+ } catch (error) {
123
+ console.error(error);
124
+ onError(error);
125
+ setLoading(false);
126
+ return;
127
+ }
128
+ const newPathMap: Map<string, string> = new Map();
129
+ const accountArray = accountList.map(
130
+ ({ path: currentPath, account }) => {
131
+ newPathMap.set(account, currentPath);
132
+ return account;
133
+ },
134
+ );
135
+ setPathMap((prev) => new Map([...prev, ...newPathMap]));
136
+ setAccountMap((prev) => prev.set(page, accountArray));
137
+ if (loadAccountListEthBalance) {
138
+ const balanceMapRes = await loadAccountListEthBalance(
139
+ accountArray,
140
+ chainId,
141
+ );
142
+ setBalanceMap((prev) => new Map([...prev, ...balanceMapRes]));
143
+ }
144
+ };
145
+ computed();
146
+ }
147
+ }, [page]);
148
+
149
+ const etherSymbol = getChain(chainId)?.gasToken?.symbol ?? 'ETH';
150
+
151
+ const borderColor = theme.palette.border.main;
152
+ return (
153
+ <Dialog open={on} onClose={onClose} width={420}>
154
+ <DialogTitle onClose={onClose}>
155
+ <Trans>Before proceeding make sure</Trans>
156
+ </DialogTitle>
157
+ <Box>
158
+ <Box
159
+ component="table"
160
+ sx={{
161
+ mt: 38,
162
+ width: '100%',
163
+ borderRadius: 12,
164
+ borderCollapse: 'separate',
165
+ borderSpacing: 0,
166
+ border: `solid 1px ${borderColor}`,
167
+ '& td, & th': {
168
+ py: 12,
169
+ border: `solid 0px ${borderColor}`,
170
+ borderBottomWidth: 1,
171
+ },
172
+ '& th': {
173
+ typography: 'body1',
174
+ color: 'text.secondary',
175
+ },
176
+ '& tr:last-of-type td': {
177
+ borderColor: 'transparent',
178
+ },
179
+ '& td': {
180
+ '&:first-of-type': {
181
+ pl: 20,
182
+ pr: 8,
183
+ },
184
+ '&:last-of-type': {
185
+ pr: 20,
186
+ },
187
+ },
188
+ }}
189
+ >
190
+ <thead>
191
+ <tr>
192
+ <th style={{ width: 60 }}> </th>
193
+ <th style={{ width: 28 }}>
194
+ <Trans>ID</Trans>
195
+ </th>
196
+ <Box
197
+ component="th"
198
+ sx={{
199
+ textAlign: 'center',
200
+ }}
201
+ >
202
+ <Trans>Address</Trans>
203
+ </Box>
204
+ {!!loadAccountListEthBalance && (
205
+ <th>
206
+ <Trans>Balance</Trans>
207
+ </th>
208
+ )}
209
+ </tr>
210
+ </thead>
211
+ <tbody>
212
+ {(
213
+ accountMap.get(page) ??
214
+ Object.keys(new Array(pageSize + 1).join(','))
215
+ ).map((address, index) => (
216
+ <Box
217
+ component="tr"
218
+ key={address || index}
219
+ onClick={() => {
220
+ if (address) {
221
+ setActiveAddress(address);
222
+ }
223
+ }}
224
+ sx={
225
+ address
226
+ ? {
227
+ cursor: 'pointer',
228
+ '&:hover': {
229
+ backgroundColor: 'custom.background.listHover',
230
+ },
231
+ }
232
+ : undefined
233
+ }
234
+ >
235
+ <td>
236
+ <Radio
237
+ checked={address === activeAddress}
238
+ onChange={() => setActiveAddress(address as string)}
239
+ // @ts-ignore
240
+ disabled={!address}
241
+ />
242
+ </td>
243
+ <td>{index + 1 + (page - 1) * pageSize}</td>
244
+ <LoadingSkeleton
245
+ loading={loading}
246
+ component="td"
247
+ sx={{
248
+ textAlign: 'center',
249
+ }}
250
+ >
251
+ {address ? (
252
+ <AddressWithLink
253
+ address={address}
254
+ truncate
255
+ iconSpace={6}
256
+ customChainId={chainId}
257
+ sx={{
258
+ display: 'inline-flex',
259
+ }}
260
+ />
261
+ ) : (
262
+ ''
263
+ )}
264
+ </LoadingSkeleton>
265
+ <LoadingSkeleton
266
+ loading={loading || !balanceMap.get(address)}
267
+ component="td"
268
+ sx={{
269
+ textAlign: 'right',
270
+ }}
271
+ >
272
+ {balanceMap.get(address)
273
+ ? `${formatReadableNumber({
274
+ input: balanceMap.get(address) || '',
275
+ })} ${etherSymbol}`
276
+ : ''}
277
+ </LoadingSkeleton>
278
+ </Box>
279
+ ))}
280
+ </tbody>
281
+ </Box>
282
+ <Box
283
+ sx={{
284
+ display: 'flex',
285
+ alignItems: 'center',
286
+ justifyContent: 'flex-end',
287
+ mt: 20,
288
+ }}
289
+ >
290
+ <SwitchPageBtn
291
+ left
292
+ disabled={page === 1}
293
+ onClick={() => setPage((prev) => prev - 1)}
294
+ />
295
+ <Box
296
+ sx={{
297
+ mx: 8,
298
+ }}
299
+ >
300
+ {page}
301
+ </Box>
302
+ <SwitchPageBtn onClick={() => setPage((prev) => prev + 1)} />
303
+ </Box>
304
+ </Box>
305
+ <Box
306
+ sx={{
307
+ mt: 40,
308
+ px: 20,
309
+ py: 16,
310
+ backgroundColor: 'background.paperContrast',
311
+ }}
312
+ >
313
+ <Button
314
+ fullWidth
315
+ disabled={!activeAddress}
316
+ onClick={() => {
317
+ onNext(pathMap.get(activeAddress) as string, activeAddress);
318
+ onClose();
319
+ }}
320
+ >
321
+ <Trans>Continue</Trans>
322
+ </Button>
323
+ </Box>
324
+ </Dialog>
325
+ );
326
+ }
@@ -0,0 +1,68 @@
1
+ import { Button, alpha, Box, useTheme } from '@dodoex/components';
2
+ import { HD_PATH_LIST } from '@dodoex/wallet-web3';
3
+ import { Trans } from '@lingui/macro';
4
+ import { useState } from 'react';
5
+ import Dialog, { DialogTitle } from '../../components/Dialog';
6
+
7
+ export default function SelectPathDialog({
8
+ on,
9
+ onClose,
10
+ onNext,
11
+ }: {
12
+ on: boolean;
13
+ onClose: () => void;
14
+ onNext: (path: string) => void;
15
+ }) {
16
+ const theme = useTheme();
17
+ const [activePath, setActivePath] = useState('');
18
+ const handleSelectPath = (path: string) => {
19
+ setActivePath(path);
20
+ };
21
+
22
+ return (
23
+ <Dialog open={on} onClose={onClose} width={420}>
24
+ <DialogTitle onClose={onClose}>
25
+ <Trans>Available Ledger Account</Trans>
26
+ </DialogTitle>
27
+ {HD_PATH_LIST.map(({ path, name }) => (
28
+ <Button
29
+ fullWidth
30
+ variant={Button.Variant.outlined}
31
+ sx={{
32
+ mt: 20,
33
+ ...(activePath !== path
34
+ ? {
35
+ color: 'text.disabled',
36
+ borderColor: theme.palette.background.paperDarkContrast,
37
+ '&:hover': {
38
+ backgroundColor: alpha(theme.palette.text.primary, 0.1),
39
+ color: 'text.primary',
40
+ },
41
+ }
42
+ : {}),
43
+ }}
44
+ key={path}
45
+ onClick={() => handleSelectPath(path)}
46
+ >
47
+ {name}
48
+ </Button>
49
+ ))}
50
+ <Box
51
+ sx={{
52
+ mt: 40,
53
+ px: 20,
54
+ py: 16,
55
+ backgroundColor: 'background.paperContrast',
56
+ }}
57
+ >
58
+ <Button
59
+ fullWidth
60
+ disabled={!activePath}
61
+ onClick={() => onNext(activePath)}
62
+ >
63
+ <Trans>Continue</Trans>
64
+ </Button>
65
+ </Box>
66
+ </Dialog>
67
+ );
68
+ }
@@ -0,0 +1,14 @@
1
+ import { getLedgerUSBPackage } from '@dodoex/wallet-web3';
2
+ export async function getTransport() {
3
+ const ledger = await getLedgerUSBPackage();
4
+ return ledger.getTransport();
5
+ }
6
+
7
+ export async function getAccountList(
8
+ pathRule: string,
9
+ page?: number | undefined,
10
+ pageSize?: number,
11
+ ) {
12
+ const ledger = await getLedgerUSBPackage();
13
+ return ledger.getAccountList(pathRule, page, pageSize);
14
+ }
@@ -0,0 +1,89 @@
1
+ import { useEffect, useMemo, useState } from 'react';
2
+ import { getTransport } from './helper';
3
+ import ProtocolDialog from './ProtocolDialog';
4
+ import SelectAddressDialog from './SelectAddressDialog';
5
+ import SelectPathDialog from './SelectPathDialog';
6
+ import LoadingDialog from './LoadingDialog';
7
+ import LockedDialog from './LockedDialog';
8
+ import ErrorDialog from './ErrorDialog';
9
+
10
+ enum Step {
11
+ init = 1,
12
+ readProtocol,
13
+ loadingConnect,
14
+ selectPath,
15
+ selectAddress,
16
+ }
17
+
18
+ export default function ConnectLedger({
19
+ on,
20
+ chainId = 1,
21
+ onClose,
22
+ onConnect,
23
+ }: {
24
+ on: boolean;
25
+ chainId: number | undefined;
26
+ onClose: () => void;
27
+ onConnect: (path: string, account: string) => void;
28
+ }) {
29
+ const [currentStep, setCurrentStep] = useState(Step.init);
30
+ const [path, setPath] = useState('');
31
+ const [error, setError] = useState<any | undefined>();
32
+
33
+ useEffect(() => {
34
+ if (!on) {
35
+ setCurrentStep(Step.init);
36
+ } else {
37
+ setCurrentStep(Step.readProtocol);
38
+ }
39
+ }, [on]);
40
+
41
+ const locked = useMemo(() => error?.statusCode === 27404, [error]);
42
+
43
+ return (
44
+ <>
45
+ <ProtocolDialog
46
+ on={currentStep === Step.readProtocol}
47
+ chainId={chainId}
48
+ onClose={onClose}
49
+ onNext={async () => {
50
+ setCurrentStep(Step.loadingConnect);
51
+ try {
52
+ const transport = await getTransport();
53
+ transport.close();
54
+ setCurrentStep(Step.selectPath);
55
+ } catch (e: any) {
56
+ // cancel
57
+ console.error(e);
58
+ onClose();
59
+ }
60
+ }}
61
+ />
62
+ <LoadingDialog on={currentStep === Step.loadingConnect} />
63
+ <SelectPathDialog
64
+ on={currentStep === Step.selectPath}
65
+ onClose={onClose}
66
+ onNext={(p) => {
67
+ setPath(p);
68
+ setCurrentStep(Step.selectAddress);
69
+ }}
70
+ />
71
+ <SelectAddressDialog
72
+ on={currentStep === Step.selectAddress}
73
+ path={path}
74
+ chainId={chainId}
75
+ onClose={onClose}
76
+ onNext={onConnect}
77
+ onError={(e: any) => {
78
+ setCurrentStep(Step.selectPath);
79
+ setError(e);
80
+ }}
81
+ />
82
+ <LockedDialog on={!!locked} onClose={() => setError(undefined)} />
83
+ <ErrorDialog
84
+ error={error && !locked ? error.message : undefined}
85
+ onClose={() => setError(undefined)}
86
+ />
87
+ </>
88
+ );
89
+ }