1
0
mirror of https://github.com/oceanprotocol/market.git synced 2024-12-02 05:57:29 +01:00

Add custom network (#450)

* add custom network

* created announcement banner

* add custom network from banner

* show ADD CUSTOM NETWORK on MetaMask provider

* show add ocean to wallet action

* removed warningPolygon from alert

* removed customNetwork component

* remove Add custom network on asset details page

* Details use function from web3 to add token

* changed available on Polygon link, refactoring

* show Switch to Polygon when no wallet connected

* banner content for no provider and Polygon network

* change message when not provider and eth network

* changed warning and added announcement in site.json

* moved network logic inside Announcement, moved Announcement component

* added switch to ETH button, refactoring

* removed add mOcean action button

* moved location verification to App.tsx

* styling & copy updates

Co-authored-by: Matthias Kretschmann <m@kretschmann.io>
This commit is contained in:
Norbi 2021-03-30 16:37:30 +03:00 committed by GitHub
parent 6190737f08
commit 96296008c9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 234 additions and 55 deletions

View File

@ -16,8 +16,13 @@
"link": "/history" "link": "/history"
} }
], ],
"warning": "We are in beta. Please familiarize yourself with [the market](https://oceanprotocol.com/technology/marketplaces), [the risks](https://blog.oceanprotocol.com/on-staking-on-data-in-ocean-market-3d8e09eb0a13), and the [Terms of Use](/terms).", "warning": {
"warningPolygon": "Polygon/Matic EVM support is in early stages. Use the Matic bridge to [get mOCEAN](https://docs.oceanprotocol.com/tutorials/polygon-bridge/).", "main": "We are in beta. Please familiarize yourself with [the market](https://oceanprotocol.com/technology/marketplaces), [the risks](https://blog.oceanprotocol.com/on-staking-on-data-in-ocean-market-3d8e09eb0a13), and the [Terms of Use](/terms).",
"warningPolygonPublish": "Only republish data sets with a pool from ETH Mainnet into Polygon/Matic if the liquidity is **less than or equal to 1000 OCEAN in the original pool**. Doing otherwise will lead to [purgatory](https://github.com/oceanprotocol/list-purgatory) for the data set in Polygon/Matic." "polygonPublish": "Only republish data sets with a pool from ETH Mainnet into Polygon/Matic if the liquidity is **less than or equal to 1000 OCEAN in the original pool**. Doing otherwise will lead to [purgatory](https://github.com/oceanprotocol/list-purgatory) for the data set in Polygon/Matic."
},
"announcement": {
"main": "Ocean Market is [available on Polygon](https://blog.oceanprotocol.com/ocean-on-polygon-network-8abad19cbf47).",
"polygon": "Polygon/Matic EVM support is in early stages. [Use the Polygon Bridge](https://docs.oceanprotocol.com/tutorials/polygon-bridge/) to get mOCEAN."
}
} }
} }

View File

