mirror of
https://github.com/oceanprotocol/market.git
synced 2024-12-02 05:57:29 +01:00
refactor network name output (#421)
* refactor network output * fetch chain & network metadata from @ethereum-lists/chains * typed responses * switch warning icon for testnet badge * add supportedNetworks list, output warning based on it * markup & spacing tweaks * check networkId against ocean.js ConfigHelper * remove supportedNetworks app config * fetch EVM networks metadata on build time * fixes
This commit is contained in:
parent
8158681b91
commit
8737264816
1
.gitignore
vendored
1
.gitignore
vendored
@ -12,4 +12,5 @@ public/storybook
|
|||||||
.artifacts
|
.artifacts
|
||||||
.vercel
|
.vercel
|
||||||
repo-metadata.json
|
repo-metadata.json
|
||||||
|
networks-metadata.json
|
||||||
src/@types/apollo
|
src/@types/apollo
|
@ -4,11 +4,14 @@ module.exports = {
|
|||||||
// networks in their wallet.
|
// networks in their wallet.
|
||||||
// Ocean Protocol contracts are deployed for: 'mainnet', 'rinkeby', 'development'
|
// Ocean Protocol contracts are deployed for: 'mainnet', 'rinkeby', 'development'
|
||||||
network: process.env.GATSBY_NETWORK || 'mainnet',
|
network: process.env.GATSBY_NETWORK || 'mainnet',
|
||||||
|
|
||||||
infuraProjectId: process.env.GATSBY_INFURA_PROJECT_ID || 'xxx',
|
infuraProjectId: process.env.GATSBY_INFURA_PROJECT_ID || 'xxx',
|
||||||
|
|
||||||
// The ETH address the marketplace fee will be sent to.
|
// The ETH address the marketplace fee will be sent to.
|
||||||
marketFeeAddress:
|
marketFeeAddress:
|
||||||
process.env.GATSBY_MARKET_FEE_ADDRESS ||
|
process.env.GATSBY_MARKET_FEE_ADDRESS ||
|
||||||
'0x903322C7E45A60d7c8C3EA236c5beA9Af86310c7',
|
'0x903322C7E45A60d7c8C3EA236c5beA9Af86310c7',
|
||||||
|
|
||||||
// Used for conversion display, can be whatever coingecko API supports
|
// Used for conversion display, can be whatever coingecko API supports
|
||||||
// see: https://api.coingecko.com/api/v3/simple/supported_vs_currencies
|
// see: https://api.coingecko.com/api/v3/simple/supported_vs_currencies
|
||||||
currencies: [
|
currencies: [
|
||||||
|
@ -11,6 +11,14 @@ execSync(`node ./scripts/write-repo-metadata > repo-metadata.json`, {
|
|||||||
// Generate Apollo typings
|
// Generate Apollo typings
|
||||||
execSync(`npm run apollo:codegen`, { stdio: 'inherit' })
|
execSync(`npm run apollo:codegen`, { stdio: 'inherit' })
|
||||||
|
|
||||||
|
// Fetch EVM networks metadata
|
||||||
|
execSync(
|
||||||
|
`node ./scripts/write-networks-metadata > content/networks-metadata.json`,
|
||||||
|
{
|
||||||
|
stdio: 'inherit'
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
exports.onCreateNode = ({ node, actions, getNode }) => {
|
exports.onCreateNode = ({ node, actions, getNode }) => {
|
||||||
createFields(node, actions, getNode)
|
createFields(node, actions, getNode)
|
||||||
}
|
}
|
||||||
|
11
scripts/write-networks-metadata.js
Normal file
11
scripts/write-networks-metadata.js
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
'use strict'
|
||||||
|
|
||||||
|
const axios = require('axios')
|
||||||
|
|
||||||
|
// https://github.com/ethereum-lists/chains
|
||||||
|
const chainDataUrl = 'https://chainid.network/chains.json'
|
||||||
|
|
||||||
|
axios(chainDataUrl).then((response) => {
|
||||||
|
process.stdout.write(JSON.stringify(response.data, null, ' '))
|
||||||
|
})
|
@ -1,8 +1,23 @@
|
|||||||
import React, { ReactElement, ReactNode } from 'react'
|
import React, { ReactElement, ReactNode, useEffect, useState } from 'react'
|
||||||
import { getNetworkName } from '../../utils/wallet'
|
import { EthereumListsChain, getNetworkData } from '../../utils/wallet'
|
||||||
import { ReactComponent as External } from '../../images/external.svg'
|
import { ReactComponent as External } from '../../images/external.svg'
|
||||||
import styles from './EtherscanLink.module.css'
|
import styles from './EtherscanLink.module.css'
|
||||||
import { useSiteMetadata } from '../../hooks/useSiteMetadata'
|
import { useSiteMetadata } from '../../hooks/useSiteMetadata'
|
||||||
|
import { graphql, useStaticQuery } from 'gatsby'
|
||||||
|
|
||||||
|
const networksQuery = graphql`
|
||||||
|
query {
|
||||||
|
allNetworksMetadataJson {
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
chain
|
||||||
|
network
|
||||||
|
networkId
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
export default function EtherscanLink({
|
export default function EtherscanLink({
|
||||||
networkId,
|
networkId,
|
||||||
@ -13,15 +28,24 @@ export default function EtherscanLink({
|
|||||||
path: string
|
path: string
|
||||||
children: ReactNode
|
children: ReactNode
|
||||||
}): ReactElement {
|
}): ReactElement {
|
||||||
|
const data = useStaticQuery(networksQuery)
|
||||||
|
const networksList: { node: EthereumListsChain }[] =
|
||||||
|
data.allNetworksMetadataJson.edges
|
||||||
|
|
||||||
const { appConfig } = useSiteMetadata()
|
const { appConfig } = useSiteMetadata()
|
||||||
const url =
|
const [url, setUrl] = useState<string>()
|
||||||
(!networkId && appConfig.network === 'mainnet') || networkId === 1
|
|
||||||
? `https://etherscan.io`
|
useEffect(() => {
|
||||||
: `https://${
|
const networkData = getNetworkData(networksList, networkId)
|
||||||
networkId
|
const url =
|
||||||
? getNetworkName(networkId).toLowerCase()
|
(!networkId && appConfig.network === 'mainnet') || networkId === 1
|
||||||
: appConfig.network
|
? `https://etherscan.io`
|
||||||
}.etherscan.io`
|
: `https://${
|
||||||
|
networkId ? networkData.network : appConfig.network
|
||||||
|
}.etherscan.io`
|
||||||
|
|
||||||
|
setUrl(url)
|
||||||
|
}, [networkId, networksList, appConfig.network])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<a
|
<a
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
transition: border 0.2s ease-out;
|
transition: border 0.2s ease-out;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
min-width: 190px;
|
min-width: 190px;
|
||||||
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.button,
|
.button,
|
||||||
@ -42,7 +43,7 @@
|
|||||||
.address {
|
.address {
|
||||||
text-transform: none;
|
text-transform: none;
|
||||||
border-right: 1px solid var(--border-color);
|
border-right: 1px solid var(--border-color);
|
||||||
padding-right: calc(var(--spacer) / 4);
|
padding-right: calc(var(--spacer) / 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
.button svg {
|
.button svg {
|
||||||
@ -51,7 +52,7 @@
|
|||||||
fill: var(--border-color);
|
fill: var(--border-color);
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
margin-left: calc(var(--spacer) / 4);
|
margin-left: calc(var(--spacer) / 3);
|
||||||
transition: transform 0.2s ease-out;
|
transition: transform 0.2s ease-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,8 +24,8 @@ const Blockies = ({ account }: { account: string | undefined }) => {
|
|||||||
// Forward ref for Tippy.js
|
// Forward ref for Tippy.js
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
const Account = React.forwardRef((props, ref: any) => {
|
const Account = React.forwardRef((props, ref: any) => {
|
||||||
const { accountId, status, connect, networkId, web3Modal } = useOcean()
|
const { accountId, status, connect, web3Modal } = useOcean()
|
||||||
const hasSuccess = status === 1 && networkId === 1
|
const hasSuccess = status === 1
|
||||||
|
|
||||||
async function handleActivation(e: FormEvent<HTMLButtonElement>) {
|
async function handleActivation(e: FormEvent<HTMLButtonElement>) {
|
||||||
// prevent accidentially submitting a form the button might be in
|
// prevent accidentially submitting a form the button might be in
|
||||||
|
@ -2,7 +2,6 @@ import React, { ReactElement } from 'react'
|
|||||||
import Status from '../../atoms/Status'
|
import Status from '../../atoms/Status'
|
||||||
import styles from './Feedback.module.css'
|
import styles from './Feedback.module.css'
|
||||||
import { useOcean } from '@oceanprotocol/react'
|
import { useOcean } from '@oceanprotocol/react'
|
||||||
import { getNetworkName } from '../../../utils/wallet'
|
|
||||||
|
|
||||||
export declare type Web3Error = {
|
export declare type Web3Error = {
|
||||||
status: 'error' | 'warning' | 'success'
|
status: 'error' | 'warning' | 'success'
|
||||||
@ -15,19 +14,13 @@ export default function Web3Feedback({
|
|||||||
}: {
|
}: {
|
||||||
isBalanceSufficient?: boolean
|
isBalanceSufficient?: boolean
|
||||||
}): ReactElement {
|
}): ReactElement {
|
||||||
const { account, status, networkId } = useOcean()
|
const { account, status } = useOcean()
|
||||||
const isOceanConnectionError = status === -1
|
const isOceanConnectionError = status === -1
|
||||||
const isMainnet = networkId === 1
|
|
||||||
const showFeedback =
|
const showFeedback =
|
||||||
!account ||
|
!account || isOceanConnectionError || isBalanceSufficient === false
|
||||||
isOceanConnectionError ||
|
|
||||||
!isMainnet ||
|
|
||||||
isBalanceSufficient === false
|
|
||||||
|
|
||||||
const state = !account
|
const state = !account
|
||||||
? 'error'
|
? 'error'
|
||||||
: !isMainnet
|
|
||||||
? 'warning'
|
|
||||||
: account && isBalanceSufficient
|
: account && isBalanceSufficient
|
||||||
? 'success'
|
? 'success'
|
||||||
: 'warning'
|
: 'warning'
|
||||||
@ -36,8 +29,6 @@ export default function Web3Feedback({
|
|||||||
? 'No account connected'
|
? 'No account connected'
|
||||||
: isOceanConnectionError
|
: isOceanConnectionError
|
||||||
? 'Error connecting to Ocean'
|
? 'Error connecting to Ocean'
|
||||||
: !isMainnet
|
|
||||||
? getNetworkName(networkId)
|
|
||||||
: account
|
: account
|
||||||
? isBalanceSufficient === false
|
? isBalanceSufficient === false
|
||||||
? 'Insufficient balance'
|
? 'Insufficient balance'
|
||||||
@ -48,8 +39,6 @@ export default function Web3Feedback({
|
|||||||
? 'Please connect your Web3 wallet.'
|
? 'Please connect your Web3 wallet.'
|
||||||
: isOceanConnectionError
|
: isOceanConnectionError
|
||||||
? 'Please try again.'
|
? 'Please try again.'
|
||||||
: !isMainnet
|
|
||||||
? undefined
|
|
||||||
: isBalanceSufficient === false
|
: isBalanceSufficient === false
|
||||||
? 'You do not have enough OCEAN in your wallet to purchase this asset.'
|
? 'You do not have enough OCEAN in your wallet to purchase this asset.'
|
||||||
: 'Something went wrong.'
|
: 'Something went wrong.'
|
||||||
|
27
src/components/molecules/Wallet/Network.module.css
Normal file
27
src/components/molecules/Wallet/Network.module.css
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
.network {
|
||||||
|
border: 1px solid var(--border-color);
|
||||||
|
border-right: none;
|
||||||
|
border-top-left-radius: var(--border-radius);
|
||||||
|
border-bottom-left-radius: var(--border-radius);
|
||||||
|
padding: calc(var(--spacer) / 4) calc(var(--spacer) / 2);
|
||||||
|
white-space: nowrap;
|
||||||
|
margin-right: -3px;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.name {
|
||||||
|
font-size: var(--font-size-small);
|
||||||
|
display: inline-block;
|
||||||
|
text-transform: capitalize;
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge {
|
||||||
|
margin-left: calc(var(--spacer) / 8);
|
||||||
|
background-color: var(--border-color);
|
||||||
|
color: var(--font-color-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
.warning {
|
||||||
|
margin-right: calc(var(--spacer) / 4);
|
||||||
|
}
|
74
src/components/molecules/Wallet/Network.tsx
Normal file
74
src/components/molecules/Wallet/Network.tsx
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
import React, { useState, useEffect, ReactElement } from 'react'
|
||||||
|
import { useOcean } from '@oceanprotocol/react'
|
||||||
|
import Status from '../../atoms/Status'
|
||||||
|
import {
|
||||||
|
EthereumListsChain,
|
||||||
|
getNetworkData,
|
||||||
|
getNetworkDisplayName
|
||||||
|
} from '../../../utils/wallet'
|
||||||
|
import { ConfigHelper } from '@oceanprotocol/lib'
|
||||||
|
import { ConfigHelperConfig } from '@oceanprotocol/lib/dist/node/utils/ConfigHelper'
|
||||||
|
import styles from './Network.module.css'
|
||||||
|
import Badge from '../../atoms/Badge'
|
||||||
|
import Tooltip from '../../atoms/Tooltip'
|
||||||
|
import { graphql, useStaticQuery } from 'gatsby'
|
||||||
|
|
||||||
|
const networksQuery = graphql`
|
||||||
|
query NetworksQuery {
|
||||||
|
allNetworksMetadataJson {
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
chain
|
||||||
|
network
|
||||||
|
networkId
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
export default function Network(): ReactElement {
|
||||||
|
const data = useStaticQuery(networksQuery)
|
||||||
|
const networksList: { node: EthereumListsChain }[] =
|
||||||
|
data.allNetworksMetadataJson.edges
|
||||||
|
|
||||||
|
const { config, networkId } = useOcean()
|
||||||
|
const networkIdConfig = (config as ConfigHelperConfig).networkId
|
||||||
|
|
||||||
|
const [isEthMainnet, setIsEthMainnet] = useState<boolean>()
|
||||||
|
const [networkName, setNetworkName] = useState<string>()
|
||||||
|
const [isTestnet, setIsTestnet] = useState<boolean>()
|
||||||
|
const [isSupportedNetwork, setIsSupportedNetwork] = useState<boolean>()
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// take network from user when present,
|
||||||
|
// otherwise use the default configured one of app
|
||||||
|
const network = networkId || networkIdConfig
|
||||||
|
const isEthMainnet = network === 1
|
||||||
|
setIsEthMainnet(isEthMainnet)
|
||||||
|
|
||||||
|
// Check networkId against ocean.js ConfigHelper configs
|
||||||
|
// to figure out if network is supported.
|
||||||
|
const isSupportedNetwork = Boolean(new ConfigHelper().getConfig(network))
|
||||||
|
setIsSupportedNetwork(isSupportedNetwork)
|
||||||
|
|
||||||
|
// Figure out if we're on a chain's testnet, or not
|
||||||
|
const networkData = getNetworkData(networksList, network)
|
||||||
|
setIsTestnet(networkData.network !== 'mainnet')
|
||||||
|
|
||||||
|
const networkName = getNetworkDisplayName(networkData, network)
|
||||||
|
setNetworkName(networkName)
|
||||||
|
}, [networkId, networkIdConfig, networksList])
|
||||||
|
|
||||||
|
return !isEthMainnet && networkName ? (
|
||||||
|
<div className={styles.network}>
|
||||||
|
{!isSupportedNetwork && (
|
||||||
|
<Tooltip content="No Ocean Protocol contracts are deployed to this network.">
|
||||||
|
<Status state="error" className={styles.warning} />
|
||||||
|
</Tooltip>
|
||||||
|
)}
|
||||||
|
<span className={styles.name}>{networkName}</span>
|
||||||
|
{isTestnet && <Badge label="Test" className={styles.badge} />}
|
||||||
|
</div>
|
||||||
|
) : null
|
||||||
|
}
|
3
src/components/molecules/Wallet/index.module.css
Normal file
3
src/components/molecules/Wallet/index.module.css
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
.wallet {
|
||||||
|
display: flex;
|
||||||
|
}
|
@ -2,14 +2,23 @@ import React, { ReactElement } from 'react'
|
|||||||
import Account from './Account'
|
import Account from './Account'
|
||||||
import Details from './Details'
|
import Details from './Details'
|
||||||
import Tooltip from '../../atoms/Tooltip'
|
import Tooltip from '../../atoms/Tooltip'
|
||||||
|
import Network from './Network'
|
||||||
import { useOcean } from '@oceanprotocol/react'
|
import { useOcean } from '@oceanprotocol/react'
|
||||||
|
import styles from './index.module.css'
|
||||||
|
|
||||||
export default function Wallet(): ReactElement {
|
export default function Wallet(): ReactElement {
|
||||||
const { accountId } = useOcean()
|
const { accountId } = useOcean()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Tooltip content={<Details />} trigger="click focus" disabled={!accountId}>
|
<div className={styles.wallet}>
|
||||||
<Account />
|
<Network />
|
||||||
</Tooltip>
|
<Tooltip
|
||||||
|
content={<Details />}
|
||||||
|
trigger="click focus"
|
||||||
|
disabled={!accountId}
|
||||||
|
>
|
||||||
|
<Account />
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,19 @@
|
|||||||
import {
|
import { infuraProjectId as infuraId, portisId } from '../../app.config'
|
||||||
infuraProjectId as infuraId,
|
|
||||||
portisId,
|
|
||||||
network
|
|
||||||
} from '../../app.config'
|
|
||||||
import WalletConnectProvider from '@walletconnect/web3-provider'
|
import WalletConnectProvider from '@walletconnect/web3-provider'
|
||||||
|
|
||||||
|
export interface EthereumListsChain {
|
||||||
|
name: string
|
||||||
|
chainId: number
|
||||||
|
shortName: string
|
||||||
|
chain: string
|
||||||
|
network: string
|
||||||
|
networkId: number
|
||||||
|
nativeCurrency: { name: string; symbol: string; decimals: number }
|
||||||
|
rpc: string[]
|
||||||
|
faucets: string[]
|
||||||
|
infoURL: string
|
||||||
|
}
|
||||||
|
|
||||||
const web3ModalTheme = {
|
const web3ModalTheme = {
|
||||||
background: 'var(--background-body)',
|
background: 'var(--background-body)',
|
||||||
main: 'var(--font-color-heading)',
|
main: 'var(--font-color-heading)',
|
||||||
@ -47,28 +56,6 @@ export const web3ModalOpts = {
|
|||||||
theme: web3ModalTheme
|
theme: web3ModalTheme
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getNetworkId(network: string): number {
|
|
||||||
switch (network) {
|
|
||||||
case 'mainnet':
|
|
||||||
return 1
|
|
||||||
case 'ropsten':
|
|
||||||
return 3
|
|
||||||
case 'rinkeby':
|
|
||||||
return 4
|
|
||||||
case 'kovan':
|
|
||||||
return 42
|
|
||||||
case 'development':
|
|
||||||
return 8996
|
|
||||||
default:
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isDefaultNetwork(networkId: number): boolean {
|
|
||||||
const configuredNetwork = getNetworkId(network)
|
|
||||||
return configuredNetwork === networkId
|
|
||||||
}
|
|
||||||
|
|
||||||
export function accountTruncate(account: string): string {
|
export function accountTruncate(account: string): string {
|
||||||
if (!account) return
|
if (!account) return
|
||||||
const middle = account.substring(6, 38)
|
const middle = account.substring(6, 38)
|
||||||
@ -76,19 +63,25 @@ export function accountTruncate(account: string): string {
|
|||||||
return truncated
|
return truncated
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getNetworkName(networkId: number): string {
|
export function getNetworkDisplayName(
|
||||||
switch (networkId) {
|
data: EthereumListsChain,
|
||||||
case 1:
|
networkId: number
|
||||||
return 'Main'
|
): string {
|
||||||
case 3:
|
const displayName = data
|
||||||
return 'Ropsten'
|
? `${data.chain} ${data.network === 'mainnet' ? '' : data.network}`
|
||||||
case 4:
|
: networkId === 8996
|
||||||
return 'Rinkeby'
|
? 'Development'
|
||||||
case 42:
|
: 'Unknown'
|
||||||
return 'Kovan'
|
|
||||||
case 8996:
|
return displayName
|
||||||
return 'Development'
|
}
|
||||||
default:
|
|
||||||
return 'Unknown'
|
export function getNetworkData(
|
||||||
}
|
data: { node: EthereumListsChain }[],
|
||||||
|
networkId: number
|
||||||
|
): EthereumListsChain {
|
||||||
|
const networkData = data.filter(
|
||||||
|
({ node }: { node: EthereumListsChain }) => node.networkId === networkId
|
||||||
|
)[0]
|
||||||
|
return networkData.node
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user