From 565c0324f9e8e3f06776cbab53341f850f5e3846 Mon Sep 17 00:00:00 2001 From: Norbi <37236152+KatunaNorbert@users.noreply.github.com> Date: Thu, 15 Jul 2021 18:03:03 +0300 Subject: [PATCH] Create wallet network switcher (#676) * created component for wallet network switching * component styling * display network names * created networks config * fix get network config function * wip * moved switcher component inside consume * use isAssetNetwork to show Switcher component, added to publish * get network properties using networkList and oceanConfig * error fix * hide wallet network switcher if no provider * use chainId from useAsset ddo * added switcher component to Compute * added component to edit metadata and compute settings * added component to advance settings form * fixed lint errors * included component inside Web3Feedback * updated text and icon design * button design update, and Web3Feedback position on edit asset * fixed lint error * message update * tag error fixes * disabled pool and trade buttons if not asset network * mainnet aquarius fallback url * filename typo fix * replace NetworkName component with getNetworkDisplayName function * added method to switch to EthereumChain networks, removed logs * fixed lint error * style tweaks * markup and styles simplification * restrict add datatoken Co-authored-by: Norbi Co-authored-by: Matthias Kretschmann --- src/components/atoms/Button.module.css | 1 + src/components/molecules/MetadataPreview.tsx | 6 ++ .../WalletNetworkSwitcher.module.css | 5 ++ .../molecules/WalletNetworkSwitcher.tsx | 51 +++++++++++++++ .../molecules/Web3Feedback.module.css | 2 +- src/components/molecules/Web3Feedback.tsx | 11 ++-- .../organisms/AssetActions/Consume.module.css | 2 +- .../Edit/EditAdvancedSettings.tsx | 5 +- .../AssetActions/Edit/EditComputeDataset.tsx | 5 +- .../Edit/FormAdvancedSettings.tsx | 8 ++- .../Edit/FormEditComputeDataset.tsx | 8 ++- .../AssetActions/Edit/FormEditMetadata.tsx | 4 +- .../organisms/AssetActions/Pool/index.tsx | 11 +++- .../AssetActions/Trade/FormTrade.tsx | 4 +- .../organisms/AssetActions/index.tsx | 10 ++- .../organisms/AssetContent/MetaMain.tsx | 4 +- .../organisms/AssetContent/index.tsx | 4 +- src/components/pages/Publish/index.tsx | 1 - src/providers/Web3.tsx | 1 - src/utils/web3.ts | 65 +++++++++++++------ 20 files changed, 156 insertions(+), 52 deletions(-) create mode 100644 src/components/molecules/WalletNetworkSwitcher.module.css create mode 100644 src/components/molecules/WalletNetworkSwitcher.tsx diff --git a/src/components/atoms/Button.module.css b/src/components/atoms/Button.module.css index c83453a4f..d63783b26 100644 --- a/src/components/atoms/Button.module.css +++ b/src/components/atoms/Button.module.css @@ -78,6 +78,7 @@ color: var(--brand-pink); box-shadow: none; cursor: pointer; + min-width: auto; } /* Size Modifiers */ diff --git a/src/components/molecules/MetadataPreview.tsx b/src/components/molecules/MetadataPreview.tsx index 852c7b8f9..976803a54 100644 --- a/src/components/molecules/MetadataPreview.tsx +++ b/src/components/molecules/MetadataPreview.tsx @@ -13,6 +13,8 @@ import { transformTags } from '../../utils/metadata' import NetworkName from '../atoms/NetworkName' import { useWeb3 } from '../../providers/Web3' import styles from './MetadataPreview.module.css' +import Web3Feedback from './Web3Feedback' +import { useAsset } from '../../providers/Asset' function Description({ description }: { description: string }) { const [fullDescription, setFullDescription] = useState(false) @@ -95,6 +97,7 @@ export function MetadataPreview({ values: Partial }): ReactElement { const { networkId } = useWeb3() + const { isAssetNetwork } = useAsset() return (
@@ -126,6 +129,9 @@ export function MetadataPreview({ + {isAssetNetwork === false && ( + + )}
) } diff --git a/src/components/molecules/WalletNetworkSwitcher.module.css b/src/components/molecules/WalletNetworkSwitcher.module.css new file mode 100644 index 000000000..24e7cb047 --- /dev/null +++ b/src/components/molecules/WalletNetworkSwitcher.module.css @@ -0,0 +1,5 @@ +.text { + color: var(--color-secondary); + margin-top: calc(var(--spacer) / 4); + margin-bottom: calc(var(--spacer) / 2); +} diff --git a/src/components/molecules/WalletNetworkSwitcher.tsx b/src/components/molecules/WalletNetworkSwitcher.tsx new file mode 100644 index 000000000..d3563873d --- /dev/null +++ b/src/components/molecules/WalletNetworkSwitcher.tsx @@ -0,0 +1,51 @@ +import React, { ReactElement } from 'react' +import { useWeb3 } from '../../providers/Web3' +import { + addCustomNetwork, + getNetworkConfigObject, + getNetworkDisplayName, + getNetworkDataById +} from '../../utils/web3' +import Button from '../atoms/Button' +import styles from './WalletNetworkSwitcher.module.css' +import useNetworkMetadata from '../../hooks/useNetworkMetadata' +import { getOceanConfig } from '../../utils/ocean' +import { useAsset } from '../../providers/Asset' + +export default function WalletNetworkSwitcher(): ReactElement { + const { networkId, web3Provider } = useWeb3() + const { ddo } = useAsset() + const oceanConfig = getOceanConfig(ddo.chainId) + const { networksList } = useNetworkMetadata() + const ddoNetworkData = getNetworkDataById(networksList, ddo.chainId) + const walletNetworkData = getNetworkDataById(networksList, networkId) + + const ddoNetworkName = ( + {getNetworkDisplayName(ddoNetworkData, ddo.chainId)} + ) + const walletNetworkName = ( + {getNetworkDisplayName(walletNetworkData, networkId)} + ) + + async function switchWalletNetwork() { + const networkNode = networksList.find( + (data) => data.node.chainId === ddo.chainId + ).node + const network = { ...networkNode, providerUri: oceanConfig.providerUri } + const networkConfig = getNetworkConfigObject(network) + addCustomNetwork(web3Provider, networkConfig) + } + + return ( + <> +

+ This asset is published on {ddoNetworkName} but your wallet is connected + to {walletNetworkName}. Connect to {ddoNetworkName} to interact with + this asset. +

+ + + ) +} diff --git a/src/components/molecules/Web3Feedback.module.css b/src/components/molecules/Web3Feedback.module.css index a208a2c31..e4ddf87fd 100644 --- a/src/components/molecules/Web3Feedback.module.css +++ b/src/components/molecules/Web3Feedback.module.css @@ -10,7 +10,7 @@ .feedback i { position: absolute; left: 0; - top: calc(var(--spacer) / 1.5); + top: calc(var(--spacer) / 1.45); } .title { diff --git a/src/components/molecules/Web3Feedback.tsx b/src/components/molecules/Web3Feedback.tsx index 2f548b742..694ea4517 100644 --- a/src/components/molecules/Web3Feedback.tsx +++ b/src/components/molecules/Web3Feedback.tsx @@ -2,6 +2,7 @@ import React, { ReactElement } from 'react' import { useWeb3 } from '../../providers/Web3' import Status from '../atoms/Status' import styles from './Web3Feedback.module.css' +import WalletNetworkSwitcher from './WalletNetworkSwitcher' export declare type Web3Error = { status: 'error' | 'warning' | 'success' @@ -34,7 +35,7 @@ export default function Web3Feedback({ : // : !ocean // ? 'Error connecting to Ocean' accountId && isAssetNetwork === false - ? 'Wrong network' + ? 'Not connected to asset network' : accountId ? isBalanceSufficient === false ? 'Insufficient balance' @@ -47,15 +48,17 @@ export default function Web3Feedback({ // ? 'Please try again.' isBalanceSufficient === false ? 'You do not have enough OCEAN in your wallet to purchase this asset.' - : isAssetNetwork === false - ? 'Connect to the asset network.' : 'Something went wrong.' return showFeedback ? (

{title}

- {message &&

{message}

} + {isAssetNetwork === false ? ( + + ) : ( + message &&

{message}

+ )}
) : null } diff --git a/src/components/organisms/AssetActions/Consume.module.css b/src/components/organisms/AssetActions/Consume.module.css index c095bcfcf..d6dc45629 100644 --- a/src/components/organisms/AssetActions/Consume.module.css +++ b/src/components/organisms/AssetActions/Consume.module.css @@ -6,7 +6,6 @@ .info { display: flex; width: auto; - padding: 0 calc(var(--spacer)) 0 calc(var(--spacer)); } .filewrapper { @@ -15,4 +14,5 @@ .feedback { width: 100%; + margin-top: calc(var(--spacer)); } diff --git a/src/components/organisms/AssetActions/Edit/EditAdvancedSettings.tsx b/src/components/organisms/AssetActions/Edit/EditAdvancedSettings.tsx index 9534797f6..2854c0f41 100644 --- a/src/components/organisms/AssetActions/Edit/EditAdvancedSettings.tsx +++ b/src/components/organisms/AssetActions/Edit/EditAdvancedSettings.tsx @@ -20,6 +20,7 @@ import { setMinterToDispenser, setMinterToPublisher } from '../../../../utils/freePrice' +import Web3Feedback from '../../../molecules/Web3Feedback' const contentQuery = graphql` query EditAvanceSettingsQuery { @@ -72,7 +73,7 @@ export default function EditAdvancedSettings({ const { debug } = useUserPreferences() const { accountId } = useWeb3() const { ocean } = useOcean() - const { metadata, ddo, refreshDdo, price } = useAsset() + const { isAssetNetwork, ddo, refreshDdo, price } = useAsset() const [success, setSuccess] = useState() const [error, setError] = useState() const { appConfig } = useSiteMetadata() @@ -168,7 +169,7 @@ export default function EditAdvancedSettings({ setShowEdit={setShowEdit} /> - + {debug === true && (
() const [error, setError] = useState() @@ -169,7 +170,7 @@ export default function EditComputeDataset({ setShowEdit={setShowEdit} /> - + {debug === true && (
diff --git a/src/components/organisms/AssetActions/Edit/FormAdvancedSettings.tsx b/src/components/organisms/AssetActions/Edit/FormAdvancedSettings.tsx index a67186abf..b15968554 100644 --- a/src/components/organisms/AssetActions/Edit/FormAdvancedSettings.tsx +++ b/src/components/organisms/AssetActions/Edit/FormAdvancedSettings.tsx @@ -7,6 +7,7 @@ import { FormFieldProps } from '../../../../@types/Form' import { useOcean } from '../../../../providers/Ocean' import { useWeb3 } from '../../../../providers/Web3' import { AdvancedSettingsForm } from '../../../../models/FormEditCredential' +import { useAsset } from '../../../../providers/Asset' export default function FormAdvancedSettings({ data, @@ -16,6 +17,7 @@ export default function FormAdvancedSettings({ setShowEdit: (show: boolean) => void }): ReactElement { const { accountId } = useWeb3() + const { isAssetNetwork } = useAsset() const { ocean, config } = useOcean() const { isValid, @@ -45,9 +47,11 @@ export default function FormAdvancedSettings({ } /> ))} -
- )} {hasAddedLiquidity && !isRemoveDisabled && ( - )} diff --git a/src/components/organisms/AssetActions/Trade/FormTrade.tsx b/src/components/organisms/AssetActions/Trade/FormTrade.tsx index f04bd5704..1188d5618 100644 --- a/src/components/organisms/AssetActions/Trade/FormTrade.tsx +++ b/src/components/organisms/AssetActions/Trade/FormTrade.tsx @@ -14,6 +14,7 @@ import { FormTradeData, initialValues } from '../../../../models/FormTrade' import Decimal from 'decimal.js' import { useOcean } from '../../../../providers/Ocean' import { useWeb3 } from '../../../../providers/Web3' +import { useAsset } from '../../../../providers/Asset' const contentQuery = graphql` query TradeQuery { @@ -49,6 +50,7 @@ export default function FormTrade({ const content = data.content.edges[0].node.childContentJson.trade const { accountId } = useWeb3() const { ocean } = useOcean() + const { isAssetNetwork } = useAsset() const { debug } = useUserPreferences() const [txId, setTxId] = useState() @@ -139,7 +141,7 @@ export default function FormTrade({
)} - {type !== 'algorithm' && ( - - )} + ) } diff --git a/src/components/organisms/AssetContent/MetaMain.tsx b/src/components/organisms/AssetContent/MetaMain.tsx index 969581c0c..d6cc64088 100644 --- a/src/components/organisms/AssetContent/MetaMain.tsx +++ b/src/components/organisms/AssetContent/MetaMain.tsx @@ -9,7 +9,7 @@ import AssetType from '../../atoms/AssetType' import styles from './MetaMain.module.css' export default function MetaMain(): ReactElement { - const { ddo, owner, type } = useAsset() + const { ddo, owner, type, isAssetNetwork } = useAsset() const { networkId, web3ProviderInfo } = useWeb3() const isCompute = Boolean(ddo?.findServiceByType('compute')) const accessType = isCompute ? 'compute' : 'access' @@ -35,7 +35,7 @@ export default function MetaMain(): ReactElement { {`${ddo?.dataTokenInfo.name} — ${ddo?.dataTokenInfo.symbol}`} - {web3ProviderInfo?.name === 'MetaMask' && ( + {web3ProviderInfo?.name === 'MetaMask' && isAssetNetwork && ( () const [showEditCompute, setShowEditCompute] = useState() @@ -110,7 +110,7 @@ export default function AssetContent(props: AssetContentProps): ReactElement { - {isOwner && ( + {isOwner && isAssetNetwork && (
diff --git a/src/providers/Web3.tsx b/src/providers/Web3.tsx index add5d9d33..fe8286a07 100644 --- a/src/providers/Web3.tsx +++ b/src/providers/Web3.tsx @@ -228,7 +228,6 @@ function Web3Provider({ children }: { children: ReactNode }): ReactElement { // ----------------------------------- useEffect(() => { if (!networkId) return - const networkData = getNetworkDataById(networksList, networkId) setNetworkData(networkData) Logger.log( diff --git a/src/utils/web3.ts b/src/utils/web3.ts index a9b5cab3e..083963cbf 100644 --- a/src/utils/web3.ts +++ b/src/utils/web3.ts @@ -19,6 +19,16 @@ export interface NetworkObject { urlList: string[] } +export function getNetworkConfigObject(node: any): NetworkObject { + const networkConfig = { + name: node.chain, + symbol: node.nativeCurrency.symbol, + chainId: node.chainId, + urlList: [node.providerUri] + } + return networkConfig +} + export function accountTruncate(account: string): string { if (!account) return const middle = account.substring(6, 38) @@ -64,6 +74,7 @@ export function getNetworkDataById( data: { node: EthereumListsChain }[], networkId: number ): EthereumListsChain { + if (!networkId) return const networkData = data.filter( ({ node }: { node: EthereumListsChain }) => node.chainId === networkId ) @@ -71,34 +82,48 @@ export function getNetworkDataById( return networkData[0]?.node } -export function addCustomNetwork( +export async function addCustomNetwork( web3Provider: any, network: NetworkObject -): void { +): Promise { const newNewtworkData = { chainId: `0x${network.chainId.toString(16)}`, chainName: network.name, rpcUrls: network.urlList } - web3Provider.request( - { - method: 'wallet_addEthereumChain', - params: [newNewtworkData] - }, - (err: string, added: any) => { - if (err || 'error' in added) { - Logger.error( - `Couldn't add ${network.name} (0x${ - network.chainId - }) netowrk to MetaMask, error: ${err || added.error}` - ) - } else { - Logger.log( - `Added ${network.name} (0x${network.chainId}) network to MetaMask` - ) - } + try { + await web3Provider.request({ + method: 'wallet_switchEthereumChain', + params: [{ chainId: newNewtworkData.chainId }] + }) + } catch (switchError) { + if (switchError.code === 4902) { + web3Provider.request( + { + method: 'wallet_addEthereumChain', + params: [newNewtworkData] + }, + (err: string, added: any) => { + if (err || 'error' in added) { + Logger.error( + `Couldn't add ${network.name} (0x${ + network.chainId + }) netowrk to MetaMask, error: ${err || added.error}` + ) + } else { + Logger.log( + `Added ${network.name} (0x${network.chainId}) network to MetaMask` + ) + } + } + ) + } else { + Logger.error( + `Couldn't add ${network.name} (0x${network.chainId}) netowrk to MetaMask, error: ${switchError}` + ) } - ) + } + Logger.log(`Added ${network.name} (0x${network.chainId}) network to MetaMask`) } export async function addTokenToWallet(