UI/UX: Scam tokens tooltip (#3018)

* UI/UX: Scam tokens tooltip

* review fixes
This commit is contained in:
Igor Stuev
2025-09-26 22:40:04 +02:00
committed by GitHub
parent a53c945d5f
commit ec76ae30a1
41 changed files with 163 additions and 23 deletions
+3
View File
@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 20 20">
<path fill="#E53E3E" d="M10 0c5.523 0 10 4.477 10 10s-4.477 10-10 10S0 15.523 0 10 4.477 0 10 0m0 1.6a8.4 8.4 0 1 0 0 16.8 8.4 8.4 0 0 0 0-16.8m6.895 9.41a.501.501 0 0 1 .21.98l-.154.03-1.547 2.68a.2.2 0 0 1-.345 0l-1.222-2.115-.152.022-1.293 3.02a.2.2 0 0 1-.359.02l-1.556-2.774q-.362.008-.725.003l-1.554 2.77a.2.2 0 0 1-.358-.019l-1.28-2.985-.184-.026L5.173 14.7a.2.2 0 0 1-.346 0l-1.516-2.626-.416-.085-.096-.031A.501.501 0 0 1 3.005 11l.1.01.992.207c4.824.957 7.78.867 12.798-.206M3.88 5.368a.43.43 0 0 1 .266.038L9.064 7.88a.426.426 0 0 1-.04.777l-1.246.472A2.42 2.42 0 0 1 4.83 8.094L3.59 6.002a.43.43 0 0 1 .055-.506.43.43 0 0 1 .235-.129m12.241 0a.424.424 0 0 1 .29.634l-1.24 2.093a2.43 2.43 0 0 1-2.951 1.035l-1.246-.472h.003a.428.428 0 0 1-.217-.611.43.43 0 0 1 .177-.166l4.919-2.474a.42.42 0 0 1 .265-.039"/>
</svg>

After

Width:  |  Height:  |  Size: 902 B

+2
View File
@@ -27,6 +27,7 @@ export const token1: SearchResultToken = {
exchange_rate: null,
is_verified_via_admin_panel: true,
is_smart_contract_verified: true,
reputation: 'ok',
};
export const token2: SearchResultToken = {
@@ -42,6 +43,7 @@ export const token2: SearchResultToken = {
exchange_rate: '1.11',
is_verified_via_admin_panel: false,
is_smart_contract_verified: false,
reputation: 'ok',
};
export const block1: SearchResultBlock = {
+14
View File
@@ -11,6 +11,7 @@ export const tokenInfo: TokenInfo = {
type: 'ERC-20' as const,
total_supply: '1235',
icon_url: 'http://localhost:3000/token-icon.png',
reputation: 'ok',
};
export const tokenCounters: TokenCounters = {
@@ -29,6 +30,7 @@ export const tokenInfoERC20a: TokenInfo<'ERC-20'> = {
total_supply: '369000000000000000000000000',
type: 'ERC-20' as const,
icon_url: 'http://localhost:3000/token-icon.png',
reputation: 'ok',
};
export const tokenInfoERC20b: TokenInfo<'ERC-20'> = {
@@ -42,6 +44,7 @@ export const tokenInfoERC20b: TokenInfo<'ERC-20'> = {
total_supply: '900000000000000000000000000',
type: 'ERC-20' as const,
icon_url: null,
reputation: 'ok',
};
export const tokenInfoERC20c: TokenInfo<'ERC-20'> = {
@@ -55,6 +58,7 @@ export const tokenInfoERC20c: TokenInfo<'ERC-20'> = {
total_supply: '1000000000000000000000000',
type: 'ERC-20' as const,
icon_url: null,
reputation: 'ok',
};
export const tokenInfoERC20d: TokenInfo<'ERC-20'> = {
@@ -68,6 +72,7 @@ export const tokenInfoERC20d: TokenInfo<'ERC-20'> = {
total_supply: '2100000000000000000000000000',
type: 'ERC-20' as const,
icon_url: null,
reputation: 'ok',
};
export const tokenInfoERC20LongSymbol: TokenInfo<'ERC-20'> = {
@@ -81,6 +86,7 @@ export const tokenInfoERC20LongSymbol: TokenInfo<'ERC-20'> = {
total_supply: '2100000000000000000000000000',
type: 'ERC-20' as const,
icon_url: null,
reputation: 'ok',
};
export const tokenInfoERC721a: TokenInfo<'ERC-721'> = {
@@ -94,6 +100,7 @@ export const tokenInfoERC721a: TokenInfo<'ERC-721'> = {
total_supply: '105',
type: 'ERC-721' as const,
icon_url: null,
reputation: 'ok',
};
export const tokenInfoERC721b: TokenInfo<'ERC-721'> = {
@@ -107,6 +114,7 @@ export const tokenInfoERC721b: TokenInfo<'ERC-721'> = {
total_supply: null,
type: 'ERC-721' as const,
icon_url: null,
reputation: 'ok',
};
export const tokenInfoERC721c: TokenInfo<'ERC-721'> = {
@@ -120,6 +128,7 @@ export const tokenInfoERC721c: TokenInfo<'ERC-721'> = {
total_supply: null,
type: 'ERC-721' as const,
icon_url: null,
reputation: 'ok',
};
export const tokenInfoERC721LongSymbol: TokenInfo<'ERC-721'> = {
@@ -133,6 +142,7 @@ export const tokenInfoERC721LongSymbol: TokenInfo<'ERC-721'> = {
total_supply: null,
type: 'ERC-721' as const,
icon_url: null,
reputation: 'ok',
};
export const tokenInfoERC1155a: TokenInfo<'ERC-1155'> = {
@@ -146,6 +156,7 @@ export const tokenInfoERC1155a: TokenInfo<'ERC-1155'> = {
total_supply: '482',
type: 'ERC-1155' as const,
icon_url: null,
reputation: 'ok',
};
export const tokenInfoERC1155b: TokenInfo<'ERC-1155'> = {
@@ -159,6 +170,7 @@ export const tokenInfoERC1155b: TokenInfo<'ERC-1155'> = {
total_supply: '4943',
type: 'ERC-1155' as const,
icon_url: null,
reputation: 'ok',
};
export const tokenInfoERC1155WithoutName: TokenInfo<'ERC-1155'> = {
@@ -172,6 +184,7 @@ export const tokenInfoERC1155WithoutName: TokenInfo<'ERC-1155'> = {
total_supply: '482',
type: 'ERC-1155' as const,
icon_url: null,
reputation: 'ok',
};
export const tokenInfoERC404: TokenInfo<'ERC-404'> = {
@@ -185,6 +198,7 @@ export const tokenInfoERC404: TokenInfo<'ERC-404'> = {
symbol: 'O404',
total_supply: '6482275000000000000',
type: 'ERC-404' as const,
reputation: 'ok',
};
export const bridgedTokenA: TokenInfo<'ERC-20'> = {
+4
View File
@@ -37,6 +37,7 @@ export const erc20: TokenTransfer = {
type: 'ERC-20',
total_supply: '0',
icon_url: null,
reputation: 'ok',
},
total: {
decimals: '18',
@@ -85,6 +86,7 @@ export const erc721: TokenTransfer = {
type: 'ERC-721',
total_supply: '0',
icon_url: null,
reputation: 'ok',
},
total: {
token_id: '875879856',
@@ -133,6 +135,7 @@ export const erc1155A: TokenTransfer = {
type: 'ERC-1155',
total_supply: '0',
icon_url: null,
reputation: 'ok',
},
total: {
token_id: '123',
@@ -212,6 +215,7 @@ export const erc404A: TokenTransfer = {
type: 'ERC-404',
total_supply: '0',
icon_url: null,
reputation: 'ok',
},
total: {
value: '42000000000000000000000000',
+4
View File
@@ -35,6 +35,7 @@ export const mintToken: TxStateChange = {
total_supply: '10645',
type: 'ERC-721',
icon_url: null,
reputation: 'ok',
},
type: 'token' as const,
};
@@ -74,6 +75,7 @@ export const receiveMintedToken: TxStateChange = {
total_supply: '10645',
type: 'ERC-721',
icon_url: null,
reputation: 'ok',
},
type: 'token' as const,
};
@@ -105,6 +107,7 @@ export const transfer1155Token: TxStateChange = {
symbol: null,
total_supply: null,
type: 'ERC-1155',
reputation: 'ok',
},
token_id: '1',
type: 'token' as const,
@@ -177,6 +180,7 @@ export const sendERC20Token: TxStateChange = {
symbol: 'USDT',
total_supply: '39030615894320966',
type: 'ERC-20' as const,
reputation: 'ok',
},
type: 'token' as const,
};
+2
View File
@@ -311,6 +311,7 @@ export const stabilityTx: Transaction = {
symbol: 'GAS',
total_supply: '10000000000000000000000000',
type: 'ERC-20',
reputation: 'ok',
},
total_fee: '68762500000000',
validator_address: {
@@ -342,6 +343,7 @@ export const celoTxn: Transaction = {
symbol: 'cUSD',
total_supply: '7145754483836626799435133',
type: 'ERC-20',
reputation: 'ok',
},
},
};
+1
View File
@@ -22,6 +22,7 @@ export const txInterpretation: TxInterpretationResponse = {
total_supply: '210000000000000000000000000',
exchange_rate: null,
circulating_market_cap: null,
reputation: 'ok',
},
},
to_address: {
+1
View File
@@ -144,6 +144,7 @@
| "rocket_xl"
| "rocket"
| "RPC"
| "scam"
| "scope"
| "score/score-not-ok"
| "score/score-ok"
+1
View File
@@ -15,6 +15,7 @@ export const SEARCH_RESULT_ITEM: SearchResultItem = {
exchange_rate: '1.11',
total_supply: null,
token_type: 'ERC-20',
reputation: 'ok',
};
export const SEARCH_RESULT_NEXT_PAGE_PARAMS: SearchResult['next_page_params'] = {
+1
View File
@@ -27,6 +27,7 @@ export const TOKEN_INFO_ERC_20: TokenInfo<'ERC-20'> = {
total_supply: '60000000000000000000000',
type: 'ERC-20',
icon_url: null,
reputation: 'ok',
};
export const TOKEN_INFO_ERC_721: TokenInfo<'ERC-721'> = {
+2 -1
View File
@@ -1,6 +1,6 @@
import type * as bens from '@blockscout/bens-types';
import type * as tac from '@blockscout/tac-operation-lifecycle-types';
import type { TokenType } from 'types/api/token';
import type { TokenReputation, TokenType } from 'types/api/token';
import type { AddressMetadataTagApi } from './addressMetadata';
@@ -36,6 +36,7 @@ export interface SearchResultToken {
is_smart_contract_verified: boolean;
filecoin_robust_address?: string | null;
certified?: boolean;
reputation: TokenReputation | null;
}
type SearchResultEnsInfo = {
+3
View File
@@ -4,6 +4,8 @@ import type { AddressParam } from './addressParams';
export type NFTTokenType = 'ERC-721' | 'ERC-1155' | 'ERC-404';
export type TokenType = 'ERC-20' | NFTTokenType;
export type TokenReputation = 'ok' | 'scam';
export interface TokenInfo<T extends TokenType = TokenType> {
address_hash: string;
type: T;
@@ -15,6 +17,7 @@ export interface TokenInfo<T extends TokenType = TokenType> {
total_supply: string | null;
icon_url: string | null;
circulating_market_cap: string | null;
reputation: TokenReputation | null;
// bridged token fields
is_bridged?: boolean | null;
bridge_type?: string | null;
+18
View File
@@ -0,0 +1,18 @@
import React from 'react';
import * as metadataMock from 'mocks/metadata/address';
import { test, expect } from 'playwright/lib';
import AddressAlerts from './AddressAlerts';
test('base view', async({ render }) => {
const component = await render(<AddressAlerts tags={ [ metadataMock.noteTag, metadataMock.noteTag2 ] }/>);
await expect(component).toHaveScreenshot();
});
test('with scam token', async({ render }) => {
const component = await render(<AddressAlerts tags={ [ metadataMock.noteTag, metadataMock.noteTag2 ] } isScamToken={ true }/>);
await expect(component).toHaveScreenshot();
});
@@ -8,19 +8,25 @@ import { Alert } from 'toolkit/chakra/alert';
interface Props {
tags: Array<AddressMetadataTagFormatted> | undefined;
isScamToken?: boolean;
className?: string;
}
const AddressMetadataAlert = ({ tags, className }: Props) => {
const AddressAlerts = ({ tags, isScamToken, className }: Props) => {
const noteTags = tags?.filter(({ tagType }) => tagType === 'note').filter(({ meta }) => meta?.data);
if (!noteTags?.length) {
if (!noteTags?.length && !isScamToken) {
return null;
}
return (
<Flex flexDir="column" gap={ 3 } className={ className }>
{ noteTags.map((noteTag) => (
{ isScamToken && (
<Alert status="error">
This token has been flagged as a potential scam.
</Alert>
) }
{ noteTags?.map((noteTag) => (
<Alert
key={ noteTag.name }
status={ noteTag.meta?.alertStatus as AlertProps['status'] ?? 'error' }
@@ -44,4 +50,4 @@ const AddressMetadataAlert = ({ tags, className }: Props) => {
);
};
export default React.memo(chakra(AddressMetadataAlert));
export default React.memo(chakra(AddressAlerts));
@@ -1,12 +0,0 @@
import React from 'react';
import * as metadataMock from 'mocks/metadata/address';
import { test, expect } from 'playwright/lib';
import AddressMetadataAlert from './AddressMetadataAlert';
test('base view', async({ render }) => {
const component = await render(<AddressMetadataAlert tags={ [ metadataMock.noteTag, metadataMock.noteTag2 ] }/>);
await expect(component).toHaveScreenshot();
});
Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

@@ -126,6 +126,7 @@ const CrossChainTxsTableItem = ({ item, isLoading, animation, currencySymbol, cu
icon_url: '',
name: '',
symbol: 'TBD',
reputation: null,
}}
noCopy
onlySymbol
+2 -2
View File
@@ -41,8 +41,8 @@ import AddressUserOps from 'ui/address/AddressUserOps';
import AddressWithdrawals from 'ui/address/AddressWithdrawals';
import AddressClusters from 'ui/address/clusters/AddressClusters';
import { CONTRACT_TAB_IDS } from 'ui/address/contract/utils';
import AddressAlerts from 'ui/address/details/AddressAlerts';
import AddressFavoriteButton from 'ui/address/details/AddressFavoriteButton';
import AddressMetadataAlert from 'ui/address/details/AddressMetadataAlert';
import AddressQrCode from 'ui/address/details/AddressQrCode';
import AddressEnsDomains from 'ui/address/ensDomains/AddressEnsDomains';
import SolidityscanReport from 'ui/address/SolidityscanReport';
@@ -468,7 +468,7 @@ const AddressPageContent = () => {
isLoading={ isLoading }
/>
{ !addressMetadataQuery.isPending &&
<AddressMetadataAlert tags={ addressMetadataQuery.data?.addresses?.[hash.toLowerCase()]?.tags } mt="-4px" mb={ 6 }/> }
<AddressAlerts tags={ addressMetadataQuery.data?.addresses?.[hash.toLowerCase()]?.tags } mt="-4px" mb={ 6 }/> }
{ config.features.metasuites.isEnabled && <Box display="none" id="meta-suites__address" data-ready={ !isLoading }/> }
<RoutedTabs tabs={ tabs } isLoading={ isTabsLoading }/>
</>
+16
View File
@@ -92,6 +92,22 @@ test('bridged token', async({ render, page, createSocket, mockApiResponse, mockA
});
});
test('scam token', async({ render, page, createSocket, mockApiResponse, mockEnvs }) => {
await mockEnvs([
[ 'NEXT_PUBLIC_VIEWS_TOKEN_SCAM_TOGGLE_ENABLED', 'true' ],
]);
await mockApiResponse('general:token', { ...tokenInfo, reputation: 'scam' }, { pathParams: { hash } });
const component = await render(<Token/>, { hooksConfig }, { withSocket: true });
const socket = await createSocket();
await socketServer.joinChannel(socket, `tokens:${ hash }`);
await expect(component).toHaveScreenshot({
mask: [ page.locator(pwConfig.adsBannerSelector) ],
maskColor: pwConfig.maskColor,
});
});
test.describe('mobile', () => {
test.use({ viewport: devices['iPhone 13 Pro'].viewport });
Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

+2
View File
@@ -29,6 +29,7 @@ const PoolInfo = ({ data, isPlaceholderData }: Props) => {
name: data.base_token_symbol,
symbol: data.base_token_symbol,
icon_url: data.base_token_icon_url,
reputation: null,
}}
isLoading={ isPlaceholderData }
/>
@@ -48,6 +49,7 @@ const PoolInfo = ({ data, isPlaceholderData }: Props) => {
name: data.quote_token_symbol,
symbol: data.quote_token_symbol,
icon_url: data.quote_token_icon_url,
reputation: null,
}}
isLoading={ isPlaceholderData }
/>
@@ -83,6 +83,7 @@ const SearchResultListItem = ({ data, searchTerm, isLoading, addressFormat }: Pr
</Link>
{ data.certified && <ContractCertifiedLabel iconSize={ 4 } boxSize={ 4 } ml={ 1 }/> }
{ data.is_verified_via_admin_panel && !data.certified && <IconSvg name="certified" boxSize={ 4 } ml={ 1 } color="green.500"/> }
{ data.reputation && <TokenEntity.Reputation token={{ ...data, type: data.token_type }}/> }
</Flex>
);
}
@@ -86,6 +86,7 @@ const SearchResultTableItem = ({ data, searchTerm, isLoading, addressFormat }: P
</Link>
{ data.certified && <ContractCertifiedLabel iconSize={ 4 } boxSize={ 4 } ml={ 1 }/> }
{ data.is_verified_via_admin_panel && !data.certified && <IconSvg name="certified" boxSize={ 4 } ml={ 1 } color="green.500"/> }
{ data.reputation && <TokenEntity.Reputation token={{ ...data, type: data.token_type }}/> }
</Flex>
</TableCell>
<TableCell verticalAlign="middle">
+1
View File
@@ -23,6 +23,7 @@ const DefaultView = () => {
exchange_rate: null,
total_supply: null,
icon_url: 'https://example.com/logo.png',
reputation: 'ok',
};
const contentAfter = (
@@ -23,6 +23,7 @@ const LongNameAndManyTags = () => {
symbol: 'BatcoiRing ding ding daa baa Baa aramba baa bom baa barooumba Wh-wha-what&#39;s going on-on? Ding, ding This is the Crazy Frog Ding, ding Bem, bem! Ring ding ding ding ding ding Ring ding ding ding bem bem bem Ring ding ding ding ding ding Ring ding ding ding',
total_supply: '13747',
type: 'ERC-721',
reputation: 'ok',
};
const contentAfter = (
+2
View File
@@ -50,6 +50,7 @@ const Icon = (props: IconProps) => {
address_hash: props.pool.base_token_address,
name: '',
type: 'ERC-20',
reputation: null,
}}
isLoading={ props.isLoading }
/>
@@ -70,6 +71,7 @@ const Icon = (props: IconProps) => {
address_hash: props.pool.quote_token_address,
name: '',
type: 'ERC-20',
reputation: null,
}}
isLoading={ props.isLoading }
/>
@@ -40,6 +40,7 @@ test.describe('variant', () => {
symbol: 'DUCK DUCK DUCK',
address_hash: tokenMock.tokenInfo.address_hash,
icon_url: LOGO_URL,
reputation: 'ok',
}}
chain={ opSuperchainMock.chainDataA }
/>,
@@ -83,6 +84,7 @@ test('with logo, long name and symbol', async({ page, render }) => {
symbol: 'DUCK DUCK DUCK',
address_hash: tokenMock.tokenInfo.address_hash,
icon_url: LOGO_URL,
reputation: 'ok',
}}
/>,
);
@@ -94,6 +96,34 @@ test('with logo, long name and symbol', async({ page, render }) => {
await expect(page).toHaveScreenshot();
});
test('scam token', async({ page, render, mockEnvs }) => {
await mockEnvs([
[ 'NEXT_PUBLIC_VIEWS_TOKEN_SCAM_TOGGLE_ENABLED', 'true' ],
]);
const LOGO_URL = 'https://example.com/logo.png';
await page.route(LOGO_URL, (route) => {
return route.fulfill({
status: 200,
path: './playwright/mocks/image_s.jpg',
});
});
await render(
<TokenEntity
token={{
type: 'ERC-20',
name: 'Duck Token',
symbol: 'DUCK',
address_hash: tokenMock.tokenInfo.address_hash,
icon_url: LOGO_URL,
reputation: 'scam',
}}
/>,
);
await expect(page).toHaveScreenshot();
});
test('loading', async({ render }) => {
const component = await render(
<TokenEntity
+17 -1
View File
@@ -5,12 +5,15 @@ import type { TokenInfo } from 'types/api/token';
import { route } from 'nextjs/routes';
import config from 'configs/app';
import { useMultichainContext } from 'lib/contexts/multichain';
import getChainTooltipText from 'lib/multichain/getChainTooltipText';
import getIconUrl from 'lib/multichain/getIconUrl';
import { Skeleton } from 'toolkit/chakra/skeleton';
import { Tooltip } from 'toolkit/chakra/tooltip';
import { TruncatedTextTooltip } from 'toolkit/components/truncation/TruncatedTextTooltip';
import * as EntityBase from 'ui/shared/entities/base/components';
import IconSvg from 'ui/shared/IconSvg';
import TokenLogoPlaceholder from 'ui/shared/TokenLogoPlaceholder';
import { distributeEntityProps, getIconProps } from '../base/utils';
@@ -125,8 +128,20 @@ const Copy = (props: CopyProps) => {
const Container = EntityBase.Container;
export const Reputation = (props: Pick<EntityProps, 'token'>) => {
if (config.UI.views.token.hideScamTokensEnabled && props.token.reputation === 'scam') {
return (
<Tooltip content="This token has been flagged as a potential scam. You enabled the display of flagged tokens in the explorer — proceed with caution.">
<IconSvg name="scam" boxSize={ 5 } ml={ 2 }/>
</Tooltip>
);
}
return null;
};
export interface EntityProps extends EntityBase.EntityBaseProps {
token: Pick<TokenInfo, 'address_hash' | 'icon_url' | 'name' | 'symbol' | 'type'>;
token: Pick<TokenInfo, 'address_hash' | 'icon_url' | 'name' | 'symbol' | 'type' | 'reputation'>;
noSymbol?: boolean;
jointSymbol?: boolean;
onlySymbol?: boolean;
@@ -144,6 +159,7 @@ const TokenEntity = (props: EntityProps) => {
{ props.noLink ? content : <Link { ...partsProps.link }>{ content }</Link> }
<Symbol { ...partsProps.symbol }/>
<Copy { ...partsProps.copy }/>
<Reputation token={ props.token }/>
</Container>
);
};
Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

+1
View File
@@ -32,6 +32,7 @@ const TOKEN = {
total_supply: '76923002799740785',
type: 'ERC-20' as const,
volume_24h: '82069586622.4918',
reputation: 'ok' as const,
};
const LinkShowcase = () => {
@@ -53,6 +53,7 @@ const SearchBarSuggestToken = ({ data, isMobile, searchTerm, addressFormat }: It
{ name }
{ data.certified && certifiedIcon }
{ data.is_verified_via_admin_panel && !data.certified && verifiedIcon }
{ data.reputation && <TokenEntity.Reputation token={{ ...data, type: data.token_type }}/> }
</Flex>
<Grid templateColumns={ templateCols } alignItems="center" gap={ 2 }>
<Flex alignItems="center" overflow="hidden">
@@ -72,6 +73,7 @@ const SearchBarSuggestToken = ({ data, isMobile, searchTerm, addressFormat }: It
{ name }
{ data.certified && certifiedIcon }
{ data.is_verified_via_admin_panel && !data.certified && verifiedIcon }
{ data.reputation && <TokenEntity.Reputation token={{ ...data, type: data.token_type }}/> }
</Flex>
<Flex alignItems="center" overflow="hidden">
{ address }
+10 -3
View File
@@ -13,7 +13,7 @@ import useApiQuery from 'lib/api/useApiQuery';
import { useMultichainContext } from 'lib/contexts/multichain';
import { getTokenTypeName } from 'lib/token/tokenTypes';
import { Tooltip } from 'toolkit/chakra/tooltip';
import AddressMetadataAlert from 'ui/address/details/AddressMetadataAlert';
import AddressAlerts from 'ui/address/details/AddressAlerts';
import AddressQrCode from 'ui/address/details/AddressQrCode';
import AccountActionsMenu from 'ui/shared/AccountActionsMenu/AccountActionsMenu';
import AddressAddToWallet from 'ui/shared/address/AddressAddToWallet';
@@ -92,6 +92,7 @@ const TokenPageTitle = ({ tokenQuery, addressQuery, hash }: Props) => {
const contentAfter = (
<>
{ tokenQuery.data && <TokenEntity.Reputation token={ tokenQuery.data }/> }
{ verifiedInfoQuery.data?.tokenAddress && (
<Tooltip content={ `Information on this token has been verified by ${ config.chain.name }` }>
<IconSvg name="certified" color="green.500" boxSize={ 6 } cursor="pointer"/>
@@ -144,8 +145,14 @@ const TokenPageTitle = ({ tokenQuery, addressQuery, hash }: Props) => {
contentAfter={ contentAfter }
secondRow={ secondRow }
/>
{ !addressMetadataQuery.isPending &&
<AddressMetadataAlert tags={ addressMetadataQuery.data?.addresses?.[hash.toLowerCase()]?.tags } mt="-4px" mb={ 6 }/> }
{ !addressMetadataQuery.isPending && (
<AddressAlerts
tags={ addressMetadataQuery.data?.addresses?.[hash.toLowerCase()]?.tags }
isScamToken={ tokenQuery.data?.reputation === 'scam' }
mt="-4px"
mb={ 6 }
/>
) }
</>
);
};
@@ -29,6 +29,7 @@ const NovesActionSnippet: FC<Props> = ({ item, isLoaded }) => {
address_hash: action.nft?.address || action.token?.address || '',
icon_url: '',
type: action.nft ? 'ERC-721' as const : 'ERC-20' as const,
reputation: null,
};
return token;
@@ -44,6 +44,7 @@ const TxDetailsAction = ({ action }: Props) => {
type: 'ERC-20' as const,
symbol: null,
icon_url: null,
reputation: null,
};
const token1 = {
address_hash: data.symbol1 === 'Ether' ? '' : data.address1,
@@ -51,6 +52,7 @@ const TxDetailsAction = ({ action }: Props) => {
type: 'ERC-20' as const,
symbol: null,
icon_url: null,
reputation: null,
};
return (
@@ -102,6 +104,7 @@ const TxDetailsAction = ({ action }: Props) => {
type: 'ERC-20' as const,
symbol: null,
icon_url: null,
reputation: null,
};
return (
@@ -31,6 +31,7 @@ const ArbitrumL2TxnWithdrawalsValue = ({ data }: Props) => {
total_supply: null,
circulating_market_cap: null,
icon_url: null,
reputation: null,
};
return (
@@ -56,6 +56,7 @@ const VerifiedAddressesListItem = ({ item, application, onAdd, onEdit, isLoading
address_hash: application.tokenAddress,
name: item.metadata.tokenName,
symbol: '',
reputation: null,
};
return (
@@ -57,6 +57,7 @@ const VerifiedAddressesTableItem = ({ item, application, onAdd, onEdit, isLoadin
address_hash: application.tokenAddress,
name: item.metadata.tokenName,
symbol: '',
reputation: null,
};
return (
@@ -21,6 +21,7 @@ const WatchListAddressItem = ({ item, isLoading }: { item: WatchlistAddress; isL
symbol: '',
address_hash: '',
type: 'ERC-20' as const,
reputation: null,
}), [ ]);
const { usdBn: usdNative } = getCurrencyValue({ value: item.address_balance, accuracy: 2, accuracyUsd: 2, exchangeRate: item.exchange_rate });
@@ -112,6 +112,7 @@ const ZetaChainAssetFilter = ({ value = null, handleFilterChange }: Props) => {
holders_count: null,
exchange_rate: null,
circulating_market_cap: null,
reputation: null,
} : token;
setCurrentValue(tokenInfo);
const filterParams = getFilterParamsFromValue(tokenInfo);
@@ -98,6 +98,7 @@ const ZetaChainFilterByColumn = ({ column, filters, columnName, handleFilterChan
holders_count: null,
exchange_rate: null,
circulating_market_cap: null,
reputation: null,
};
}