import { Box, chakra } from '@chakra-ui/react';
import React from 'react';
import type { WatchAssetParams } from 'viem';
import type { TokenInfo } from 'types/api/token';
import config from 'configs/app';
import useIsMobile from 'lib/hooks/useIsMobile';
import useRewardsActivity from 'lib/hooks/useRewardsActivity';
import * as mixpanel from 'lib/mixpanel/index';
import useProvider from 'lib/web3/useProvider';
import useSwitchOrAddChain from 'lib/web3/useSwitchOrAddChain';
import { WALLETS_INFO } from 'lib/web3/wallets';
import { IconButton } from 'toolkit/chakra/icon-button';
import { Skeleton } from 'toolkit/chakra/skeleton';
import { toaster } from 'toolkit/chakra/toaster';
import { Tooltip } from 'toolkit/chakra/tooltip';
import IconSvg from 'ui/shared/IconSvg';
function getRequestParams(token: TokenInfo, tokenId?: string): WatchAssetParams | undefined {
switch (token.type) {
case 'ERC-20':
return {
type: 'ERC20',
options: {
address: token.address_hash,
symbol: token.symbol || '',
decimals: Number(token.decimals ?? '18'),
image: token.icon_url || '',
},
};
case 'ERC-721':
case 'ERC-1155': {
if (!tokenId) {
return;
}
return {
type: token.type === 'ERC-721' ? 'ERC721' : 'ERC1155',
options: {
address: token.address_hash,
tokenId: tokenId,
},
} as never; // There is no official EIP, and therefore no typings for these token types.
}
default:
return;
}
}
interface Props {
className?: string;
token: TokenInfo;
tokenId?: string;
isLoading?: boolean;
variant?: 'icon' | 'button';
iconSize?: number;
chainConfig?: typeof config;
}
const AddressAddToWallet = ({ className, token, tokenId, isLoading, variant = 'icon', iconSize = 6, chainConfig }: Props) => {
const { data: { wallet, provider } = {} } = useProvider();
const switchOrAddChain = useSwitchOrAddChain({ chainConfig });
const isMobile = useIsMobile();
const { trackUsage } = useRewardsActivity();
const feature = (chainConfig ?? config).features.web3Wallet;
const handleClick = React.useCallback(async() => {
if (!wallet) {
return;
}
try {
const params = getRequestParams(token, tokenId);
if (!params) {
throw new Error('Unsupported token type');
}
// switch to the correct network otherwise the token will be added to the wrong one
await switchOrAddChain();
const wasAdded = await provider?.request?.({
method: 'wallet_watchAsset',
params,
});
if (wasAdded) {
toaster.success({
title: 'Success',
description: 'Successfully added token to your wallet',
});
await trackUsage('add_token');
mixpanel.logEvent(mixpanel.EventTypes.ADD_TO_WALLET, {
Target: 'token',
Wallet: wallet,
Token: token.symbol || '',
});
}
} catch (error) {
toaster.error({
title: 'Error',
description: (error as Error)?.message || 'Something went wrong',
});
}
}, [ wallet, token, tokenId, switchOrAddChain, provider, trackUsage ]);
if (!provider || !wallet) {
return null;
}
if (isLoading) {
return ;
}
const canBeAdded = (
// MetaMask can add NFTs now, but this is still experimental feature, and doesn't work on mobile devices
// https://docs.metamask.io/wallet/how-to/display/tokens/#display-nfts
wallet === 'metamask' &&
[ 'ERC-721', 'ERC-1155' ].includes(token.type) &&
tokenId &&
!isMobile
) || token.type === 'ERC-20';
if (!feature.isEnabled || !canBeAdded) {
return null;
}
if (variant === 'button') {
return (
);
}
return (
);
};
export default React.memo(chakra(AddressAddToWallet));