@ -7,6 +7,7 @@ import { useSiteMetadata } from '../hooks/useSiteMetadata'
import Alert from './atoms/Alert' import Alert from './atoms/Alert'
import { graphql, PageProps, useStaticQuery } from 'gatsby' import { graphql, PageProps, useStaticQuery } from 'gatsby'
import { useAccountPurgatory } from '../hooks/useAccountPurgatory' import { useAccountPurgatory } from '../hooks/useAccountPurgatory'
import AnnouncementBanner from './molecules/AnnouncementBanner'
import { useWeb3 } from '../providers/Web3' import { useWeb3 } from '../providers/Web3'
const contentQuery = graphql` const contentQuery = graphql`
@ -35,20 +36,17 @@ export default function App({
const data = useStaticQuery(contentQuery) const data = useStaticQuery(contentQuery)
const purgatory = data.purgatory.edges[0].node.childContentJson.account const purgatory = data.purgatory.edges[0].node.childContentJson.account
const { warning, warningPolygon } = useSiteMetadata() const { warning } = useSiteMetadata()
const { accountId } = useWeb3() const { accountId } = useWeb3()
const { isInPurgatory, purgatoryData } = useAccountPurgatory(accountId) const { isInPurgatory, purgatoryData } = useAccountPurgatory(accountId)
const { networkId } = useWeb3()
return ( return (
<Styles> <Styles>
<div className={styles.app}> <div className={styles.app}>
{!location.pathname.includes('/asset/did') && <AnnouncementBanner />}
<Header /> <Header />
{(props as PageProps).uri === '/' && ( {(props as PageProps).uri === '/' && (
<Alert <Alert text={warning.main} state="info" />
text={(networkId === 137 ? `${warningPolygon}\n\n` : '') + warning}
state="info"
/>
)} )}
{isInPurgatory && ( {isInPurgatory && (
<Alert <Alert

View File

@ -0,0 +1,31 @@
.banner {
text-align: center;
padding: calc(var(--spacer) / 5) calc(var(--spacer) / 2);
border-bottom: 1px solid var(--border-color);
background-color: var(--background-content);
}
.banner > div {
display: inline-block;
}
.banner button {
font-size: calc(var(--font-size-small) / 1.1);
}
.text {
font-size: var(--font-size-small);
font-weight: var(--font-weight-bold);
margin: 0;
margin-right: calc(var(--spacer) / 4);
text-align: center;
}
.text a {
color: inherit;
text-decoration: underline;
}
.text p:last-child {
margin-bottom: 0;
}

View File

@ -0,0 +1,103 @@
import React, { ReactElement, useEffect, useState } from 'react'
import styles from './AnnouncementBanner.module.css'
import Markdown from '../atoms/Markdown'
import { useWeb3 } from '../../providers/Web3'
import { addCustomNetwork, NetworkObject } from '../../utils/web3'
import { getOceanConfig } from '../../utils/ocean'
import { getProviderInfo } from 'web3modal'
import { useOcean } from '../../providers/Ocean'
import { useSiteMetadata } from '../../hooks/useSiteMetadata'
import Button from '../atoms/Button'
export interface AnnouncementAction {
name: string
style?: string
handleAction: () => void
}
const network: NetworkObject = {
chainId: 137,
name: 'Matic Network',
urlList: [
'https://rpc-mainnet.matic.network',
'https://rpc-mainnet.maticvigil.com/'
]
}
export default function AnnouncementBanner(): ReactElement {
const { web3Provider } = useWeb3()
const { config, connect } = useOcean()
const { announcement } = useSiteMetadata()
const [text, setText] = useState<string>(announcement.main)
const [action, setAction] = useState<AnnouncementAction>()
const addCustomNetworkAction = {
name: 'Add custom network',
handleAction: () => addCustomNetwork(web3Provider, network)
}
const switchToPolygonAction = {
name: 'Switch to Polygon',
handleAction: async () => {
const config = getOceanConfig('polygon')
await connect(config)
}
}
const switchToEthAction = {
name: 'Switch to ETH',
handleAction: async () => {
const config = getOceanConfig('mainnet')
await connect(config)
}
}
function setBannerForMatic() {
setText(announcement.polygon)
setAction(undefined)
}
useEffect(() => {
if (!web3Provider && !config) return
const providerInfo = getProviderInfo(web3Provider)
switch (providerInfo?.name) {
case 'Web3':
if (config.networkId !== 137) {
setText(announcement.main)
setAction(switchToPolygonAction)
} else {
setText(announcement.polygon)
setAction(switchToEthAction)
}
break
case 'MetaMask':
if (config.networkId === 137) {
setBannerForMatic()
} else {
setText(announcement.main)
setAction(addCustomNetworkAction)
}
break
default:
if (config.networkId === 137) {
setBannerForMatic()
} else {
setText(announcement.main)
setAction(undefined)
}
}
}, [web3Provider, config, announcement])
return (
<div className={styles.container}>
<div className={styles.banner}>
{text && <Markdown className={styles.text} text={text} />}
{action && (
<Button style="text" size="small" onClick={action.handleAction}>
{action.name}
</Button>
)}
</div>
</div>
)
}

View File

@ -8,6 +8,7 @@ import Conversion from '../../atoms/Price/Conversion'
import { formatCurrency } from '@coingecko/cryptoformat' import { formatCurrency } from '@coingecko/cryptoformat'
import { useUserPreferences } from '../../../providers/UserPreferences' import { useUserPreferences } from '../../../providers/UserPreferences'
import { useWeb3 } from '../../../providers/Web3' import { useWeb3 } from '../../../providers/Web3'
import { addOceanToWallet } from '../../../utils/web3'
import { Logger } from '@oceanprotocol/lib' import { Logger } from '@oceanprotocol/lib'
export default function Details(): ReactElement { export default function Details(): ReactElement {
@ -27,39 +28,6 @@ export default function Details(): ReactElement {
setProviderInfo(providerInfo) setProviderInfo(providerInfo)
}, [web3Provider]) }, [web3Provider])
async function addOceanToWallet() {
const tokenMetadata = {
type: 'ERC20',
options: {
address: config.oceanTokenAddress,
symbol: config.oceanTokenSymbol,
decimals: 18,
image:
'https://raw.githubusercontent.com/oceanprotocol/art/main/logo/token.png'
}
}
web3Provider.sendAsync(
{
method: 'wallet_watchAsset',
params: tokenMetadata,
id: Math.round(Math.random() * 100000)
},
(err: string, added: any) => {
if (err || 'error' in added) {
Logger.error(
`Couldn't add ${tokenMetadata.options.symbol} (${
tokenMetadata.options.address
}) to MetaMask, error: ${err || added.error}`
)
} else {
Logger.log(
`Added ${tokenMetadata.options.symbol} (${tokenMetadata.options.address}) to MetaMask`
)
}
}
)
}
useEffect(() => { useEffect(() => {
if (!networkData) return if (!networkData) return
@ -112,7 +80,7 @@ export default function Details(): ReactElement {
style="text" style="text"
size="small" size="small"
onClick={() => { onClick={() => {
addOceanToWallet() addOceanToWallet(config, web3Provider)
}} }}
> >
{`Add ${config.oceanTokenSymbol}`} {`Add ${config.oceanTokenSymbol}`}

View File

@ -174,7 +174,7 @@ export default function Add({
) : ( ) : (
<Alert <Alert
className={styles.warning} className={styles.warning}
text={content.warning} text={content.warning.main}
state="info" state="info"
action={{ action={{
name: 'I understand', name: 'I understand',

View File

@ -129,7 +129,7 @@ export default function FormTrade({
) : ( ) : (
<div className={styles.alertWrap}> <div className={styles.alertWrap}>
<Alert <Alert
text={content.warning} text={content.warning.main}
state="info" state="info"
action={{ action={{
name: 'I understand', name: 'I understand',

View File

@ -20,7 +20,6 @@ import Alert from '../../atoms/Alert'
import MetadataFeedback from '../../molecules/MetadataFeedback' import MetadataFeedback from '../../molecules/MetadataFeedback'
import { useAccountPurgatory } from '../../../hooks/useAccountPurgatory' import { useAccountPurgatory } from '../../../hooks/useAccountPurgatory'
import { useWeb3 } from '../../../providers/Web3' import { useWeb3 } from '../../../providers/Web3'
import { useSiteMetadata } from '../../../hooks/useSiteMetadata'
const formName = 'ocean-publish-form' const formName = 'ocean-publish-form'
@ -29,9 +28,8 @@ export default function PublishPage({
}: { }: {
content: { warning: string; form: FormContent } content: { warning: string; form: FormContent }
}): ReactElement { }): ReactElement {
const { warningPolygonPublish } = useSiteMetadata()
const { debug } = useUserPreferences() const { debug } = useUserPreferences()
const { accountId, networkId } = useWeb3() const { accountId } = useWeb3()
const { isInPurgatory, purgatoryData } = useAccountPurgatory(accountId) const { isInPurgatory, purgatoryData } = useAccountPurgatory(accountId)
const { publish, publishError, isLoading, publishStepText } = usePublish() const { publish, publishError, isLoading, publishStepText } = usePublish()
const [success, setSuccess] = useState<string>() const [success, setSuccess] = useState<string>()
@ -114,10 +112,7 @@ export default function PublishPage({
) : ( ) : (
<> <>
<Alert <Alert
text={ text={content.warning}
(networkId === 137 ? `${warningPolygonPublish}\n\n` : '') +
content.warning
}
state="info" state="info"
className={styles.alert} className={styles.alert}
/> />

View File

@ -13,9 +13,14 @@ const query = graphql`
name name
link link
} }
warning warning {
warningPolygon main
warningPolygonPublish polygonPublish
}
announcement {
main
polygon
}
appConfig { appConfig {
infuraProjectId infuraProjectId
network network

View File

@ -1,3 +1,6 @@
import { Logger } from '@oceanprotocol/lib'
import { ConfigHelperConfig } from '@oceanprotocol/lib/dist/node/utils/ConfigHelper'
export interface EthereumListsChain { export interface EthereumListsChain {
name: string name: string
chainId: number chainId: number
@ -11,6 +14,12 @@ export interface EthereumListsChain {
infoURL: string infoURL: string
} }
export interface NetworkObject {
chainId: number
name: string
urlList: string[]
}
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)
@ -40,3 +49,68 @@ export function getNetworkData(
)[0] )[0]
return networkData.node return networkData.node
} }
export function addCustomNetwork(
web3Provider: any,
network: NetworkObject
): void {
const newNewtworkData = {
chainId: `0x${network.chainId.toString(16)}`,
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`
)
}
}
)
}
export function addOceanToWallet(
config: ConfigHelperConfig,
web3Provider: any
): void {
const tokenMetadata = {
type: 'ERC20',
options: {
address: config.oceanTokenAddress,
symbol: config.oceanTokenSymbol,
decimals: 18,
image:
'https://raw.githubusercontent.com/oceanprotocol/art/main/logo/token.png'
}
}
web3Provider.sendAsync(
{
method: 'wallet_watchAsset',
params: tokenMetadata,
id: Math.round(Math.random() * 100000)
},
(err: string, added: any) => {
if (err || 'error' in added) {
Logger.error(
`Couldn't add ${tokenMetadata.options.symbol} (${
tokenMetadata.options.address
}) to MetaMask, error: ${err || added.error}`
)
} else {
Logger.log(
`Added ${tokenMetadata.options.symbol} (${tokenMetadata.options.address}) to MetaMask`
)
}
}
)
}