@lifi/widget 4.9.0 → 4.10.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.
- package/README.md +26 -3
- package/dist/esm/components/TokenList/TokenDetailsSheet.js +5 -8
- package/dist/esm/components/TokenList/TokenDetailsSheet.js.map +1 -1
- package/dist/esm/components/TokenList/TokenDetailsSheetContent.js +30 -2
- package/dist/esm/components/TokenList/TokenDetailsSheetContent.js.map +1 -1
- package/dist/esm/components/TokenList/TokenListItem.js +36 -47
- package/dist/esm/components/TokenList/TokenListItem.js.map +1 -1
- package/dist/esm/components/TokenList/VirtualizedTokenList.d.ts.map +1 -1
- package/dist/esm/components/TokenList/VirtualizedTokenList.js +2 -2
- package/dist/esm/components/TokenList/VirtualizedTokenList.js.map +1 -1
- package/dist/esm/components/TokenList/tokenVerificationIcons.js +29 -0
- package/dist/esm/components/TokenList/tokenVerificationIcons.js.map +1 -0
- package/dist/esm/config/version.d.ts +1 -1
- package/dist/esm/config/version.js +1 -1
- package/dist/esm/config/version.js.map +1 -1
- package/dist/esm/i18n/bn.json +5 -1
- package/dist/esm/i18n/de.json +5 -1
- package/dist/esm/i18n/en.json +5 -1
- package/dist/esm/i18n/es.json +5 -1
- package/dist/esm/i18n/fr.json +5 -1
- package/dist/esm/i18n/hi.json +5 -1
- package/dist/esm/i18n/id.json +5 -1
- package/dist/esm/i18n/it.json +5 -1
- package/dist/esm/i18n/ja.json +5 -1
- package/dist/esm/i18n/ko.json +5 -1
- package/dist/esm/i18n/pl.json +5 -1
- package/dist/esm/i18n/pt.json +5 -1
- package/dist/esm/i18n/th.json +5 -1
- package/dist/esm/i18n/tr.json +5 -1
- package/dist/esm/i18n/uk.json +5 -1
- package/dist/esm/i18n/vi.json +5 -1
- package/dist/esm/i18n/zh.json +5 -1
- package/dist/esm/utils/token.js +13 -1
- package/dist/esm/utils/token.js.map +1 -1
- package/package.json +1 -1
- package/src/components/TokenList/TokenDetailsSheet.tsx +5 -9
- package/src/components/TokenList/TokenDetailsSheetContent.tsx +46 -4
- package/src/components/TokenList/TokenListItem.tsx +44 -68
- package/src/components/TokenList/VirtualizedTokenList.tsx +3 -6
- package/src/components/TokenList/tokenVerificationIcons.ts +15 -0
- package/src/components/TokenList/types.ts +3 -11
- package/src/config/version.ts +1 -1
- package/src/utils/token.ts +48 -0
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import type { StaticToken } from '@lifi/sdk'
|
|
2
2
|
import { ChainType } from '@lifi/sdk'
|
|
3
3
|
import InfoOutlinedIcon from '@mui/icons-material/InfoOutlined'
|
|
4
|
-
import ReportRoundedIcon from '@mui/icons-material/ReportRounded'
|
|
5
|
-
import VerifiedIcon from '@mui/icons-material/Verified'
|
|
6
4
|
import {
|
|
7
5
|
Avatar,
|
|
8
6
|
Box,
|
|
@@ -18,14 +16,19 @@ import type { JSX, MouseEventHandler } from 'react'
|
|
|
18
16
|
import { memo, useMemo, useRef, useState } from 'react'
|
|
19
17
|
import { useTranslation } from 'react-i18next'
|
|
20
18
|
import { useLongPress } from '../../hooks/useLongPress.js'
|
|
19
|
+
import type { TokenAmount } from '../../types/token.js'
|
|
21
20
|
import { formatTokenAmount, formatTokenPrice } from '../../utils/format.js'
|
|
22
|
-
import {
|
|
21
|
+
import {
|
|
22
|
+
getTokenVerificationBadge,
|
|
23
|
+
getTokenVerificationProvider,
|
|
24
|
+
} from '../../utils/token.js'
|
|
23
25
|
import { shortenAddress } from '../../utils/wallet.js'
|
|
24
26
|
import { TokenAvatar } from '../Avatar/TokenAvatar.js'
|
|
25
27
|
import { ListItemButton } from '../ListItem/ListItemButton.js'
|
|
26
28
|
import { PinTokenButton } from './PinTokenButton.js'
|
|
27
29
|
import { RemoveRecentTokenButton } from './RemoveRecentTokenButton.js'
|
|
28
30
|
import { IconButton, ListItem } from './TokenList.style.js'
|
|
31
|
+
import { tokenVerificationIcons } from './tokenVerificationIcons.js'
|
|
29
32
|
import type {
|
|
30
33
|
TokenListItemAvatarProps,
|
|
31
34
|
TokenListItemButtonProps,
|
|
@@ -88,23 +91,17 @@ const TokenListItemAvatar = memo(({ token }: TokenListItemAvatarProps) => {
|
|
|
88
91
|
})
|
|
89
92
|
|
|
90
93
|
interface OpenTokenDetailsButtonProps {
|
|
91
|
-
|
|
94
|
+
token: TokenAmount
|
|
92
95
|
withoutContractAddress: boolean
|
|
93
|
-
|
|
94
|
-
onClick: (
|
|
95
|
-
tokenAddress: string,
|
|
96
|
-
withoutContractAddress: boolean,
|
|
97
|
-
chainId: number
|
|
98
|
-
) => void
|
|
96
|
+
onClick: (token: TokenAmount, withoutContractAddress: boolean) => void
|
|
99
97
|
}
|
|
100
98
|
|
|
101
99
|
const OpenTokenDetailsButton = ({
|
|
102
|
-
|
|
100
|
+
token,
|
|
103
101
|
withoutContractAddress,
|
|
104
|
-
chainId,
|
|
105
102
|
onClick,
|
|
106
103
|
}: OpenTokenDetailsButtonProps) => {
|
|
107
|
-
if (!
|
|
104
|
+
if (!token.address) {
|
|
108
105
|
return null
|
|
109
106
|
}
|
|
110
107
|
return (
|
|
@@ -113,7 +110,7 @@ const OpenTokenDetailsButton = ({
|
|
|
113
110
|
onClick={(e) => {
|
|
114
111
|
e.stopPropagation()
|
|
115
112
|
e.currentTarget.blur() // Remove focus to prevent accessibility issues when opening drawer
|
|
116
|
-
onClick(
|
|
113
|
+
onClick(token, withoutContractAddress)
|
|
117
114
|
}}
|
|
118
115
|
>
|
|
119
116
|
<InfoOutlinedIcon />
|
|
@@ -169,65 +166,46 @@ const TokenListItemButton: React.FC<TokenListItemButtonProps> = memo(
|
|
|
169
166
|
)
|
|
170
167
|
|
|
171
168
|
const longPressEvents = useLongPress(() =>
|
|
172
|
-
onShowTokenDetails(token
|
|
169
|
+
onShowTokenDetails(token, withoutContractAddress)
|
|
173
170
|
)
|
|
174
171
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
let
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
verificationBadge = {
|
|
184
|
-
Icon: VerifiedIcon,
|
|
185
|
-
color: 'info.main',
|
|
186
|
-
title: chainName
|
|
172
|
+
const verificationBadge = getTokenVerificationBadge(token)
|
|
173
|
+
const verificationIcon = verificationBadge
|
|
174
|
+
? tokenVerificationIcons[verificationBadge]
|
|
175
|
+
: undefined
|
|
176
|
+
let verificationTitle = ''
|
|
177
|
+
switch (verificationBadge) {
|
|
178
|
+
case 'native':
|
|
179
|
+
verificationTitle = chainName
|
|
187
180
|
? t('tooltip.tokenNativeOnChain', {
|
|
188
181
|
tokenSymbol: token.symbol,
|
|
189
182
|
chainName,
|
|
190
183
|
})
|
|
191
|
-
: t('tooltip.tokenNative', { tokenSymbol: token.symbol })
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
Icon: ReportRoundedIcon,
|
|
196
|
-
color: 'error.main',
|
|
197
|
-
title: t('warning.message.tokenFlagged', {
|
|
184
|
+
: t('tooltip.tokenNative', { tokenSymbol: token.symbol })
|
|
185
|
+
break
|
|
186
|
+
case 'flagged':
|
|
187
|
+
verificationTitle = t('warning.message.tokenFlagged', {
|
|
198
188
|
tokenSymbol: token.symbol,
|
|
199
|
-
})
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
Icon: VerifiedIcon,
|
|
205
|
-
color: 'success.main',
|
|
206
|
-
title: provider
|
|
189
|
+
})
|
|
190
|
+
break
|
|
191
|
+
case 'verified': {
|
|
192
|
+
const provider = getTokenVerificationProvider(token)
|
|
193
|
+
verificationTitle = provider
|
|
207
194
|
? t('tooltip.tokenVerifiedByProvider', {
|
|
208
195
|
tokenSymbol: token.symbol,
|
|
209
196
|
provider,
|
|
210
197
|
})
|
|
211
|
-
: t('tooltip.tokenVerified', { tokenSymbol: token.symbol })
|
|
198
|
+
: t('tooltip.tokenVerified', { tokenSymbol: token.symbol })
|
|
199
|
+
break
|
|
212
200
|
}
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
!token.listed &&
|
|
216
|
-
!token.verified
|
|
217
|
-
) {
|
|
218
|
-
verificationBadge = {
|
|
219
|
-
Icon: ReportRoundedIcon,
|
|
220
|
-
color: 'warning.main',
|
|
221
|
-
title: t('warning.message.tokenUnverifiedByProvider', {
|
|
201
|
+
case 'unverifiedByProvider':
|
|
202
|
+
verificationTitle = t('warning.message.tokenUnverifiedByProvider', {
|
|
222
203
|
tokenSymbol: token.symbol,
|
|
223
|
-
})
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
color: 'warning.main',
|
|
229
|
-
title: t('warning.message.tokenUnverified'),
|
|
230
|
-
}
|
|
204
|
+
})
|
|
205
|
+
break
|
|
206
|
+
case 'unverified':
|
|
207
|
+
verificationTitle = t('warning.message.tokenUnverified')
|
|
208
|
+
break
|
|
231
209
|
}
|
|
232
210
|
|
|
233
211
|
return (
|
|
@@ -261,13 +239,13 @@ const TokenListItemButton: React.FC<TokenListItemButtonProps> = memo(
|
|
|
261
239
|
primary={
|
|
262
240
|
<Box sx={{ display: 'flex', alignItems: 'center', gap: 0.5 }}>
|
|
263
241
|
{token.symbol}
|
|
264
|
-
{
|
|
265
|
-
<Tooltip title={
|
|
266
|
-
<
|
|
242
|
+
{verificationIcon && (
|
|
243
|
+
<Tooltip title={verificationTitle} placement="top" arrow>
|
|
244
|
+
<verificationIcon.Icon
|
|
267
245
|
sx={{
|
|
268
246
|
display: 'flex',
|
|
269
247
|
fontSize: 16,
|
|
270
|
-
color:
|
|
248
|
+
color: verificationIcon.color,
|
|
271
249
|
cursor: 'help',
|
|
272
250
|
}}
|
|
273
251
|
/>
|
|
@@ -313,9 +291,8 @@ const TokenListItemButton: React.FC<TokenListItemButtonProps> = memo(
|
|
|
313
291
|
>
|
|
314
292
|
<Box>
|
|
315
293
|
<OpenTokenDetailsButton
|
|
316
|
-
|
|
294
|
+
token={token}
|
|
317
295
|
withoutContractAddress={withoutContractAddress}
|
|
318
|
-
chainId={token.chainId}
|
|
319
296
|
onClick={onShowTokenDetails}
|
|
320
297
|
/>
|
|
321
298
|
<PinTokenButton
|
|
@@ -385,9 +362,8 @@ const TokenListItemButton: React.FC<TokenListItemButtonProps> = memo(
|
|
|
385
362
|
</Box>
|
|
386
363
|
<Box>
|
|
387
364
|
<OpenTokenDetailsButton
|
|
388
|
-
|
|
365
|
+
token={token}
|
|
389
366
|
withoutContractAddress={withoutContractAddress}
|
|
390
|
-
chainId={token.chainId}
|
|
391
367
|
onClick={onShowTokenDetails}
|
|
392
368
|
/>
|
|
393
369
|
<PinTokenButton
|
|
@@ -5,6 +5,7 @@ import { useCallback, useEffect, useMemo, useRef } from 'react'
|
|
|
5
5
|
import { useTranslation } from 'react-i18next'
|
|
6
6
|
import { useAvailableChains } from '../../hooks/useAvailableChains.js'
|
|
7
7
|
import { getTokenKey } from '../../stores/recentTokens/utils.js'
|
|
8
|
+
import type { TokenAmount } from '../../types/token.js'
|
|
8
9
|
import { isHoistableNative } from '../../utils/tokenList.js'
|
|
9
10
|
import { createBandResolver } from '../../utils/tokenListBands.js'
|
|
10
11
|
import { RecentTokensHeader } from './RecentTokensHeader.js'
|
|
@@ -53,12 +54,8 @@ export const VirtualizedTokenList: FC<VirtualizedTokenListProps> = ({
|
|
|
53
54
|
const tokenDetailsSheetRef = useRef<TokenDetailsSheetBase>(null)
|
|
54
55
|
|
|
55
56
|
const onShowTokenDetails = useCallback(
|
|
56
|
-
(
|
|
57
|
-
tokenDetailsSheetRef.current?.open(
|
|
58
|
-
tokenAddress,
|
|
59
|
-
noContractAddress,
|
|
60
|
-
chainId
|
|
61
|
-
)
|
|
57
|
+
(token: TokenAmount, noContractAddress: boolean) => {
|
|
58
|
+
tokenDetailsSheetRef.current?.open(token, noContractAddress)
|
|
62
59
|
},
|
|
63
60
|
[]
|
|
64
61
|
)
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import ReportRoundedIcon from '@mui/icons-material/ReportRounded'
|
|
2
|
+
import VerifiedIcon from '@mui/icons-material/Verified'
|
|
3
|
+
import type { SvgIcon } from '@mui/material'
|
|
4
|
+
import type { TokenVerificationBadge } from '../../utils/token.js'
|
|
5
|
+
|
|
6
|
+
export const tokenVerificationIcons: Record<
|
|
7
|
+
TokenVerificationBadge,
|
|
8
|
+
{ Icon: typeof SvgIcon; color: string }
|
|
9
|
+
> = {
|
|
10
|
+
native: { Icon: VerifiedIcon, color: 'info.main' },
|
|
11
|
+
flagged: { Icon: ReportRoundedIcon, color: 'error.main' },
|
|
12
|
+
verified: { Icon: VerifiedIcon, color: 'success.main' },
|
|
13
|
+
unverifiedByProvider: { Icon: ReportRoundedIcon, color: 'warning.main' },
|
|
14
|
+
unverified: { Icon: ReportRoundedIcon, color: 'warning.main' },
|
|
15
|
+
}
|
|
@@ -38,11 +38,7 @@ interface TokenListItemBaseProps {
|
|
|
38
38
|
|
|
39
39
|
export interface TokenListItemProps extends TokenListItemBaseProps {
|
|
40
40
|
token: TokenAmount
|
|
41
|
-
onShowTokenDetails: (
|
|
42
|
-
tokenAddress: string,
|
|
43
|
-
noContractAddress: boolean,
|
|
44
|
-
chainId: number
|
|
45
|
-
) => void
|
|
41
|
+
onShowTokenDetails: (token: TokenAmount, noContractAddress: boolean) => void
|
|
46
42
|
chain?: ExtendedChain
|
|
47
43
|
/** Resolved for every row, unlike `chain`, which the list passes only in all-networks mode. */
|
|
48
44
|
chainName?: string
|
|
@@ -53,11 +49,7 @@ export interface TokenListItemProps extends TokenListItemBaseProps {
|
|
|
53
49
|
}
|
|
54
50
|
|
|
55
51
|
export interface TokenListItemButtonProps {
|
|
56
|
-
onShowTokenDetails: (
|
|
57
|
-
tokenAddress: string,
|
|
58
|
-
noContractAddress: boolean,
|
|
59
|
-
chainId: number
|
|
60
|
-
) => void
|
|
52
|
+
onShowTokenDetails: (token: TokenAmount, noContractAddress: boolean) => void
|
|
61
53
|
onClick?(tokenAddress: string, chainId?: number): void
|
|
62
54
|
token: TokenAmount
|
|
63
55
|
chain?: ExtendedChain
|
|
@@ -73,6 +65,6 @@ export interface TokenListItemAvatarProps {
|
|
|
73
65
|
|
|
74
66
|
export interface TokenDetailsSheetBase {
|
|
75
67
|
isOpen(): void
|
|
76
|
-
open(
|
|
68
|
+
open(token: TokenAmount, noContractAddress: boolean): void
|
|
77
69
|
close(): void
|
|
78
70
|
}
|
package/src/config/version.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export const name = '@lifi/widget'
|
|
2
|
-
export const version = '4.
|
|
2
|
+
export const version = '4.10.0'
|
package/src/utils/token.ts
CHANGED
|
@@ -280,6 +280,54 @@ export const getTokenVerificationProvider = (
|
|
|
280
280
|
: undefined
|
|
281
281
|
}
|
|
282
282
|
|
|
283
|
+
export type TokenVerificationBadge =
|
|
284
|
+
| 'native'
|
|
285
|
+
| 'flagged'
|
|
286
|
+
| 'verified'
|
|
287
|
+
| 'unverifiedByProvider'
|
|
288
|
+
| 'unverified'
|
|
289
|
+
|
|
290
|
+
export const getTokenVerificationBadge = (
|
|
291
|
+
token: Pick<
|
|
292
|
+
TokenWithFlags,
|
|
293
|
+
'native' | 'listed' | 'verified' | 'verificationStatus'
|
|
294
|
+
>
|
|
295
|
+
): TokenVerificationBadge | undefined => {
|
|
296
|
+
// The provider calls the native-address convention a scam on some chains.
|
|
297
|
+
if (token.native) {
|
|
298
|
+
return 'native'
|
|
299
|
+
}
|
|
300
|
+
if (token.verificationStatus === 'flagged') {
|
|
301
|
+
return 'flagged'
|
|
302
|
+
}
|
|
303
|
+
if (token.verificationStatus === 'verified') {
|
|
304
|
+
return 'verified'
|
|
305
|
+
}
|
|
306
|
+
if (token.listed || token.verified) {
|
|
307
|
+
return undefined
|
|
308
|
+
}
|
|
309
|
+
return token.verificationStatus === 'unverified'
|
|
310
|
+
? 'unverifiedByProvider'
|
|
311
|
+
: 'unverified'
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
export type TokenStatusTextKey =
|
|
315
|
+
| 'tokenMetric.statusVerified'
|
|
316
|
+
| 'tokenMetric.statusFlagged'
|
|
317
|
+
| 'tokenMetric.statusUnverified'
|
|
318
|
+
|
|
319
|
+
export const getTokenStatusTextKey = (
|
|
320
|
+
token: Pick<TokenWithFlags, 'native' | 'verificationStatus'>
|
|
321
|
+
): TokenStatusTextKey => {
|
|
322
|
+
if (token.verificationStatus === 'verified') {
|
|
323
|
+
return 'tokenMetric.statusVerified'
|
|
324
|
+
}
|
|
325
|
+
if (token.verificationStatus === 'flagged' && !token.native) {
|
|
326
|
+
return 'tokenMetric.statusFlagged'
|
|
327
|
+
}
|
|
328
|
+
return 'tokenMetric.statusUnverified'
|
|
329
|
+
}
|
|
330
|
+
|
|
283
331
|
/**
|
|
284
332
|
* Hyperliquid declares Arbitrum USDC as its native token, Lighter declares
|
|
285
333
|
* Ethereum USDC. Neither is a gas token you hold there. A chain-local
|