Commit bd516d97 authored by Igor Stuev's avatar Igor Stuev Committed by GitHub

Merge pull request #786 from blockscout/token/add-to-custom-wallet

add network to wallet
parents c48ad815 68176c65
......@@ -44,6 +44,8 @@ NEXT_PUBLIC_HOMEPAGE_SHOW_AVG_BLOCK_TIME=__PLACEHOLDER_FOR_NEXT_PUBLIC_HOMEPAGE_
NEXT_PUBLIC_AD_DOMAIN_WITH_AD=__PLACEHOLDER_FOR_NEXT_PUBLIC_AD_DOMAIN_WITH_AD__
NEXT_PUBLIC_AD_ADBUTLER_ON=__PLACEHOLDER_FOR_NEXT_PUBLIC_AD_ADBUTLER_ON__
NEXT_PUBLIC_GRAPHIQL_TRANSACTION=__PLACEHOLDER_FOR_NEXT_PUBLIC_GRAPHIQL_TRANSACTION__
NEXT_PUBLIC_WEB3_DEFAULT_WALLET=__PLACEHOLDER_FOR_NEXT_PUBLIC_WEB3_DEFAULT_WALLET__
NEXT_PUBLIC_WEB3_DISABLE_ADD_TOKEN_TO_WALLET=__PLACEHOLDER_FOR_NEXT_PUBLIC_WEB3_DISABLE_ADD_TOKEN_TO_WALLET__
# api config
NEXT_PUBLIC_API_HOST=__PLACEHOLDER_FOR_NEXT_PUBLIC_API_HOST__
......
......@@ -68,7 +68,7 @@
},
{
"type": "shell",
"command": "NEXT_PUBLIC_L1_BASE_URL=https://${input:goerliApiHost} yarn dev:goerli:optimism",
"command": "NEXT_PUBLIC_API_HOST=${input:L2ApiHost} NEXT_PUBLIC_L1_BASE_URL=https://${input:goerliApiHost} yarn dev:goerli:optimism",
"problemMatcher": [],
"label": "dev server: goerli optimism",
"detail": "start local dev server for Goerli Optimism network",
......@@ -379,5 +379,15 @@
],
"default": ""
},
{
"type": "pickString",
"id": "L2ApiHost",
"description": "Choose L2 API host:",
"options": [
"blockscout-optimism-goerli.test.aws-k8s.blockscout.com",
"base-goerli.blockscout.com",
],
"default": ""
},
],
}
\ No newline at end of file
/* eslint-disable no-restricted-properties */
import type { WalletType } from 'types/client/wallets';
import type { NetworkExplorer } from 'types/networks';
import type { ChainIndicatorId } from 'ui/home/indicators/types';
......@@ -11,6 +12,15 @@ const parseEnvJson = <DataType>(env: string | undefined): DataType | null => {
}
};
const stripTrailingSlash = (str: string) => str[str.length - 1] === '/' ? str.slice(0, -1) : str;
const getWeb3DefaultWallet = (): WalletType => {
const envValue = getEnvValue(process.env.NEXT_PUBLIC_WEB3_DEFAULT_WALLET);
const SUPPORTED_WALLETS: Array<WalletType> = [
'metamask',
'coinbase',
];
return (envValue && SUPPORTED_WALLETS.includes(envValue) ? envValue : 'metamask') as WalletType;
};
const env = process.env.NODE_ENV;
const isDev = env === 'development';
......@@ -103,6 +113,10 @@ const config = Object.freeze({
domainWithAd: getEnvValue(process.env.NEXT_PUBLIC_AD_DOMAIN_WITH_AD) || 'blockscout.com',
adButlerOn: getEnvValue(process.env.NEXT_PUBLIC_AD_ADBUTLER_ON) === 'true',
},
web3: {
defaultWallet: getWeb3DefaultWallet(),
disableAddTokenToWallet: getEnvValue(process.env.NEXT_PUBLIC_WEB3_DISABLE_ADD_TOKEN_TO_WALLET) === 'true',
},
api: {
host: apiHost,
endpoint: apiEndpoint,
......
......@@ -3,6 +3,8 @@ NEXT_PUBLIC_FEATURED_NETWORKS=https://raw.githubusercontent.com/blockscout/front
NEXT_PUBLIC_NETWORK_EXPLORERS=
NEXT_PUBLIC_HOMEPAGE_PLATE_GRADIENT=linear-gradient(136.9deg,rgb(107 94 236) 1.5%,rgb(0 82 255) 56.84%,rgb(82 62 231) 98.54%)
NEXT_PUBLIC_GRAPHIQL_TRANSACTION=0x4a0ed8ddf751a7cb5297f827699117b0f6d21a0b2907594d300dc9fed75c7e62
NEXT_PUBLIC_WEB3_DEFAULT_WALLET=coinbase
NEXT_PUBLIC_WEB3_DISABLE_ADD_TOKEN_TO_WALLET=true
# network config
NEXT_PUBLIC_NETWORK_NAME=Base Göerli
......@@ -10,14 +12,14 @@ NEXT_PUBLIC_NETWORK_SHORT_NAME=Base
NEXT_PUBLIC_NETWORK_ASSETS_PATHNAME=optimism
NEXT_PUBLIC_NETWORK_LOGO=https://raw.githubusercontent.com/blockscout/frontend-configs/dev/configs/network-logos/base.svg
NEXT_PUBLIC_NETWORK_ICON=https://raw.githubusercontent.com/blockscout/frontend-configs/dev/configs/network-icons/base.svg
NEXT_PUBLIC_NETWORK_ID=420
NEXT_PUBLIC_NETWORK_ID=84531
NEXT_PUBLIC_NETWORK_CURRENCY_NAME=Ether
NEXT_PUBLIC_NETWORK_CURRENCY_SYMBOL=ETH
NEXT_PUBLIC_NETWORK_CURRENCY_DECIMALS=18
NEXT_PUBLIC_NETWORK_TOKEN_ADDRESS=
NEXT_PUBLIC_IS_ACCOUNT_SUPPORTED=true
NEXT_PUBLIC_NETWORK_VERIFICATION_TYPE=validation
NEXT_PUBLIC_NETWORK_RPC_URL=https://goerli.optimism.io
NEXT_PUBLIC_NETWORK_RPC_URL=https://goerli.base.org
NEXT_PUBLIC_MARKETPLACE_CONFIG_URL=https://raw.githubusercontent.com/blockscout/frontend-configs/dev/configs/marketplace/base-goerli.json
NEXT_PUBLIC_MARKETPLACE_SUBMIT_FORM=https://airtable.com/shrqUAcjgGJ4jU88C
NEXT_PUBLIC_HOMEPAGE_CHARTS=['daily_txs']
......
......@@ -391,6 +391,10 @@ frontend:
_default: ''
NEXT_PUBLIC_NETWORK_RPC_URL:
_default: https://goerli.optimism.io
NEXT_PUBLIC_WEB3_DEFAULT_WALLET:
_default: coinbase
NEXT_PUBLIC_WEB3_DISABLE_ADD_TOKEN_TO_WALLET:
_default: true
NEXT_PUBLIC_HOMEPAGE_CHARTS:
_default: "['daily_txs']"
NEXT_PUBLIC_IS_TESTNET:
......
......@@ -119,6 +119,10 @@ frontend:
_default: ''
NEXT_PUBLIC_NETWORK_RPC_URL:
_default: https://goerli.optimism.io
NEXT_PUBLIC_WEB3_DEFAULT_WALLET:
_default: coinbase
NEXT_PUBLIC_WEB3_DISABLE_ADD_TOKEN_TO_WALLET:
_default: true
NEXT_PUBLIC_HOMEPAGE_CHARTS:
_default: "['daily_txs']"
NEXT_PUBLIC_IS_TESTNET:
......
......@@ -50,6 +50,8 @@ The app instance could be customized by passing following variables to NodeJS en
| NEXT_PUBLIC_AD_ADBUTLER_ON | `boolean` | Set to true to show Adbutler banner instead of Coinzilla banner | - | `false` | `true` |
| NEXT_PUBLIC_API_SPEC_URL | `string` | Spec to be displayed on api-docs page | - | - | `https://raw.githubusercontent.com/blockscout/blockscout-api-v2-swagger/main/swagger.yaml` |
| NEXT_PUBLIC_GRAPHIQL_TRANSACTION | `string` | Txn hash for default query at GraphQl playground page | - | - | `0x69e3923eef50eada197c3336d546936d0c994211492c9f947a24c02827568f9f` |
| NEXT_PUBLIC_WEB3_DEFAULT_WALLET | `metamask` \| `coinbase`| Type of Web3 wallet which will be used by default to add tokens or chains to | - | `metamask` | `coinbase` |
| NEXT_PUBLIC_WEB3_DISABLE_ADD_TOKEN_TO_WALLET | `boolean`| Set to `true` to hide icon "Add to your wallet" next to token addresses | - | `false` | `true` |
### Marketplace app configuration properties
......
import type { MetaMaskInpageProvider } from '@metamask/providers';
import type { ExternalProvider } from 'types/client/wallets';
type CPreferences = {
zone: string;
......@@ -7,8 +7,10 @@ type CPreferences = {
}
declare global {
interface Window {
ethereum: MetaMaskInpageProvider;
export interface Window {
ethereum?: {
providers?: Array<ExternalProvider>;
};
coinzilla_display: Array<CPreferences>;
}
}
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 2500 2500">
<rect fill="none"/>
<path fill-rule="evenodd" clip-rule="evenodd" fill="#0052FF" d="M520.7 0h1458.5C2266.9 0 2500 250.8 2500 560.2v1379.6c0 309.4-233.1 560.2-520.7 560.2H520.7C233.1 2500 0 2249.2 0 1939.8V560.2C0 250.8 233.1 0 520.7 0z"/>
<path fill-rule="evenodd" clip-rule="evenodd" fill="#FFF" d="M1250 362.1c490.4 0 887.9 397.5 887.9 887.9s-397.5 887.9-887.9 887.9-887.9-397.5-887.9-887.9S759.6 362.1 1250 362.1z"/>
<path fill-rule="evenodd" clip-rule="evenodd" fill="#0052FF" d="M1031.3 966.2h437.3c36 0 65.1 31.4 65.1 70v427.5c0 38.7-29.2 70-65.1 70h-437.3c-36 0-65.1-31.4-65.1-70v-427.5c0-38.6 29.2-70 65.1-70z"/>
</svg>
import React from 'react';
import type { ExternalProvider } from 'types/client/wallets';
import appConfig from 'configs/app/config';
export default function useProvider() {
const [ provider, setProvider ] = React.useState<ExternalProvider>();
React.useEffect(() => {
if (!('ethereum' in window)) {
return;
}
window.ethereum?.providers?.forEach(async(provider) => {
if (appConfig.web3.defaultWallet === 'coinbase' && provider.isCoinbaseWallet) {
return setProvider(provider);
}
if (appConfig.web3.defaultWallet === 'metamask' && provider.isMetaMask) {
return setProvider(provider);
}
});
}, []);
return provider;
}
import type { WalletType, WalletInfo } from 'types/client/wallets';
import coinbaseIcon from 'icons/wallets/coinbase.svg';
import metamaskIcon from 'icons/wallets/metamask.svg';
export const WALLETS_INFO: Record<WalletType, WalletInfo> = {
metamask: {
add_token_text: 'Add token to MetaMask',
add_network_text: 'Add network to MetaMask',
icon: metamaskIcon,
},
coinbase: {
add_token_text: 'Add token to Coinbase Wallet',
add_network_text: 'Add network to Coinbase Wallet',
icon: coinbaseIcon,
},
};
import type { providers } from 'ethers';
export type WalletType = 'metamask' | 'coinbase';
export interface WalletInfo {
add_token_text: string;
add_network_text: string;
icon: React.ElementType;
}
export interface ExternalProvider extends providers.ExternalProvider {
isCoinbaseWallet?: boolean;
// have to patch ethers here, since params could be not only an array
// eslint-disable-next-line @typescript-eslint/no-explicit-any
request?: (request: { method: string; params?: any }) => Promise<any>;
}
import type { MetaMaskInpageProvider } from '@metamask/providers';
import { test, expect } from '@playwright/experimental-ct-react';
import type { UseQueryResult } from '@tanstack/react-query';
import React from 'react';
......@@ -73,7 +72,9 @@ test('token', async({ mount, page }) => {
}), { times: 1 });
await page.evaluate(() => {
window.ethereum = { } as MetaMaskInpageProvider;
window.ethereum = {
providers: [ { isMetaMask: true } ],
};
});
const component = await mount(
......
......@@ -4,13 +4,12 @@ import React from 'react';
import type { AddressTokenBalance } from 'types/api/address';
import getCurrencyValue from 'lib/getCurrencyValue';
import AddressAddToWallet from 'ui/shared/address/AddressAddToWallet';
import AddressLink from 'ui/shared/address/AddressLink';
import CopyToClipboard from 'ui/shared/CopyToClipboard';
import ListItemMobile from 'ui/shared/ListItemMobile/ListItemMobile';
import TokenLogo from 'ui/shared/TokenLogo';
import AddressAddToMetaMask from '../details/AddressAddToMetaMask';
type Props = AddressTokenBalance;
const TokensListItem = ({ token, value }: Props) => {
......@@ -31,7 +30,7 @@ const TokensListItem = ({ token, value }: Props) => {
<Flex alignItems="center" pl={ 8 }>
<AddressLink hash={ token.address } type="address" truncation="constant"/>
<CopyToClipboard text={ token.address } ml={ 1 }/>
<AddressAddToMetaMask token={ token } ml={ 2 }/>
<AddressAddToWallet token={ token } ml={ 2 }/>
</Flex>
{ token.exchange_rate !== undefined && token.exchange_rate !== null && (
<HStack spacing={ 3 }>
......
......@@ -4,12 +4,11 @@ import React from 'react';
import type { AddressTokenBalance } from 'types/api/address';
import getCurrencyValue from 'lib/getCurrencyValue';
import AddressAddToWallet from 'ui/shared/address/AddressAddToWallet';
import AddressLink from 'ui/shared/address/AddressLink';
import CopyToClipboard from 'ui/shared/CopyToClipboard';
import TokenLogo from 'ui/shared/TokenLogo';
import AddressAddToMetaMask from '../details/AddressAddToMetaMask';
type Props = AddressTokenBalance;
const TokensTableItem = ({
......@@ -38,7 +37,7 @@ const TokensTableItem = ({
<AddressLink hash={ token.address } type="address" truncation="constant"/>
<CopyToClipboard text={ token.address } ml={ 1 }/>
</Flex>
<AddressAddToMetaMask token={ token } ml={ 4 }/>
<AddressAddToWallet token={ token } ml={ 4 }/>
</Flex>
</Td>
<Td isNumeric verticalAlign="middle">
......
......@@ -6,9 +6,9 @@ import type { TokenInfo } from 'types/api/token';
import config from 'configs/app/config';
import useIsMobile from 'lib/hooks/useIsMobile';
import AddressAddToMetaMask from 'ui/address/details/AddressAddToMetaMask';
import AddressFavoriteButton from 'ui/address/details/AddressFavoriteButton';
import AddressQrCode from 'ui/address/details/AddressQrCode';
import AddressAddToWallet from 'ui/shared/address/AddressAddToWallet';
import AddressIcon from 'ui/shared/address/AddressIcon';
import AddressLink from 'ui/shared/address/AddressLink';
import CopyToClipboard from 'ui/shared/CopyToClipboard';
......@@ -35,7 +35,7 @@ const AddressHeadingInfo = ({ address, token, isLinkDisabled }: Props) => {
isDisabled={ isLinkDisabled }
/>
<CopyToClipboard text={ address.hash }/>
{ address.is_contract && token && <AddressAddToMetaMask ml={ 2 } token={ token }/> }
{ address.is_contract && token && <AddressAddToWallet ml={ 2 } token={ token }/> }
{ !address.is_contract && config.isAccountSupported && (
<AddressFavoriteButton hash={ address.hash } watchListId={ address.watchlist_address_id } ml={ 3 }/>
) }
......
import { Box, Icon, Tooltip, chakra } from '@chakra-ui/react';
import React from 'react';
import appConfig from 'configs/app/config';
import useToast from 'lib/hooks/useToast';
import useProvider from 'lib/web3/useProvider';
import { WALLETS_INFO } from 'lib/web3/wallets';
interface Props {
className?: string;
}
const NetworkAddToWallet = ({ className }: Props) => {
const toast = useToast();
const provider = useProvider();
const handleClick = React.useCallback(async() => {
try {
const hexadecimalChainId = '0x' + Number(appConfig.network.id).toString(16);
const config = {
method: 'wallet_addEthereumChain',
params: [ {
chainId: hexadecimalChainId,
chainName: appConfig.network.name,
nativeCurrency: {
name: appConfig.network.currency.name,
symbol: appConfig.network.currency.symbol,
decimals: appConfig.network.currency.decimals,
},
rpcUrls: [ appConfig.network.rpcUrl ],
blockExplorerUrls: [ appConfig.baseUrl ],
} ],
};
await provider?.request?.(config);
toast({
position: 'top-right',
title: 'Success',
description: 'Successfully added network to your wallet',
status: 'success',
variant: 'subtle',
isClosable: true,
});
} catch (error) {
toast({
position: 'top-right',
title: 'Error',
description: (error as Error)?.message || 'Something went wrong',
status: 'error',
variant: 'subtle',
isClosable: true,
});
}
}, [ provider, toast ]);
if (!provider) {
return null;
}
const defaultWallet = appConfig.web3.defaultWallet;
return (
<Tooltip label={ WALLETS_INFO[defaultWallet].add_network_text }>
<Box className={ className } display="inline-flex" cursor="pointer" onClick={ handleClick }>
<Icon as={ WALLETS_INFO[defaultWallet].icon } boxSize={ 5 }/>
</Box>
</Tooltip>
);
};
export default React.memo(chakra(NetworkAddToWallet));
......@@ -3,20 +3,23 @@ import React from 'react';
import type { TokenInfo } from 'types/api/token';
import metamaskIcon from 'icons/metamask.svg';
import appConfig from 'configs/app/config';
import useToast from 'lib/hooks/useToast';
import useProvider from 'lib/web3/useProvider';
import { WALLETS_INFO } from 'lib/web3/wallets';
interface Props {
className?: string;
token: TokenInfo;
}
const AddressAddToMetaMask = ({ className, token }: Props) => {
const AddressAddToWallet = ({ className, token }: Props) => {
const toast = useToast();
const provider = useProvider();
const handleClick = React.useCallback(async() => {
try {
const wasAdded = await window.ethereum.request?.({
const wasAdded = await provider?.request?.({
method: 'wallet_watchAsset',
params: {
type: 'ERC20', // Initially only supports ERC20, but eventually more!
......@@ -24,6 +27,8 @@ const AddressAddToMetaMask = ({ className, token }: Props) => {
address: token.address,
symbol: token.symbol,
decimals: Number(token.decimals) || 18,
// TODO: add token image when we have it in API
// image: ''
},
},
});
......@@ -32,7 +37,7 @@ const AddressAddToMetaMask = ({ className, token }: Props) => {
toast({
position: 'top-right',
title: 'Success',
description: 'Successfully added token to MetaMask',
description: 'Successfully added token to your wallet',
status: 'success',
variant: 'subtle',
isClosable: true,
......@@ -48,19 +53,21 @@ const AddressAddToMetaMask = ({ className, token }: Props) => {
isClosable: true,
});
}
}, [ toast, token ]);
}, [ toast, token, provider ]);
if (!('ethereum' in window)) {
if (!provider) {
return null;
}
const defaultWallet = appConfig.web3.defaultWallet;
return (
<Tooltip label="Add token to MetaMask">
<Tooltip label={ WALLETS_INFO[defaultWallet].add_token_text }>
<Box className={ className } display="inline-flex" cursor="pointer" onClick={ handleClick }>
<Icon as={ metamaskIcon } boxSize={ 6 }/>
<Icon as={ WALLETS_INFO[defaultWallet].icon } boxSize={ 6 }/>
</Box>
</Tooltip>
);
};
export default React.memo(chakra(AddressAddToMetaMask));
export default React.memo(chakra(AddressAddToWallet));
import { Box, VStack, Text, Stack, Icon, Link } from '@chakra-ui/react';
import { Box, Text, Stack, Icon, Link, VStack } from '@chakra-ui/react';
import React from 'react';
import appConfig from 'configs/app/config';
......@@ -7,6 +7,7 @@ import statsIcon from 'icons/social/stats.svg';
import tgIcon from 'icons/social/telega.svg';
import twIcon from 'icons/social/tweet.svg';
import getDefaultTransitionProps from 'theme/utils/getDefaultTransitionProps';
import NetworkAddToWallet from 'ui/shared/NetworkAddToWallet';
const SOCIAL_LINKS = [
{ link: appConfig.footerLinks.github, icon: ghIcon, label: 'Github link' },
......@@ -35,11 +36,9 @@ const NavFooter = ({ isCollapsed, hasAccount }: Props) => {
return (
<VStack
as="footer"
spacing={ 8 }
borderTop="1px solid"
borderColor="divider"
width={{ base: '100%', lg: isExpanded ? '180px' : '20px', xl: isCollapsed ? '20px' : '180px' }}
paddingTop={{ base: 6, lg: 8 }}
marginTop={ marginTop }
alignItems="flex-start"
alignSelf="center"
......@@ -47,23 +46,28 @@ const NavFooter = ({ isCollapsed, hasAccount }: Props) => {
fontSize="xs"
{ ...getDefaultTransitionProps({ transitionProperty: 'width' }) }
>
{ SOCIAL_LINKS.length > 0 && (
<Stack direction={{ base: 'row', lg: isExpanded ? 'row' : 'column', xl: isCollapsed ? 'column' : 'row' }}>
{ SOCIAL_LINKS.map(sl => {
return (
<Link href={ sl.link } key={ sl.link } variant="secondary" w={ 5 } h={ 5 } aria-label={ sl.label } target="_blank">
<Icon as={ sl.icon } boxSize={ 5 }/>
</Link>
);
}) }
</Stack>
) }
<Stack
direction={{ base: 'row', lg: isExpanded ? 'row' : 'column', xl: isCollapsed ? 'column' : 'row' }}
mt={{ base: 6, lg: 8 }}
_empty={{
display: 'none',
}}
>
<NetworkAddToWallet/>
{ SOCIAL_LINKS.map(sl => {
return (
<Link href={ sl.link } key={ sl.link } variant="secondary" w={ 5 } h={ 5 } aria-label={ sl.label } target="_blank">
<Icon as={ sl.icon } boxSize={ 5 }/>
</Link>
);
}) }
</Stack>
<Box display={{ base: 'block', lg: isExpanded ? 'block' : 'none', xl: isCollapsed ? 'none' : 'block' }}>
<Text variant="secondary" mb={ 8 }>
<Text variant="secondary" mt={ 8 }>
Blockscout is a tool for inspecting and analyzing EVM based blockchains. Blockchain explorer for Ethereum Networks.
</Text>
{ appConfig.blockScoutVersion &&
<Text variant="secondary">Version: <Link href={ VERSION_URL } target="_blank">{ appConfig.blockScoutVersion }</Link></Text> }
<Text variant="secondary" mt={ 8 }>Version: <Link href={ VERSION_URL } target="_blank">{ appConfig.blockScoutVersion }</Link></Text> }
</Box>
</VStack>
);
......
......@@ -26,7 +26,13 @@ const test = base.extend({
]) as any,
});
test('no auth +@desktop-xl +@dark-mode-xl', async({ mount }) => {
test('no auth +@desktop-xl +@dark-mode-xl', async({ page, mount }) => {
await page.evaluate(() => {
window.ethereum = {
providers: [ { isMetaMask: true } ],
};
});
const component = await mount(
<TestApp>
<Flex w="100%" minH="100vh" alignItems="stretch">
......
......@@ -4,7 +4,7 @@ import React from 'react';
import type { TokenInfo } from 'types/api/token';
import getCurrencyValue from 'lib/getCurrencyValue';
import AddressAddToMetaMask from 'ui/address/details/AddressAddToMetaMask';
import AddressAddToWallet from 'ui/shared/address/AddressAddToWallet';
import AddressLink from 'ui/shared/address/AddressLink';
import CopyToClipboard from 'ui/shared/CopyToClipboard';
import ListItemMobile from 'ui/shared/ListItemMobile/ListItemMobile';
......@@ -60,7 +60,7 @@ const TokensTableItem = ({
<AddressLink fontSize="sm" hash={ address } type="address" truncation="constant"/>
<CopyToClipboard text={ address } ml={ 1 }/>
</Flex>
<AddressAddToMetaMask token={ token }/>
<AddressAddToWallet token={ token }/>
</Flex>
</Flex>
{ exchangeRate && (
......
......@@ -4,7 +4,7 @@ import React from 'react';
import type { TokenInfo } from 'types/api/token';
import getCurrencyValue from 'lib/getCurrencyValue';
import AddressAddToMetaMask from 'ui/address/details/AddressAddToMetaMask';
import AddressAddToWallet from 'ui/shared/address/AddressAddToWallet';
import AddressLink from 'ui/shared/address/AddressLink';
import CopyToClipboard from 'ui/shared/CopyToClipboard';
import TokenLogo from 'ui/shared/TokenLogo';
......@@ -61,7 +61,7 @@ const TokensTableItem = ({
<AddressLink fontSize="sm" hash={ address } type="address" truncation="constant" fontWeight={ 500 }/>
<CopyToClipboard text={ address } ml={ 1 }/>
</Flex>
<AddressAddToMetaMask token={ token }/>
<AddressAddToWallet token={ token }/>
</Flex>
<Tag flexShrink={ 0 } ml={ 8 } mt={ 3 }>{ type }</Tag>
</Box>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment