Skip to content

Commit

Permalink
feat(suite): unrecognized token section in tokens
Browse files Browse the repository at this point in the history
  • Loading branch information
tomasklim committed Feb 6, 2024
1 parent 866109c commit 1546394
Show file tree
Hide file tree
Showing 2 changed files with 117 additions and 61 deletions.
177 changes: 116 additions & 61 deletions packages/suite/src/views/wallet/tokens/components/TokenList.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,20 @@
import { useMemo, Fragment } from 'react';
import styled, { css, useTheme } from 'styled-components';
import { variables, Icon, Card } from '@trezor/components';
import { FiatValue, FormattedCryptoAmount, TrezorLink } from 'src/components/suite';
import {
FiatValue,
FormattedCryptoAmount,
QuestionTooltip,
TrezorLink,
} from 'src/components/suite';
import { Account } from 'src/types/wallet';
import { useSelector } from 'src/hooks/suite';
import { enhanceTokensWithRates, sortTokensWithRates } from '@suite-common/wallet-utils';
import { selectCoinsLegacy } from '@suite-common/wallet-core';
import { selectCoinsLegacy, selectTokenDefinitions } from '@suite-common/wallet-core';
import { NoRatesTooltip } from 'src/components/suite/Ticker/NoRatesTooltip';
import { FiatRates, TokenInfo } from '@trezor/blockchain-link-types';
import { spacingsPx } from '@trezor/theme';
import { NetworkSymbol, getNetworkFeatures } from '@suite-common/wallet-config';

