Commit 1929d165 authored by tom's avatar tom

add support for coinbase provider

parent fbe02374
import type { MetaMaskInpageProvider } from '@metamask/providers'; import type { ExternalProvider } from 'types/client/wallets';
type CPreferences = { type CPreferences = {
zone: string; zone: string;
...@@ -7,8 +7,10 @@ type CPreferences = { ...@@ -7,8 +7,10 @@ type CPreferences = {
} }
declare global { declare global {
interface Window { export interface Window {
ethereum: MetaMaskInpageProvider; ethereum?: {
providers?: Array<ExternalProvider>;
};
coinzilla_display: Array<CPreferences>; 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;
}
...@@ -2,3 +2,17 @@ export const SUPPORTED_WALLETS = [ ...@@ -2,3 +2,17 @@ export const SUPPORTED_WALLETS = [
'metamask' as const, 'metamask' as const,
'coinbase' as const, 'coinbase' as const,
]; ];
import coinbaseIcon from 'icons/wallets/coinbase.svg';
import metamaskIcon from 'icons/wallets/metamask.svg';
export const WALLETS_INFO = {
metamask: {
add_token_text: 'Add token to MetaMask',
icon: metamaskIcon,
},
coinbase: {
add_token_text: 'Add token to Coinbase Wallet',
icon: coinbaseIcon,
},
};
import type { providers } from 'ethers';
import type { ArrayElement } from 'types/utils'; import type { ArrayElement } from 'types/utils';
import type { SUPPORTED_WALLETS } from 'lib/web3/wallets'; import type { SUPPORTED_WALLETS } from 'lib/web3/wallets';
export type WalletType = ArrayElement<typeof SUPPORTED_WALLETS>; export type WalletType = ArrayElement<typeof SUPPORTED_WALLETS>;
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 { test, expect } from '@playwright/experimental-ct-react';
import type { UseQueryResult } from '@tanstack/react-query'; import type { UseQueryResult } from '@tanstack/react-query';
import React from 'react'; import React from 'react';
...@@ -73,7 +72,9 @@ test('token', async({ mount, page }) => { ...@@ -73,7 +72,9 @@ test('token', async({ mount, page }) => {
}), { times: 1 }); }), { times: 1 });
await page.evaluate(() => { await page.evaluate(() => {
window.ethereum = { } as MetaMaskInpageProvider; window.ethereum = {
providers: [ { isMetaMask: true } ],
};
}); });
const component = await mount( const component = await mount(
......
...@@ -3,8 +3,10 @@ import React from 'react'; ...@@ -3,8 +3,10 @@ import React from 'react';
import type { TokenInfo } from 'types/api/token'; 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 useToast from 'lib/hooks/useToast';
import useProvider from 'lib/web3/useProvider';
import { WALLETS_INFO } from 'lib/web3/wallets';
interface Props { interface Props {
className?: string; className?: string;
...@@ -14,9 +16,11 @@ interface Props { ...@@ -14,9 +16,11 @@ interface Props {
const AddressAddToWallet = ({ className, token }: Props) => { const AddressAddToWallet = ({ className, token }: Props) => {
const toast = useToast(); const toast = useToast();
const provider = useProvider();
const handleClick = React.useCallback(async() => { const handleClick = React.useCallback(async() => {
try { try {
const wasAdded = await window.ethereum.request?.({ const wasAdded = await provider?.request?.({
method: 'wallet_watchAsset', method: 'wallet_watchAsset',
params: { params: {
type: 'ERC20', // Initially only supports ERC20, but eventually more! type: 'ERC20', // Initially only supports ERC20, but eventually more!
...@@ -24,6 +28,8 @@ const AddressAddToWallet = ({ className, token }: Props) => { ...@@ -24,6 +28,8 @@ const AddressAddToWallet = ({ className, token }: 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: ''
}, },
}, },
}); });
...@@ -32,7 +38,7 @@ const AddressAddToWallet = ({ className, token }: Props) => { ...@@ -32,7 +38,7 @@ const AddressAddToWallet = ({ className, token }: Props) => {
toast({ toast({
position: 'top-right', position: 'top-right',
title: 'Success', title: 'Success',
description: 'Successfully added token to MetaMask', description: 'Successfully added token to your wallet',
status: 'success', status: 'success',
variant: 'subtle', variant: 'subtle',
isClosable: true, isClosable: true,
...@@ -48,16 +54,18 @@ const AddressAddToWallet = ({ className, token }: Props) => { ...@@ -48,16 +54,18 @@ const AddressAddToWallet = ({ className, token }: Props) => {
isClosable: true, isClosable: true,
}); });
} }
}, [ toast, token ]); }, [ toast, token, provider ]);
if (!('ethereum' in window)) { if (!provider) {
return null; return null;
} }
const defaultWallet = appConfig.web3.defaultWallet;
return ( 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 }> <Box className={ className } display="inline-flex" cursor="pointer" onClick={ handleClick }>
<Icon as={ metamaskIcon } boxSize={ 6 }/> <Icon as={ WALLETS_INFO[defaultWallet].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