Commit daa4dc19 authored by tom goriunov's avatar tom goriunov Committed by GitHub

TokenPocket wallet integration (#1088)

* base implementation

* switch network before adding token

* make envs-validator happy

* add deployment values

* fix env type

* update icon
parent 673c6dee
import type { Feature } from './types'; import type { Feature } from './types';
import type { WalletType } from 'types/client/wallets'; import type { WalletType } from 'types/client/wallets';
import { getEnvValue } from '../utils'; import { getEnvValue, parseEnvJson } from '../utils';
const wallets = ((): Array<WalletType> | undefined => {
const envValue = getEnvValue(process.env.NEXT_PUBLIC_WEB3_WALLETS);
if (envValue === 'none') {
return;
}
const defaultWallet = ((): WalletType => {
const envValue = getEnvValue(process.env.NEXT_PUBLIC_WEB3_DEFAULT_WALLET) as WalletType;
const SUPPORTED_WALLETS: Array<WalletType> = [ const SUPPORTED_WALLETS: Array<WalletType> = [
'metamask', 'metamask',
'coinbase', 'coinbase',
'token_pocket',
]; ];
return envValue && SUPPORTED_WALLETS.includes(envValue) ? envValue : 'metamask'; const wallets = parseEnvJson<Array<WalletType>>(envValue)?.filter((type) => SUPPORTED_WALLETS.includes(type));
if (!wallets || wallets.length === 0) {
return [ 'metamask' ];
}
return wallets;
})(); })();
const title = 'Web3 wallet integration (add token or network to the wallet)'; const title = 'Web3 wallet integration (add token or network to the wallet)';
const config: Feature<{ defaultWallet: Exclude<WalletType, 'none'>; addToken: { isDisabled: boolean }}> = (() => { const config: Feature<{ wallets: Array<WalletType>; addToken: { isDisabled: boolean }}> = (() => {
if (defaultWallet !== 'none') { if (wallets && wallets.length > 0) {
return Object.freeze({ return Object.freeze({
title, title,
isEnabled: true, isEnabled: true,
defaultWallet, wallets,
addToken: { addToken: {
isDisabled: getEnvValue(process.env.NEXT_PUBLIC_WEB3_DISABLE_ADD_TOKEN_TO_WALLET) === 'true', isDisabled: getEnvValue(process.env.NEXT_PUBLIC_WEB3_DISABLE_ADD_TOKEN_TO_WALLET) === 'true',
}, },
......
...@@ -46,3 +46,4 @@ NEXT_PUBLIC_STATS_API_HOST=https://stats-goerli.k8s-dev.blockscout.com ...@@ -46,3 +46,4 @@ NEXT_PUBLIC_STATS_API_HOST=https://stats-goerli.k8s-dev.blockscout.com
NEXT_PUBLIC_VISUALIZE_API_HOST=https://visualizer.services.blockscout.com NEXT_PUBLIC_VISUALIZE_API_HOST=https://visualizer.services.blockscout.com
NEXT_PUBLIC_CONTRACT_INFO_API_HOST=https://contracts-info.services.blockscout.com NEXT_PUBLIC_CONTRACT_INFO_API_HOST=https://contracts-info.services.blockscout.com
NEXT_PUBLIC_ADMIN_SERVICE_API_HOST=https://admin-rs.services.blockscout.com NEXT_PUBLIC_ADMIN_SERVICE_API_HOST=https://admin-rs.services.blockscout.com
NEXT_PUBLIC_WEB3_WALLETS=['token_pocket','metamask']
...@@ -37,7 +37,7 @@ NEXT_PUBLIC_APP_INSTANCE=local ...@@ -37,7 +37,7 @@ NEXT_PUBLIC_APP_INSTANCE=local
NEXT_PUBLIC_APP_ENV=development NEXT_PUBLIC_APP_ENV=development
NEXT_PUBLIC_GRAPHIQL_TRANSACTION=0x4a0ed8ddf751a7cb5297f827699117b0f6d21a0b2907594d300dc9fed75c7e62 NEXT_PUBLIC_GRAPHIQL_TRANSACTION=0x4a0ed8ddf751a7cb5297f827699117b0f6d21a0b2907594d300dc9fed75c7e62
NEXT_PUBLIC_API_SPEC_URL=https://raw.githubusercontent.com/blockscout/blockscout-api-v2-swagger/main/swagger.yaml NEXT_PUBLIC_API_SPEC_URL=https://raw.githubusercontent.com/blockscout/blockscout-api-v2-swagger/main/swagger.yaml
NEXT_PUBLIC_WEB3_DEFAULT_WALLET=coinbase NEXT_PUBLIC_WEB3_WALLETS=['coinbase']
NEXT_PUBLIC_WEB3_DISABLE_ADD_TOKEN_TO_WALLET=true NEXT_PUBLIC_WEB3_DISABLE_ADD_TOKEN_TO_WALLET=true
NEXT_PUBLIC_IS_ACCOUNT_SUPPORTED=true NEXT_PUBLIC_IS_ACCOUNT_SUPPORTED=true
NEXT_PUBLIC_AUTH_URL=http://localhost:3000 NEXT_PUBLIC_AUTH_URL=http://localhost:3000
......
...@@ -187,7 +187,7 @@ frontend: ...@@ -187,7 +187,7 @@ frontend:
NEXT_PUBLIC_NETWORK_EXPLORERS: '' NEXT_PUBLIC_NETWORK_EXPLORERS: ''
NEXT_PUBLIC_HOMEPAGE_PLATE_BACKGROUND: "linear-gradient(136.9deg,rgb(107 94 236) 1.5%,rgb(0 82 255) 56.84%,rgb(82 62 231) 98.54%)" NEXT_PUBLIC_HOMEPAGE_PLATE_BACKGROUND: "linear-gradient(136.9deg,rgb(107 94 236) 1.5%,rgb(0 82 255) 56.84%,rgb(82 62 231) 98.54%)"
NEXT_PUBLIC_NETWORK_RPC_URL: https://goerli.optimism.io NEXT_PUBLIC_NETWORK_RPC_URL: https://goerli.optimism.io
NEXT_PUBLIC_WEB3_DEFAULT_WALLET: coinbase NEXT_PUBLIC_WEB3_WALLETS: "['coinbase']"
NEXT_PUBLIC_WEB3_DISABLE_ADD_TOKEN_TO_WALLET: true NEXT_PUBLIC_WEB3_DISABLE_ADD_TOKEN_TO_WALLET: true
NEXT_PUBLIC_HOMEPAGE_CHARTS: "['daily_txs']" NEXT_PUBLIC_HOMEPAGE_CHARTS: "['daily_txs']"
NEXT_PUBLIC_VISUALIZE_API_HOST: https://visualizer-test.k8s-dev.blockscout.com NEXT_PUBLIC_VISUALIZE_API_HOST: https://visualizer-test.k8s-dev.blockscout.com
......
...@@ -158,6 +158,7 @@ frontend: ...@@ -158,6 +158,7 @@ frontend:
NEXT_PUBLIC_API_SPEC_URL: https://raw.githubusercontent.com/blockscout/blockscout-api-v2-swagger/main/swagger.yaml NEXT_PUBLIC_API_SPEC_URL: https://raw.githubusercontent.com/blockscout/blockscout-api-v2-swagger/main/swagger.yaml
NEXT_PUBLIC_MARKETPLACE_CONFIG_URL: https://raw.githubusercontent.com/blockscout/frontend-configs/dev/configs/marketplace/eth-goerli.json NEXT_PUBLIC_MARKETPLACE_CONFIG_URL: https://raw.githubusercontent.com/blockscout/frontend-configs/dev/configs/marketplace/eth-goerli.json
NEXT_PUBLIC_GRAPHIQL_TRANSACTION: 0xf7d4972356e6ae44ae948d0cf19ef2beaf0e574c180997e969a2837da15e349d NEXT_PUBLIC_GRAPHIQL_TRANSACTION: 0xf7d4972356e6ae44ae948d0cf19ef2beaf0e574c180997e969a2837da15e349d
NEXT_PUBLIC_WEB3_WALLETS: "['token_pocket','coinbase','metamask']"
envFromSecret: envFromSecret:
NEXT_PUBLIC_SENTRY_DSN: ref+vault://deployment-values/blockscout/dev/front-main?token_env=VAULT_TOKEN&address=https://vault.k8s.blockscout.com#/NEXT_PUBLIC_SENTRY_DSN NEXT_PUBLIC_SENTRY_DSN: ref+vault://deployment-values/blockscout/dev/front-main?token_env=VAULT_TOKEN&address=https://vault.k8s.blockscout.com#/NEXT_PUBLIC_SENTRY_DSN
SENTRY_CSP_REPORT_URI: ref+vault://deployment-values/blockscout/dev/front-main?token_env=VAULT_TOKEN&address=https://vault.k8s.blockscout.com#/SENTRY_CSP_REPORT_URI SENTRY_CSP_REPORT_URI: ref+vault://deployment-values/blockscout/dev/front-main?token_env=VAULT_TOKEN&address=https://vault.k8s.blockscout.com#/SENTRY_CSP_REPORT_URI
......
...@@ -109,8 +109,8 @@ frontend: ...@@ -109,8 +109,8 @@ frontend:
_default: "linear-gradient(136.9deg,rgb(107 94 236) 1.5%,rgb(0 82 255) 56.84%,rgb(82 62 231) 98.54%)" _default: "linear-gradient(136.9deg,rgb(107 94 236) 1.5%,rgb(0 82 255) 56.84%,rgb(82 62 231) 98.54%)"
NEXT_PUBLIC_NETWORK_RPC_URL: NEXT_PUBLIC_NETWORK_RPC_URL:
_default: https://goerli.optimism.io _default: https://goerli.optimism.io
NEXT_PUBLIC_WEB3_DEFAULT_WALLET: NEXT_PUBLIC_WEB3_WALLETS:
_default: coinbase _default: "['coinbase']"
NEXT_PUBLIC_WEB3_DISABLE_ADD_TOKEN_TO_WALLET: NEXT_PUBLIC_WEB3_DISABLE_ADD_TOKEN_TO_WALLET:
_default: true _default: true
NEXT_PUBLIC_HOMEPAGE_CHARTS: NEXT_PUBLIC_HOMEPAGE_CHARTS:
......
...@@ -123,3 +123,5 @@ frontend: ...@@ -123,3 +123,5 @@ frontend:
_default: ref+vault://deployment-values/blockscout/dev/review?token_env=VAULT_TOKEN&address=https://vault.k8s.blockscout.com#/NEXT_PUBLIC_RE_CAPTCHA_APP_SITE_KEY _default: ref+vault://deployment-values/blockscout/dev/review?token_env=VAULT_TOKEN&address=https://vault.k8s.blockscout.com#/NEXT_PUBLIC_RE_CAPTCHA_APP_SITE_KEY
NEXT_PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID: NEXT_PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID:
_default: ref+vault://deployment-values/blockscout/dev/review?token_env=VAULT_TOKEN&address=https://vault.k8s.blockscout.com#/NEXT_PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID _default: ref+vault://deployment-values/blockscout/dev/review?token_env=VAULT_TOKEN&address=https://vault.k8s.blockscout.com#/NEXT_PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID
NEXT_PUBLIC_WEB3_WALLETS:
_default: "['token_pocket','coinbase','metamask']"
...@@ -333,11 +333,11 @@ For each application, you need to specify the `MarketplaceCategoryId` to which i ...@@ -333,11 +333,11 @@ For each application, you need to specify the `MarketplaceCategoryId` to which i
### Web3 wallet integration (add token or network to the wallet) ### Web3 wallet integration (add token or network to the wallet)
This feature is **enabled by default** with the `metamask` wallet type. To switch it off pass `NEXT_PUBLIC_WEB3_DEFAULT_WALLET=none`. This feature is **enabled by default** with the `['metamask']` value. To switch it off pass `NEXT_PUBLIC_WEB3_WALLETS=none`.
| Variable | Type| Description | Compulsoriness | Default value | Example value | | Variable | Type| Description | Compulsoriness | Default value | Example value |
| --- | --- | --- | --- | --- | --- | | --- | --- | --- | --- | --- | --- |
| NEXT_PUBLIC_WEB3_DEFAULT_WALLET | `metamask` \| `coinbase` \| `none` | Type of Web3 wallet which will be used by default to add tokens or chains to | - | `metamask` | `coinbase` | | NEXT_PUBLIC_WEB3_WALLETS | `Array<'metamask' \| 'coinbase' \| 'token_pocket'>` | Array of Web3 wallets which will be used to add tokens or chain to. The first wallet which is enabled in user's browser will be shown. | - | `[ '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 | - | - | `true` | | NEXT_PUBLIC_WEB3_DISABLE_ADD_TOKEN_TO_WALLET | `boolean`| Set to `true` to hide icon "Add to your wallet" next to token addresses | - | - | `true` |
&nbsp; &nbsp;
......
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<mask id="token-pocket_svg__a" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="2" y="6" width="20" height="13">
<path d="M22 6H2v12.904h20V6Z" fill="#fff"/>
</mask>
<g mask="url(#token-pocket_svg__a)">
<path fill-rule="evenodd" clip-rule="evenodd" d="M9.84 6H2.611A.61.61 0 0 0 2 6.611v2.482a.61.61 0 0 0 .611.611h2.327v8.589c0 .338.274.611.612.611h2.604a.61.61 0 0 0 .611-.611V9.704h1.064c1.022 0 1.853-.83 1.853-1.852A1.838 1.838 0 0 0 9.84 6Zm5.877 10.112.003.001v-4.992a1.156 1.156 0 0 1 2.309 0 1.15 1.15 0 0 1-1.154 1.155v3.967a5.125 5.125 0 0 0 5.121-5.121A5.119 5.119 0 0 0 16.875 6a5.123 5.123 0 0 0-5.121 5.121v7.154a.61.61 0 0 0 .611.612h2.74a.61.61 0 0 0 .612-.612v-2.163Z" fill="#2980FE"/>
<path d="M15.72 11.122v4.991a5.169 5.169 0 0 0 1.04.13h.036v-3.97c-.6-.04-1.075-.54-1.075-1.151Z" fill="url(#token-pocket_svg__b)"/>
<path d="M16.875 16.243v-3.967c-.029 0-.054 0-.083-.004v3.97h.083Z" fill="#2980FE"/>
</g>
<defs>
<linearGradient id="token-pocket_svg__b" x1="16.877" y1="13.683" x2="15.721" y2="13.683" gradientUnits="userSpaceOnUse">
<stop stop-color="#2980FE"/>
<stop offset=".967" stop-color="#6CA8FF"/>
<stop offset="1" stop-color="#2980FE"/>
</linearGradient>
</defs>
</svg>
import type { WalletType } from 'types/client/wallets';
export enum EventTypes { export enum EventTypes {
PAGE_VIEW = 'Page view', PAGE_VIEW = 'Page view',
SEARCH_QUERY = 'Search query', SEARCH_QUERY = 'Search query',
ADD_TO_WALLET = 'Add to wallet',
} }
/* eslint-disable @typescript-eslint/indent */
export type EventPayload<Type extends EventTypes> = export type EventPayload<Type extends EventTypes> =
Type extends EventTypes.PAGE_VIEW ? Type extends EventTypes.PAGE_VIEW ?
{ {
'Page type': string; 'Page type': string;
'Tab': string; 'Tab': string;
'Page'?: string; 'Page'?: string;
} : } :
Type extends EventTypes.SEARCH_QUERY ? { Type extends EventTypes.SEARCH_QUERY ? {
'Search query': string; 'Search query': string;
'Source page type': string; 'Source page type': string;
'Result URL': string; 'Result URL': string;
} : } :
undefined; Type extends EventTypes.ADD_TO_WALLET ? (
{
'Wallet': WalletType;
'Target': 'network';
} | {
'Wallet': WalletType;
'Target': 'token';
'Token': string;
}
) :
undefined;
/* eslint-enable @typescript-eslint/indent */
import React from 'react';
import config from 'configs/app';
import getErrorObj from 'lib/errors/getErrorObj';
import useProvider from './useProvider';
export default function useAddOrSwitchChain() {
const { wallet, provider } = useProvider();
return React.useCallback(async() => {
if (!wallet || !provider) {
return;
}
const hexadecimalChainId = '0x' + Number(config.chain.id).toString(16);
try {
return await provider.request({
method: 'wallet_switchEthereumChain',
params: [ { chainId: hexadecimalChainId } ],
});
} catch (error) {
const errorObj = getErrorObj(error);
const code = errorObj && 'code' in errorObj ? errorObj.code : undefined;
// This error code indicates that the chain has not been added to Wallet.
if (code === 4902) {
const params = {
method: 'wallet_addEthereumChain',
params: [ {
chainId: hexadecimalChainId,
chainName: config.chain.name,
nativeCurrency: {
name: config.chain.currency.name,
symbol: config.chain.currency.symbol,
decimals: config.chain.currency.decimals,
},
rpcUrls: [ config.chain.rpcUrl ],
blockExplorerUrls: [ config.app.baseUrl ],
} ],
// in wagmi types for wallet_addEthereumChain method is not provided
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} as any;
return await provider.request({
method: 'wallet_addEthereumChain',
params,
});
}
throw error;
}
}, [ provider, wallet ]);
}
...@@ -3,12 +3,15 @@ import type { WindowProvider } from 'wagmi'; ...@@ -3,12 +3,15 @@ import type { WindowProvider } from 'wagmi';
import 'wagmi/window'; import 'wagmi/window';
import type { WalletType } from 'types/client/wallets';
import config from 'configs/app'; import config from 'configs/app';
const feature = config.features.web3Wallet; const feature = config.features.web3Wallet;
export default function useProvider() { export default function useProvider() {
const [ provider, setProvider ] = React.useState<WindowProvider>(); const [ provider, setProvider ] = React.useState<WindowProvider>();
const [ wallet, setWallet ] = React.useState<WalletType>();
React.useEffect(() => { React.useEffect(() => {
if (!('ethereum' in window && window.ethereum) || !feature.isEnabled) { if (!('ethereum' in window && window.ethereum) || !feature.isEnabled) {
...@@ -19,16 +22,22 @@ export default function useProvider() { ...@@ -19,16 +22,22 @@ export default function useProvider() {
// if user has only one wallet, the provider is injected in the window.ethereum directly // if user has only one wallet, the provider is injected in the window.ethereum directly
const providers = Array.isArray(window.ethereum.providers) ? window.ethereum.providers : [ window.ethereum ]; const providers = Array.isArray(window.ethereum.providers) ? window.ethereum.providers : [ window.ethereum ];
providers.forEach(async(provider) => { for (const wallet of feature.wallets) {
if (feature.defaultWallet === 'coinbase' && provider.isCoinbaseWallet) { const provider = providers.find((provider) => {
return setProvider(provider); return (
} (wallet === 'coinbase' && provider.isCoinbaseWallet) ||
(wallet === 'metamask' && provider.isMetaMask) ||
(wallet === 'token_pocket' && provider.isTokenPocket)
);
});
if (feature.defaultWallet === 'metamask' && provider.isMetaMask) { if (provider) {
return setProvider(provider); setProvider(provider);
setWallet(wallet);
break;
}
} }
});
}, []); }, []);
return provider; return { provider, wallet };
} }
...@@ -2,6 +2,7 @@ import type { WalletType, WalletInfo } from 'types/client/wallets'; ...@@ -2,6 +2,7 @@ import type { WalletType, WalletInfo } from 'types/client/wallets';
import coinbaseIcon from 'icons/wallets/coinbase.svg'; import coinbaseIcon from 'icons/wallets/coinbase.svg';
import metamaskIcon from 'icons/wallets/metamask.svg'; import metamaskIcon from 'icons/wallets/metamask.svg';
import tokenPocketIcon from 'icons/wallets/token-pocket.svg';
export const WALLETS_INFO: Record<Exclude<WalletType, 'none'>, WalletInfo> = { export const WALLETS_INFO: Record<Exclude<WalletType, 'none'>, WalletInfo> = {
metamask: { metamask: {
...@@ -12,4 +13,8 @@ export const WALLETS_INFO: Record<Exclude<WalletType, 'none'>, WalletInfo> = { ...@@ -12,4 +13,8 @@ export const WALLETS_INFO: Record<Exclude<WalletType, 'none'>, WalletInfo> = {
name: 'Coinbase Wallet', name: 'Coinbase Wallet',
icon: coinbaseIcon, icon: coinbaseIcon,
}, },
token_pocket: {
name: 'TokenPocket',
icon: tokenPocketIcon,
},
}; };
export type WalletType = 'metamask' | 'coinbase' | 'none'; export type WalletType = 'metamask' | 'coinbase' | 'token_pocket';
export interface WalletInfo { export interface WalletInfo {
name: string; name: string;
......
...@@ -22,7 +22,7 @@ export type NextPublicEnvs = { ...@@ -22,7 +22,7 @@ export type NextPublicEnvs = {
NEXT_PUBLIC_FOOTER_LINKS?: string; NEXT_PUBLIC_FOOTER_LINKS?: string;
NEXT_PUBLIC_API_SPEC_URL?: string; NEXT_PUBLIC_API_SPEC_URL?: string;
NEXT_PUBLIC_GRAPHIQL_TRANSACTION?: string; NEXT_PUBLIC_GRAPHIQL_TRANSACTION?: string;
NEXT_PUBLIC_WEB3_DEFAULT_WALLET?: 'metamask' | 'coinbase'; NEXT_PUBLIC_WEB3_WALLETS?: string;
NEXT_PUBLIC_WEB3_DISABLE_ADD_TOKEN_TO_WALLET?: 'true' | 'false'; NEXT_PUBLIC_WEB3_DISABLE_ADD_TOKEN_TO_WALLET?: 'true' | 'false';
NEXT_PUBLIC_HIDE_INDEXING_ALERT?: 'true' | 'false'; NEXT_PUBLIC_HIDE_INDEXING_ALERT?: 'true' | 'false';
......
...@@ -3,6 +3,8 @@ import React from 'react'; ...@@ -3,6 +3,8 @@ import React from 'react';
import config from 'configs/app'; import config from 'configs/app';
import useToast from 'lib/hooks/useToast'; import useToast from 'lib/hooks/useToast';
import * as mixpanel from 'lib/mixpanel/index';
import useAddOrSwitchChain from 'lib/web3/useAddOrSwitchChain';
import useProvider from 'lib/web3/useProvider'; import useProvider from 'lib/web3/useProvider';
import { WALLETS_INFO } from 'lib/web3/wallets'; import { WALLETS_INFO } from 'lib/web3/wallets';
...@@ -14,28 +16,17 @@ interface Props { ...@@ -14,28 +16,17 @@ interface Props {
const NetworkAddToWallet = ({ className }: Props) => { const NetworkAddToWallet = ({ className }: Props) => {
const toast = useToast(); const toast = useToast();
const provider = useProvider(); const { provider, wallet } = useProvider();
const addOrSwitchChain = useAddOrSwitchChain();
const handleClick = React.useCallback(async() => { const handleClick = React.useCallback(async() => {
if (!wallet || !provider) {
return;
}
try { try {
const hexadecimalChainId = '0x' + Number(config.chain.id).toString(16); await addOrSwitchChain();
const params = {
method: 'wallet_addEthereumChain',
params: [ {
chainId: hexadecimalChainId,
chainName: config.chain.name,
nativeCurrency: {
name: config.chain.currency.name,
symbol: config.chain.currency.symbol,
decimals: config.chain.currency.decimals,
},
rpcUrls: [ config.chain.rpcUrl ],
blockExplorerUrls: [ config.app.baseUrl ],
} ],
// in wagmi types for wallet_addEthereumChain method is not provided
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} as any;
await provider?.request?.(params);
toast({ toast({
position: 'top-right', position: 'top-right',
title: 'Success', title: 'Success',
...@@ -44,6 +35,12 @@ const NetworkAddToWallet = ({ className }: Props) => { ...@@ -44,6 +35,12 @@ const NetworkAddToWallet = ({ className }: Props) => {
variant: 'subtle', variant: 'subtle',
isClosable: true, isClosable: true,
}); });
mixpanel.logEvent(mixpanel.EventTypes.ADD_TO_WALLET, {
Target: 'network',
Wallet: wallet,
});
} catch (error) { } catch (error) {
toast({ toast({
position: 'top-right', position: 'top-right',
...@@ -54,15 +51,15 @@ const NetworkAddToWallet = ({ className }: Props) => { ...@@ -54,15 +51,15 @@ const NetworkAddToWallet = ({ className }: Props) => {
isClosable: true, isClosable: true,
}); });
} }
}, [ provider, toast ]); }, [ addOrSwitchChain, provider, toast, wallet ]);
if (!provider || !config.chain.rpcUrl || !feature.isEnabled) { if (!provider || !wallet || !config.chain.rpcUrl || !feature.isEnabled) {
return null; return null;
} }
return ( return (
<Button variant="outline" size="sm" onClick={ handleClick } className={ className }> <Button variant="outline" size="sm" onClick={ handleClick } className={ className }>
<Icon as={ WALLETS_INFO[feature.defaultWallet].icon } boxSize={ 5 } mr={ 2 }/> <Icon as={ WALLETS_INFO[wallet].icon } boxSize={ 5 } mr={ 2 }/>
Add { config.chain.name } Add { config.chain.name }
</Button> </Button>
); );
......
...@@ -5,6 +5,8 @@ import type { TokenInfo } from 'types/api/token'; ...@@ -5,6 +5,8 @@ import type { TokenInfo } from 'types/api/token';
import config from 'configs/app'; import config from 'configs/app';
import useToast from 'lib/hooks/useToast'; import useToast from 'lib/hooks/useToast';
import * as mixpanel from 'lib/mixpanel/index';
import useAddOrSwitchChain from 'lib/web3/useAddOrSwitchChain';
import useProvider from 'lib/web3/useProvider'; import useProvider from 'lib/web3/useProvider';
import { WALLETS_INFO } from 'lib/web3/wallets'; import { WALLETS_INFO } from 'lib/web3/wallets';
...@@ -18,10 +20,18 @@ interface Props { ...@@ -18,10 +20,18 @@ interface Props {
const AddressAddToWallet = ({ className, token, isLoading }: Props) => { const AddressAddToWallet = ({ className, token, isLoading }: Props) => {
const toast = useToast(); const toast = useToast();
const provider = useProvider(); const { provider, wallet } = useProvider();
const addOrSwitchChain = useAddOrSwitchChain();
const handleClick = React.useCallback(async() => { const handleClick = React.useCallback(async() => {
if (!wallet) {
return;
}
try { try {
// switch to the correct network otherwise the token will be added to the wrong one
await addOrSwitchChain();
const wasAdded = await provider?.request?.({ const wasAdded = await provider?.request?.({
method: 'wallet_watchAsset', method: 'wallet_watchAsset',
params: { params: {
...@@ -30,8 +40,7 @@ const AddressAddToWallet = ({ className, token, isLoading }: Props) => { ...@@ -30,8 +40,7 @@ const AddressAddToWallet = ({ className, token, isLoading }: Props) => {
address: token.address, address: token.address,
symbol: token.symbol || '', symbol: token.symbol || '',
decimals: Number(token.decimals) || 18, decimals: Number(token.decimals) || 18,
// TODO: add token image when we have it in API image: token.icon_url || '',
// image: ''
}, },
}, },
}); });
...@@ -45,6 +54,12 @@ const AddressAddToWallet = ({ className, token, isLoading }: Props) => { ...@@ -45,6 +54,12 @@ const AddressAddToWallet = ({ className, token, isLoading }: Props) => {
variant: 'subtle', variant: 'subtle',
isClosable: true, isClosable: true,
}); });
mixpanel.logEvent(mixpanel.EventTypes.ADD_TO_WALLET, {
Target: 'token',
Wallet: wallet,
Token: token.symbol || '',
});
} }
} catch (error) { } catch (error) {
toast({ toast({
...@@ -56,9 +71,9 @@ const AddressAddToWallet = ({ className, token, isLoading }: Props) => { ...@@ -56,9 +71,9 @@ const AddressAddToWallet = ({ className, token, isLoading }: Props) => {
isClosable: true, isClosable: true,
}); });
} }
}, [ toast, token, provider ]); }, [ toast, token, provider, wallet, addOrSwitchChain ]);
if (!provider) { if (!provider || !wallet) {
return null; return null;
} }
...@@ -71,9 +86,9 @@ const AddressAddToWallet = ({ className, token, isLoading }: Props) => { ...@@ -71,9 +86,9 @@ const AddressAddToWallet = ({ className, token, isLoading }: Props) => {
} }
return ( return (
<Tooltip label={ `Add token to ${ WALLETS_INFO[feature.defaultWallet].name }` }> <Tooltip label={ `Add token to ${ WALLETS_INFO[wallet].name }` }>
<Box className={ className } display="inline-flex" cursor="pointer" onClick={ handleClick }> <Box className={ className } display="inline-flex" cursor="pointer" onClick={ handleClick }>
<Icon as={ WALLETS_INFO[feature.defaultWallet].icon } boxSize={ 6 }/> <Icon as={ WALLETS_INFO[wallet].icon } boxSize={ 6 }/>
</Box> </Box>
</Tooltip> </Tooltip>
); );
......
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