const Wrapper = styled(Card)<{ isTestnet?: boolean }>`
display: grid;
Expand Down Expand Up @@ -68,92 +76,139 @@ const StyledNoRatesTooltip = styled(NoRatesTooltip)`
justify-content: flex-end;
`;

const StyledQuestionTooltip = styled(QuestionTooltip)<{ addMarginTop: boolean }>`
${({ addMarginTop }) =>
addMarginTop &&
css`
margin-top: ${spacingsPx.xxl};
`}
margin-bottom: ${spacingsPx.sm};
`;

interface TokenListProps {
tokens: Account['tokens'];
networkType: Account['networkType'];
explorerUrl: string;
explorerUrlQueryString: string;
isTestnet?: boolean;
networkSymbol: NetworkSymbol;
}

type EnhancedTokenInfo = TokenInfo & { rates?: FiatRates };

export const TokenList = ({
tokens,
explorerUrl,
explorerUrlQueryString,
isTestnet,
networkType,
networkSymbol,
}: TokenListProps) => {
const theme = useTheme();
const coins = useSelector(selectCoinsLegacy);
const tokenDefinitions = useSelector(state => selectTokenDefinitions(state, networkSymbol));

const sortedTokens = useMemo(() => {
const sortedTokens: EnhancedTokenInfo[] = useMemo(() => {
const tokensWithRates = enhanceTokensWithRates(tokens, coins);

return tokensWithRates.sort(sortTokensWithRates);
}, [tokens, coins]);

if (!tokens || tokens.length === 0) return null;

const hasNetworkFeatures = getNetworkFeatures(networkSymbol).includes('token-definitions');
const { knownTokens, unknownTokens } = sortedTokens.reduce<{
knownTokens: EnhancedTokenInfo[];
unknownTokens: EnhancedTokenInfo[];
}>(
(acc, token) => {
if (tokenDefinitions[token.contract]?.isTokenKnown || !hasNetworkFeatures) {
acc.knownTokens.push(token);
} else {
acc.unknownTokens.push(token);
}
return acc;
},
{ knownTokens: [], unknownTokens: [] },
);

return (
<Wrapper isTestnet={isTestnet} paddingType="none">
{sortedTokens.map(t => {
// In Cardano token name is optional and in there is no symbol.
// However, if Cardano token doesn't have a name on blockchain, its TokenInfo has both name
// and symbol props set to a token fingerprint (done in blockchain-link) and we
// don't want to render it twice.
// In ethereum we are fine with rendering symbol - name even if they are the same.
const symbolMatchesName =
networkType === 'cardano' && t.symbol?.toLowerCase() === t.name?.toLowerCase();
const noSymbol = !t.symbol || symbolMatchesName;

const isTokenWithRate = Boolean(t.rates && Object.keys(t.rates).length);

return (
<Fragment key={t.contract}>
<Col isTestnet={isTestnet}>
{!noSymbol && <TokenSymbol>{t.symbol}</TokenSymbol>}
<TokenName>
{!noSymbol && ` - `}
{t.name}
</TokenName>
</Col>
<Col isTestnet={isTestnet} justify="right">
{t.balance && (
<CryptoAmount
value={t.balance}
symbol={networkType === 'cardano' ? undefined : t.symbol}
/>
)}
</Col>
{!isTestnet && (
<Col isTestnet={isTestnet} justify="right">
{t.balance && t.symbol && isTokenWithRate ? (
<FiatWrapper>
<FiatValue
amount={t.balance}
symbol={t.symbol}
tokenAddress={t.contract}
/>
</FiatWrapper>
) : (
<StyledNoRatesTooltip />
)}
</Col>
<>
{[knownTokens, unknownTokens].map((tokens, groupIndex) =>
tokens.length ? (
<Fragment key={groupIndex === 0 ? 'knownTokens' : 'unknownTokens'}>
{groupIndex === 1 && (
<StyledQuestionTooltip
label="TR_TOKEN_UNRECOGNIZED_BY_TREZOR"
tooltip="TR_TOKEN_UNRECOGNIZED_BY_TREZOR_TOOLTIP"
addMarginTop={!!knownTokens.length}
/>
)}
<Col isTestnet={isTestnet} justify="right">
<TrezorLink
href={`${explorerUrl}${t.contract}${explorerUrlQueryString}`}
>
<Icon
icon="EXTERNAL_LINK"
size={16}
color={theme.TYPE_LIGHT_GREY}
/>
</TrezorLink>
</Col>
<Wrapper isTestnet={isTestnet} paddingType="none">
{tokens.map(t => {
const symbolMatchesName =
networkType === 'cardano' &&
t.symbol?.toLowerCase() === t.name?.toLowerCase();
const noSymbol = !t.symbol || symbolMatchesName;

const isTokenWithRate = Boolean(
t.rates && Object.keys(t.rates).length,
);

return (
<Fragment key={t.contract}>
<Col isTestnet={isTestnet}>
{!noSymbol && <TokenSymbol>{t.symbol}</TokenSymbol>}
<TokenName>
{!noSymbol && ` - `}
{t.name}
</TokenName>
</Col>
<Col isTestnet={isTestnet} justify="right">
{t.balance && (
<CryptoAmount
value={t.balance}
symbol={
networkType === 'cardano'
? undefined
: t.symbol
}
/>
)}
</Col>
{!isTestnet && (
<Col isTestnet={isTestnet} justify="right">
{t.balance && t.symbol && isTokenWithRate ? (
<FiatWrapper>
<FiatValue
amount={t.balance}
symbol={t.symbol}
tokenAddress={t.contract}
/>
</FiatWrapper>
) : (
<StyledNoRatesTooltip />
)}
</Col>
)}
<Col isTestnet={isTestnet} justify="right">
<TrezorLink
href={`${explorerUrl}${t.contract}${explorerUrlQueryString}`}
>
<Icon
icon="EXTERNAL_LINK"
size={16}
color={theme.TYPE_LIGHT_GREY}
/>
</TrezorLink>
</Col>
</Fragment>
);
})}
</Wrapper>
</Fragment>
);
})}
</Wrapper>
) : null,
)}
</>
);
};
1 change: 1 addition & 0 deletions packages/suite/src/views/wallet/tokens/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export const Tokens = () => {
explorerUrlQueryString={explorerUrlQueryString}
tokens={account.tokens}
networkType={account.networkType}
networkSymbol={account.symbol}
/>
{!account.tokens?.length && <NoTokens />}
</WalletLayout>
Expand Down

0 comments on commit 1546394

Please sign in to comment.