mirror of
https://github.com/oceanprotocol/market.git
synced 2024-12-02 05:57:29 +01:00
Merge branch 'main' into feature/compute
This commit is contained in:
commit
df587bb5b5
33
README.md
33
README.md
@ -18,6 +18,7 @@
|
||||
- [Ocean Protocol Subgraph](#ocean-protocol-subgraph)
|
||||
- [3Box](#3box)
|
||||
- [Purgatory](#purgatory)
|
||||
- [Network Metadata](#network-metadata)
|
||||
- [🎨 Storybook](#-storybook)
|
||||
- [✨ Code Style](#-code-style)
|
||||
- [👩🔬 Testing](#-testing)
|
||||
@ -229,6 +230,8 @@ function Component() {
|
||||
|
||||
Based on [list-purgatory](https://github.com/oceanprotocol/list-purgatory) some data sets get additional data. Within most components this can be done with the internal `useAsset()` hook which fetches data from the [market-purgatory](https://github.com/oceanprotocol/market-purgatory) endpoint in the background.
|
||||
|
||||
For asset purgatory:
|
||||
|
||||
```tsx
|
||||
import { useAsset } from '../../../providers/Asset'
|
||||
|
||||
@ -238,6 +241,36 @@ function Component() {
|
||||
}
|
||||
```
|
||||
|
||||
For account purgatory:
|
||||
|
||||
```tsx
|
||||
import { useWeb3 } from '../../../providers/Web3'
|
||||
import { useAccountPurgatory } from '../../../hooks/useAccountPurgatory'
|
||||
|
||||
function Component() {
|
||||
const { accountId } = useWeb3()
|
||||
const { isInPurgatory, purgatoryData } = useAccountPurgatory(accountId)
|
||||
return isInPurgatory ? <div>{purgatoryData.reason}</div> : null
|
||||
}
|
||||
```
|
||||
|
||||
### Network Metadata
|
||||
|
||||
All displayed chain & network metadata is retrieved from `https://chainid.network` on build time and integrated into Gatsby's GraphQL layer. This data source is a community-maintained GitHub repository under [ethereum-lists/chains](https://github.com/ethereum-lists/chains).
|
||||
|
||||
Within components this metadata can be queried for under `allNetworksMetadataJson`. The `useWeb3()` hook does this in the background to expose the final `networkDisplayName` for use in components:
|
||||
|
||||
```tsx
|
||||
export default function NetworkName(): ReactElement {
|
||||
const { networkDisplayName, isTestnet } = useWeb3()
|
||||
return (
|
||||
<>
|
||||
{networkDisplayName} {isTestnet && `(Test)`}
|
||||
</>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
## 🎨 Storybook
|
||||
|
||||
> TODO: this is broken for most components. See https://github.com/oceanprotocol/market/issues/128
|
||||
|
@ -3,7 +3,7 @@ module.exports = {
|
||||
service: {
|
||||
name: 'ocean',
|
||||
url:
|
||||
'https://subgraph.mainnet.oceanprotocol.com/subgraphs/name/oceanprotocol/ocean-subgraph',
|
||||
'https://subgraph.rinkeby.oceanprotocol.com/subgraphs/name/oceanprotocol/ocean-subgraph',
|
||||
// optional disable SSL validation check
|
||||
skipSSLValidation: true
|
||||
}
|
||||
|
@ -16,6 +16,8 @@
|
||||
"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": "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).",
|
||||
"warningPolygon": "Polygon/Matic EVM support is in early stages. Use the Matic bridge to [get mOCEAN](https://docs.oceanprotocol.com/tutorials/polygon-bridge/).",
|
||||
"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."
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,3 @@
|
||||
const path = require('path')
|
||||
const createFields = require('./gatsby/createFields')
|
||||
const createMarkdownPages = require('./gatsby/createMarkdownPages')
|
||||
const execSync = require('child_process').execSync
|
||||
@ -48,14 +47,6 @@ exports.onCreateWebpackConfig = ({ actions }) => {
|
||||
fs: 'empty'
|
||||
},
|
||||
// fix for 'got'/'swarm-js' dependency
|
||||
externals: ['got'],
|
||||
|
||||
// fix for being able to use `npm link` with @oceanprotocol/react
|
||||
// see https://github.com/facebook/react/issues/13991
|
||||
resolve: {
|
||||
alias: {
|
||||
react: path.resolve('./node_modules/react')
|
||||
}
|
||||
}
|
||||
externals: ['got']
|
||||
})
|
||||
}
|
||||
|
12
package-lock.json
generated
12
package-lock.json
generated
@ -3643,18 +3643,6 @@
|
||||
"web3-eth-contract": "^1.3.4"
|
||||
}
|
||||
},
|
||||
"@oceanprotocol/react": {
|
||||
"version": "0.5.5",
|
||||
"resolved": "https://registry.npmjs.org/@oceanprotocol/react/-/react-0.5.5.tgz",
|
||||
"integrity": "sha512-2xkdiU7vsV+MbS4FD3xrUIud6oZ6ognuLg8zesV8yGND4WlyNR95g2bp3L93H0asg65VdYh5ZSyNzxPHKjzqhg==",
|
||||
"requires": {
|
||||
"@oceanprotocol/lib": "^0.11.4",
|
||||
"axios": "^0.21.1",
|
||||
"decimal.js": "^10.2.1",
|
||||
"web3": "1.3.4",
|
||||
"web3modal": "^1.9.3"
|
||||
}
|
||||
},
|
||||
"@oceanprotocol/typographies": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@oceanprotocol/typographies/-/typographies-0.1.0.tgz",
|
||||
|
@ -23,12 +23,11 @@
|
||||
"postinstall": "husky install"
|
||||
},
|
||||
"dependencies": {
|
||||
"@apollo/client": "^3.3.6",
|
||||
"@apollo/client": "^3.3.11",
|
||||
"@coingecko/cryptoformat": "^0.4.2",
|
||||
"@loadable/component": "^5.14.1",
|
||||
"@oceanprotocol/art": "^3.0.0",
|
||||
"@oceanprotocol/lib": "^0.11.4",
|
||||
"@oceanprotocol/react": "^0.5.5",
|
||||
"@oceanprotocol/typographies": "^0.1.0",
|
||||
"@portis/web3": "^3.0.3",
|
||||
"@sindresorhus/slugify": "^1.0.0",
|
||||
@ -87,7 +86,8 @@
|
||||
"slugify": "^1.4.6",
|
||||
"swr": "^0.3.11",
|
||||
"use-dark-mode": "^2.3.1",
|
||||
"web3": "^1.3.1",
|
||||
"web3": "^1.3.4",
|
||||
"web3modal": "^1.9.3",
|
||||
"yup": "^0.32.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
3
src/@types/MetaData.d.ts
vendored
3
src/@types/MetaData.d.ts
vendored
@ -4,7 +4,8 @@ import {
|
||||
AdditionalInformation,
|
||||
ServiceMetadata
|
||||
} from '@oceanprotocol/lib'
|
||||
import { DataTokenOptions, PriceOptions } from '@oceanprotocol/react'
|
||||
import { DataTokenOptions } from '../hooks/usePublish'
|
||||
import { PriceOptions } from '../hooks/usePricing'
|
||||
|
||||
export interface AdditionalInformationMarket extends AdditionalInformation {
|
||||
links?: File[]
|
||||
|
7
src/@types/TokenBalance.d.ts
vendored
7
src/@types/TokenBalance.d.ts
vendored
@ -1,4 +1,9 @@
|
||||
export default interface TokenBalance {
|
||||
export interface PoolBalance {
|
||||
ocean: number
|
||||
datatoken: number
|
||||
}
|
||||
|
||||
export interface UserBalance {
|
||||
eth: string
|
||||
ocean: string
|
||||
}
|
||||
|
@ -4,9 +4,10 @@ import Header from './organisms/Header'
|
||||
import Styles from '../global/Styles'
|
||||
import styles from './App.module.css'
|
||||
import { useSiteMetadata } from '../hooks/useSiteMetadata'
|
||||
import { useOcean } from '@oceanprotocol/react'
|
||||
import Alert from './atoms/Alert'
|
||||
import { graphql, PageProps, useStaticQuery } from 'gatsby'
|
||||
import { useAccountPurgatory } from '../hooks/useAccountPurgatory'
|
||||
import { useWeb3 } from '../providers/Web3'
|
||||
|
||||
const contentQuery = graphql`
|
||||
query AppQuery {
|
||||
@ -34,23 +35,25 @@ export default function App({
|
||||
const data = useStaticQuery(contentQuery)
|
||||
const purgatory = data.purgatory.edges[0].node.childContentJson.account
|
||||
|
||||
const { warning } = useSiteMetadata()
|
||||
const {
|
||||
isInPurgatory: isAccountInPurgatory,
|
||||
purgatoryData: accountPurgatory
|
||||
} = useOcean()
|
||||
const { warning, warningPolygon } = useSiteMetadata()
|
||||
const { accountId } = useWeb3()
|
||||
const { isInPurgatory, purgatoryData } = useAccountPurgatory(accountId)
|
||||
const { networkId } = useWeb3()
|
||||
|
||||
return (
|
||||
<Styles>
|
||||
<div className={styles.app}>
|
||||
<Header />
|
||||
{(props as PageProps).uri === '/' && (
|
||||
<Alert text={warning} state="info" />
|
||||
<Alert
|
||||
text={(networkId === 137 ? `${warningPolygon}\n\n` : '') + warning}
|
||||
state="info"
|
||||
/>
|
||||
)}
|
||||
{isAccountInPurgatory && (
|
||||
{isInPurgatory && (
|
||||
<Alert
|
||||
title={purgatory.title}
|
||||
badge={`Reason: ${accountPurgatory?.reason}`}
|
||||
badge={`Reason: ${purgatoryData?.reason}`}
|
||||
text={purgatory.description}
|
||||
state="error"
|
||||
/>
|
||||
|
@ -1,18 +0,0 @@
|
||||
.dropzone {
|
||||
padding: var(--spacer);
|
||||
text-align: center;
|
||||
color: var(--color-secondary);
|
||||
border: 0.1rem dashed var(--color-secondary);
|
||||
font-size: var(--font-size-small);
|
||||
border-radius: var(--border-radius);
|
||||
}
|
||||
|
||||
.dragover {
|
||||
border-color: var(--color-primary);
|
||||
}
|
||||
|
||||
.disabled {
|
||||
}
|
||||
|
||||
.error {
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
import React from 'react'
|
||||
import Dropzone from './Dropzone'
|
||||
|
||||
export default {
|
||||
title: 'Atoms/Dropzone'
|
||||
}
|
||||
|
||||
export const Default = () => <Dropzone handleOnDrop={() => null} />
|
@ -1,68 +0,0 @@
|
||||
import React, { ReactElement, useCallback } from 'react'
|
||||
import { useDropzone } from 'react-dropzone'
|
||||
import styles from './Dropzone.module.css'
|
||||
import { formatBytes } from '../../utils'
|
||||
|
||||
export default function Dropzone({
|
||||
handleOnDrop,
|
||||
disabled,
|
||||
multiple,
|
||||
error
|
||||
}: {
|
||||
handleOnDrop(files: File[]): void
|
||||
disabled?: boolean
|
||||
multiple?: boolean
|
||||
error?: string
|
||||
}): ReactElement {
|
||||
const onDrop = useCallback((acceptedFiles) => handleOnDrop(acceptedFiles), [
|
||||
handleOnDrop
|
||||
])
|
||||
|
||||
const {
|
||||
getRootProps,
|
||||
getInputProps,
|
||||
isDragActive,
|
||||
isDragReject,
|
||||
acceptedFiles
|
||||
} = useDropzone({ onDrop })
|
||||
|
||||
const files = acceptedFiles.map((file: any) => (
|
||||
<li key={file.path}>
|
||||
{file.path} - {formatBytes(file.size, 0)}
|
||||
</li>
|
||||
))
|
||||
|
||||
return (
|
||||
<div
|
||||
{...getRootProps({
|
||||
className: isDragActive
|
||||
? `${styles.dropzone} ${styles.dragover}`
|
||||
: disabled
|
||||
? `${styles.dropzone} ${styles.disabled}`
|
||||
: styles.dropzone
|
||||
})}
|
||||
>
|
||||
<div>
|
||||
{acceptedFiles.length > 0 ? (
|
||||
<aside>
|
||||
<ul>{files}</ul>
|
||||
</aside>
|
||||
) : (
|
||||
<>
|
||||
<input {...getInputProps({ multiple })} />
|
||||
|
||||
{isDragActive && !isDragReject ? (
|
||||
`Drop it like it's hot!`
|
||||
) : multiple ? (
|
||||
`Drag 'n' drop some files here, or click to select files`
|
||||
) : error ? (
|
||||
<div className={styles.error}>{error}</div>
|
||||
) : (
|
||||
`Drag 'n' drop a file here, or click to select a file`
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
@ -1,63 +0,0 @@
|
||||
import React, { ReactElement, ReactNode, useEffect, useState } from 'react'
|
||||
import { EthereumListsChain, getNetworkData } from '../../utils/wallet'
|
||||
import { ReactComponent as External } from '../../images/external.svg'
|
||||
import styles from './EtherscanLink.module.css'
|
||||
import { useSiteMetadata } from '../../hooks/useSiteMetadata'
|
||||
import { graphql, useStaticQuery } from 'gatsby'
|
||||
|
||||
const networksQuery = graphql`
|
||||
query {
|
||||
allNetworksMetadataJson {
|
||||
edges {
|
||||
node {
|
||||
chain
|
||||
network
|
||||
networkId
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
export default function EtherscanLink({
|
||||
networkId,
|
||||
path,
|
||||
children
|
||||
}: {
|
||||
networkId: number
|
||||
path: string
|
||||
children: ReactNode
|
||||
}): ReactElement {
|
||||
const data = useStaticQuery(networksQuery)
|
||||
const networksList: { node: EthereumListsChain }[] =
|
||||
data.allNetworksMetadataJson.edges
|
||||
|
||||
const { appConfig } = useSiteMetadata()
|
||||
const [url, setUrl] = useState<string>()
|
||||
|
||||
useEffect(() => {
|
||||
const networkData = networkId
|
||||
? getNetworkData(networksList, networkId)
|
||||
: null
|
||||
const url =
|
||||
(!networkId && appConfig.network === 'mainnet') || networkId === 1
|
||||
? `https://etherscan.io`
|
||||
: `https://${
|
||||
networkData ? networkData.network : appConfig.network
|
||||
}.etherscan.io`
|
||||
|
||||
setUrl(url)
|
||||
}, [networkId, networksList, appConfig.network])
|
||||
|
||||
return (
|
||||
<a
|
||||
href={`${url}/${path}`}
|
||||
title="View on Etherscan"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
className={styles.link}
|
||||
>
|
||||
{children} <External />
|
||||
</a>
|
||||
)
|
||||
}
|
33
src/components/atoms/ExplorerLink.tsx
Normal file
33
src/components/atoms/ExplorerLink.tsx
Normal file
@ -0,0 +1,33 @@
|
||||
import React, { ReactElement, ReactNode, useEffect, useState } from 'react'
|
||||
import { ReactComponent as External } from '../../images/external.svg'
|
||||
import styles from './ExplorerLink.module.css'
|
||||
import { ConfigHelperConfig } from '@oceanprotocol/lib/dist/node/utils/ConfigHelper'
|
||||
import { useOcean } from '../../providers/Ocean'
|
||||
|
||||
export default function ExplorerLink({
|
||||
path,
|
||||
children
|
||||
}: {
|
||||
networkId: number
|
||||
path: string
|
||||
children: ReactNode
|
||||
}): ReactElement {
|
||||
const { config } = useOcean()
|
||||
const [url, setUrl] = useState<string>()
|
||||
|
||||
useEffect(() => {
|
||||
setUrl((config as ConfigHelperConfig).explorerUri)
|
||||
}, [config])
|
||||
|
||||
return (
|
||||
<a
|
||||
href={`${url}/${path}`}
|
||||
title={`View on ${(config as ConfigHelperConfig).explorerUri}`}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
className={styles.link}
|
||||
>
|
||||
{children} <External />
|
||||
</a>
|
||||
)
|
||||
}
|
@ -12,7 +12,6 @@ const Markdown = ({
|
||||
// fix react-markdown \n transformation
|
||||
// https://github.com/rexxars/react-markdown/issues/105#issuecomment-351585313
|
||||
const textCleaned = text.replace(/\\n/g, '\n ')
|
||||
|
||||
return (
|
||||
<ReactMarkdown
|
||||
source={textCleaned}
|
||||
|
@ -7,6 +7,6 @@ export default {
|
||||
title: 'Atoms/Price'
|
||||
}
|
||||
|
||||
export const Normal = () => <Price ddo={ddo as DDO} />
|
||||
export const Normal = () => <Price price={(ddo as DDO).price} />
|
||||
|
||||
export const Small = () => <Price ddo={ddo as DDO} small />
|
||||
export const Small = () => <Price price={(ddo as DDO).price} small />
|
||||
|
@ -1,25 +1,21 @@
|
||||
import React, { ReactElement } from 'react'
|
||||
import styles from './index.module.css'
|
||||
import { useMetadata } from '@oceanprotocol/react'
|
||||
import { DDO } from '@oceanprotocol/lib'
|
||||
import { BestPrice } from '@oceanprotocol/lib'
|
||||
import Loader from '../Loader'
|
||||
import Tooltip from '../Tooltip'
|
||||
import PriceUnit from './PriceUnit'
|
||||
|
||||
export default function Price({
|
||||
ddo,
|
||||
price,
|
||||
className,
|
||||
small,
|
||||
conversion
|
||||
}: {
|
||||
ddo: DDO
|
||||
price: BestPrice
|
||||
className?: string
|
||||
small?: boolean
|
||||
conversion?: boolean
|
||||
}): ReactElement {
|
||||
// price is not fetched from the chain anymore , will update one AssetProvider is implemented
|
||||
const { price } = useMetadata(ddo)
|
||||
|
||||
return price?.value ? (
|
||||
<PriceUnit
|
||||
price={`${price.value}`}
|
||||
|
@ -1,7 +1,7 @@
|
||||
import React, { ReactElement } from 'react'
|
||||
import styles from './ProfileDetails.module.css'
|
||||
import { Profile } from '../../../models/Profile'
|
||||
import EtherscanLink from '../EtherscanLink'
|
||||
import ExplorerLink from '../ExplorerLink'
|
||||
import PublisherLinks from './PublisherLinks'
|
||||
|
||||
export default function ProfileDetails({
|
||||
@ -26,9 +26,9 @@ export default function ProfileDetails({
|
||||
{profile?.emoji} {profile?.name}
|
||||
</h3>
|
||||
|
||||
<EtherscanLink networkId={networkId} path={`address/${account}`}>
|
||||
<ExplorerLink networkId={networkId} path={`address/${account}`}>
|
||||
<code>{account}</code>
|
||||
</EtherscanLink>
|
||||
</ExplorerLink>
|
||||
</header>
|
||||
|
||||
{profile?.description && (
|
||||
|
@ -5,13 +5,13 @@ import Tooltip from '../Tooltip'
|
||||
import { Profile } from '../../../models/Profile'
|
||||
import { Link } from 'gatsby'
|
||||
import get3BoxProfile from '../../../utils/profile'
|
||||
import EtherscanLink from '../EtherscanLink'
|
||||
import { accountTruncate } from '../../../utils/wallet'
|
||||
import ExplorerLink from '../ExplorerLink'
|
||||
import { accountTruncate } from '../../../utils/web3'
|
||||
import axios from 'axios'
|
||||
import { useOcean } from '@oceanprotocol/react'
|
||||
import { ReactComponent as Info } from '../../../images/info.svg'
|
||||
import ProfileDetails from './ProfileDetails'
|
||||
import Add from './Add'
|
||||
import { useWeb3 } from '../../../providers/Web3'
|
||||
|
||||
const cx = classNames.bind(styles)
|
||||
|
||||
@ -24,7 +24,7 @@ export default function Publisher({
|
||||
minimal?: boolean
|
||||
className?: string
|
||||
}): ReactElement {
|
||||
const { networkId, accountId } = useOcean()
|
||||
const { networkId, accountId } = useWeb3()
|
||||
const [profile, setProfile] = useState<Profile>()
|
||||
const [name, setName] = useState<string>()
|
||||
|
||||
@ -88,9 +88,9 @@ export default function Publisher({
|
||||
</Tooltip>
|
||||
)}
|
||||
{showAdd && <Add />}
|
||||
<EtherscanLink networkId={networkId} path={`address/${account}`}>
|
||||
Etherscan
|
||||
</EtherscanLink>
|
||||
<ExplorerLink networkId={networkId} path={`address/${account}`}>
|
||||
Explorer
|
||||
</ExplorerLink>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
@ -1,6 +1,7 @@
|
||||
import React, { ReactElement } from 'react'
|
||||
import { Helmet } from 'react-helmet'
|
||||
import { useSiteMetadata } from '../../hooks/useSiteMetadata'
|
||||
import { isBrowser } from '../../utils'
|
||||
|
||||
export default function Seo({
|
||||
title,
|
||||
@ -24,7 +25,7 @@ export default function Seo({
|
||||
>
|
||||
<html lang="en" />
|
||||
|
||||
{typeof window !== 'undefined' &&
|
||||
{isBrowser &&
|
||||
window.location &&
|
||||
window.location.hostname !== 'oceanprotocol.com' && (
|
||||
<meta name="robots" content="noindex,nofollow" />
|
||||
|
@ -1,8 +1,8 @@
|
||||
import { DDO } from '@oceanprotocol/lib'
|
||||
import { useOcean } from '@oceanprotocol/react'
|
||||
import { useOcean } from '../../providers/Ocean'
|
||||
import { Link } from 'gatsby'
|
||||
import React, { ReactElement, useEffect, useState } from 'react'
|
||||
import { retrieveDDO, getAssetsNames } from '../../utils/aquarius'
|
||||
import { getAssetsNames } from '../../utils/aquarius'
|
||||
import styles from './AssetListTitle.module.css'
|
||||
import axios from 'axios'
|
||||
|
||||
|
@ -6,7 +6,6 @@ import styles from './AssetTeaser.module.css'
|
||||
import { DDO } from '@oceanprotocol/lib'
|
||||
import removeMarkdown from 'remove-markdown'
|
||||
import Publisher from '../atoms/Publisher'
|
||||
import { useMetadata } from '@oceanprotocol/react'
|
||||
import Time from '../atoms/Time'
|
||||
import AssetType from '../atoms/AssetType'
|
||||
|
||||
@ -15,12 +14,12 @@ declare type AssetTeaserProps = {
|
||||
}
|
||||
|
||||
const AssetTeaser: React.FC<AssetTeaserProps> = ({ ddo }: AssetTeaserProps) => {
|
||||
const { owner } = useMetadata(ddo)
|
||||
const { attributes } = ddo.findServiceByType('metadata')
|
||||
const { name, type } = attributes.main
|
||||
const { dataTokenInfo } = ddo
|
||||
const isCompute = Boolean(ddo?.findServiceByType('compute'))
|
||||
const accessType = isCompute ? 'compute' : 'access'
|
||||
const { owner } = ddo.publicKey[0]
|
||||
|
||||
return (
|
||||
<article className={`${styles.teaser} ${styles[type]}`}>
|
||||
@ -48,7 +47,7 @@ const AssetTeaser: React.FC<AssetTeaserProps> = ({ ddo }: AssetTeaserProps) => {
|
||||
</div>
|
||||
|
||||
<footer className={styles.foot}>
|
||||
<Price ddo={ddo} small />
|
||||
<Price price={ddo.price} small />
|
||||
<p className={styles.date}>
|
||||
<Time date={ddo?.created} relative />
|
||||
</p>
|
||||
|
@ -2,7 +2,7 @@ import { useUserPreferences } from '../../providers/UserPreferences'
|
||||
import React, { ReactElement, useEffect, useState } from 'react'
|
||||
import Table from '../atoms/Table'
|
||||
import { DDO, Logger } from '@oceanprotocol/lib'
|
||||
import { useOcean } from '@oceanprotocol/react'
|
||||
import { useOcean } from '../../providers/Ocean'
|
||||
import Price from '../atoms/Price'
|
||||
import Tooltip from '../atoms/Tooltip'
|
||||
import { ConfigHelperConfig } from '@oceanprotocol/lib/dist/node/utils/ConfigHelper'
|
||||
@ -73,7 +73,7 @@ const columns = [
|
||||
{
|
||||
name: 'Price',
|
||||
selector: function getAssetRow(row: DDO) {
|
||||
return <Price ddo={row} small />
|
||||
return <Price price={row.price} small />
|
||||
},
|
||||
right: true
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { useField } from 'formik'
|
||||
import { InputProps } from '../../../atoms/Input'
|
||||
import { useOcean } from '@oceanprotocol/react'
|
||||
import { useOcean } from '../../../../providers/Ocean'
|
||||
import React, { ReactElement, useEffect } from 'react'
|
||||
import styles from './index.module.css'
|
||||
|
||||
|
@ -4,7 +4,7 @@ import { useField } from 'formik'
|
||||
import { toast } from 'react-toastify'
|
||||
import FileInfo from './Info'
|
||||
import FileInput from './Input'
|
||||
import { useOcean } from '@oceanprotocol/react'
|
||||
import { useOcean } from '../../../../providers/Ocean'
|
||||
import { InputProps } from '../../../atoms/Input'
|
||||
import { fileinfo } from '../../../../utils/provider'
|
||||
|
||||
|
@ -22,8 +22,7 @@ export default function MarketStats(): ReactElement {
|
||||
const { data } = useQuery(getTotalPoolsValues)
|
||||
|
||||
useEffect(() => {
|
||||
if (!data) return
|
||||
|
||||
if (!data || !data.poolFactories || data.poolFactories.length === 0) return
|
||||
setTotalValueLocked(data.poolFactories[0].totalValueLocked)
|
||||
setTotalOceanLiquidity(data.poolFactories[0].totalOceanLiquidity)
|
||||
setPoolCount(data.poolFactories[0].finalizedPoolCount)
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { useOcean } from '@oceanprotocol/react'
|
||||
import { useOcean } from '../../providers/Ocean'
|
||||
import React, { ReactElement, useEffect, useState } from 'react'
|
||||
import EtherscanLink from '../atoms/EtherscanLink'
|
||||
import ExplorerLink from '../atoms/ExplorerLink'
|
||||
import Time from '../atoms/Time'
|
||||
import Table from '../atoms/Table'
|
||||
import AssetTitle from './AssetListTitle'
|
||||
@ -15,6 +15,7 @@ import {
|
||||
} from '../../@types/apollo/TransactionHistory'
|
||||
|
||||
import web3 from 'web3'
|
||||
import { useWeb3 } from '../../providers/Web3'
|
||||
|
||||
const txHistoryQueryByPool = gql`
|
||||
query TransactionHistoryByPool($user: String, $pool: String) {
|
||||
@ -129,7 +130,8 @@ async function getTitle(
|
||||
}
|
||||
|
||||
function Title({ row }: { row: TransactionHistoryPoolTransactions }) {
|
||||
const { ocean, networkId } = useOcean()
|
||||
const { networkId } = useWeb3()
|
||||
const { ocean } = useOcean()
|
||||
const [title, setTitle] = useState<string>()
|
||||
const { locale } = useUserPreferences()
|
||||
|
||||
@ -144,9 +146,9 @@ function Title({ row }: { row: TransactionHistoryPoolTransactions }) {
|
||||
}, [ocean, row, locale])
|
||||
|
||||
return title ? (
|
||||
<EtherscanLink networkId={networkId} path={`/tx/${row.tx}`}>
|
||||
<ExplorerLink networkId={networkId} path={`/tx/${row.tx}`}>
|
||||
<span className={styles.titleText}>{title}</span>
|
||||
</EtherscanLink>
|
||||
</ExplorerLink>
|
||||
) : null
|
||||
}
|
||||
|
||||
@ -193,7 +195,7 @@ export default function PoolTransactions({
|
||||
poolAddress?: string
|
||||
minimal?: boolean
|
||||
}): ReactElement {
|
||||
const { accountId } = useOcean()
|
||||
const { accountId } = useWeb3()
|
||||
const [logs, setLogs] = useState<TransactionHistoryPoolTransactions[]>()
|
||||
|
||||
const { data, loading } = useQuery<TransactionHistory>(
|
||||
|
19
src/components/molecules/UserPreferences/Chain.module.css
Normal file
19
src/components/molecules/UserPreferences/Chain.module.css
Normal file
@ -0,0 +1,19 @@
|
||||
.buttons {
|
||||
composes: buttons from './Appearance.module.css';
|
||||
}
|
||||
|
||||
.button {
|
||||
composes: button from './Appearance.module.css';
|
||||
}
|
||||
|
||||
.button span {
|
||||
display: block;
|
||||
font-size: var(--font-size-small);
|
||||
font-family: var(--font-family-base);
|
||||
font-weight: var(--font-weight-base);
|
||||
margin-top: calc(var(--spacer) / 10);
|
||||
}
|
||||
|
||||
.selected {
|
||||
composes: selected from './Appearance.module.css';
|
||||
}
|
53
src/components/molecules/UserPreferences/Chain.tsx
Normal file
53
src/components/molecules/UserPreferences/Chain.tsx
Normal file
@ -0,0 +1,53 @@
|
||||
import { ConfigHelperConfig } from '@oceanprotocol/lib/dist/node/utils/ConfigHelper'
|
||||
import React, { ReactElement } from 'react'
|
||||
import { useOcean } from '../../../providers/Ocean'
|
||||
import { useWeb3 } from '../../../providers/Web3'
|
||||
import { getOceanConfig } from '../../../utils/ocean'
|
||||
import Button from '../../atoms/Button'
|
||||
import FormHelp from '../../atoms/Input/Help'
|
||||
import Label from '../../atoms/Input/Label'
|
||||
import styles from './Chain.module.css'
|
||||
|
||||
export default function Chain(): ReactElement {
|
||||
const { web3 } = useWeb3()
|
||||
const { config, connect } = useOcean()
|
||||
|
||||
async function connectOcean(networkName: string) {
|
||||
const config = getOceanConfig(networkName)
|
||||
await connect(config)
|
||||
}
|
||||
|
||||
const chains = [
|
||||
{ name: 'ETH', oceanConfig: 'mainnet' },
|
||||
{ name: 'Polygon/Matic', oceanConfig: 'polygon' }
|
||||
]
|
||||
|
||||
// TODO: to fully solve https://github.com/oceanprotocol/market/issues/432
|
||||
// there are more considerations for users with a wallet connected (wallet network vs. setting network).
|
||||
// For now, only show the setting for non-wallet users.
|
||||
return !web3 ? (
|
||||
<li>
|
||||
<Label htmlFor="">Chain</Label>
|
||||
<div className={styles.buttons}>
|
||||
{chains.map((button) => {
|
||||
const selected =
|
||||
(config as ConfigHelperConfig).network === button.oceanConfig
|
||||
|
||||
return (
|
||||
<Button
|
||||
key={button.name}
|
||||
className={`${styles.button} ${selected ? styles.selected : ''}`}
|
||||
size="small"
|
||||
style="text"
|
||||
onClick={() => connectOcean(button.oceanConfig)}
|
||||
>
|
||||
{button.name}
|
||||
<span>Mainnet</span>
|
||||
</Button>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
<FormHelp>Switch the data source for the interface.</FormHelp>
|
||||
</li>
|
||||
) : null
|
||||
}
|
@ -8,6 +8,7 @@ import { ReactComponent as Caret } from '../../../images/caret.svg'
|
||||
import useDarkMode from 'use-dark-mode'
|
||||
import Appearance from './Appearance'
|
||||
import { darkModeConfig } from '../../../../app.config'
|
||||
import Chain from './Chain'
|
||||
|
||||
export default function UserPreferences(): ReactElement {
|
||||
// Calling this here because <Theme /> is not mounted on first load
|
||||
@ -19,6 +20,7 @@ export default function UserPreferences(): ReactElement {
|
||||
<ul className={styles.preferencesDetails}>
|
||||
<Currency />
|
||||
<Appearance darkMode={darkMode} />
|
||||
<Chain />
|
||||
<Debug />
|
||||
</ul>
|
||||
}
|
||||
|
@ -1,11 +1,10 @@
|
||||
import { useOcean } from '@oceanprotocol/react'
|
||||
import { toDataUrl } from 'ethereum-blockies'
|
||||
import React, { FormEvent } from 'react'
|
||||
import { ReactComponent as Caret } from '../../../images/caret.svg'
|
||||
import { accountTruncate } from '../../../utils/wallet'
|
||||
import { accountTruncate } from '../../../utils/web3'
|
||||
import Loader from '../../atoms/Loader'
|
||||
import Status from '../../atoms/Status'
|
||||
import styles from './Account.module.css'
|
||||
import { useWeb3 } from '../../../providers/Web3'
|
||||
|
||||
const Blockies = ({ account }: { account: string | undefined }) => {
|
||||
if (!account) return null
|
||||
@ -24,8 +23,7 @@ const Blockies = ({ account }: { account: string | undefined }) => {
|
||||
// Forward ref for Tippy.js
|
||||
// eslint-disable-next-line
|
||||
const Account = React.forwardRef((props, ref: any) => {
|
||||
const { accountId, status, connect, web3Modal } = useOcean()
|
||||
const hasSuccess = status === 1
|
||||
const { accountId, web3Modal, connect } = useWeb3()
|
||||
|
||||
async function handleActivation(e: FormEvent<HTMLButtonElement>) {
|
||||
// prevent accidentially submitting a form the button might be in
|
||||
@ -50,9 +48,6 @@ const Account = React.forwardRef((props, ref: any) => {
|
||||
<span className={styles.address} title={accountId}>
|
||||
{accountTruncate(accountId)}
|
||||
</span>
|
||||
{!hasSuccess && (
|
||||
<Status className={styles.status} state="warning" aria-hidden />
|
||||
)}
|
||||
<Caret aria-hidden="true" />
|
||||
</button>
|
||||
) : (
|
||||
|
@ -24,7 +24,7 @@
|
||||
}
|
||||
|
||||
.symbol {
|
||||
width: 20%;
|
||||
width: 22%;
|
||||
text-align: right;
|
||||
font-weight: var(--font-weight-base);
|
||||
font-size: var(--font-size-small);
|
||||
|
@ -1,28 +1,37 @@
|
||||
import React, { ReactElement, useEffect, useState } from 'react'
|
||||
import Button from '../../atoms/Button'
|
||||
import styles from './Details.module.css'
|
||||
import { useOcean } from '@oceanprotocol/react'
|
||||
import { useOcean } from '../../../providers/Ocean'
|
||||
import Web3Feedback from './Feedback'
|
||||
import { getProviderInfo, IProviderInfo } from 'web3modal'
|
||||
import Conversion from '../../atoms/Price/Conversion'
|
||||
import { formatCurrency } from '@coingecko/cryptoformat'
|
||||
import { useUserPreferences } from '../../../providers/UserPreferences'
|
||||
import { useWeb3 } from '../../../providers/Web3'
|
||||
|
||||
export default function Details(): ReactElement {
|
||||
const { balance, connect, logout, web3Provider } = useOcean()
|
||||
const { web3Provider, connect, logout, networkData, networkId } = useWeb3()
|
||||
const { balance } = useOcean()
|
||||
const { locale } = useUserPreferences()
|
||||
|
||||
const [providerInfo, setProviderInfo] = useState<IProviderInfo>()
|
||||
const [mainCurrency, setMainCurrency] = useState<string>()
|
||||
// const [portisNetwork, setPortisNetwork] = useState<string>()
|
||||
|
||||
// Workaround cause getInjectedProviderName() always returns `MetaMask`
|
||||
// https://github.com/oceanprotocol/market/issues/332
|
||||
useEffect(() => {
|
||||
if (!web3Provider) return
|
||||
|
||||
const providerInfo = getProviderInfo(web3Provider)
|
||||
setProviderInfo(providerInfo)
|
||||
}, [web3Provider])
|
||||
|
||||
useEffect(() => {
|
||||
if (!networkData) return
|
||||
|
||||
setMainCurrency(networkData.nativeCurrency.symbol)
|
||||
}, [networkData])
|
||||
|
||||
// Handle network change for Portis
|
||||
// async function handlePortisNetworkChange(e: ChangeEvent<HTMLSelectElement>) {
|
||||
// setPortisNetwork(e.target.value)
|
||||
@ -38,7 +47,13 @@ export default function Details(): ReactElement {
|
||||
<ul>
|
||||
{Object.entries(balance).map(([key, value]) => (
|
||||
<li className={styles.balance} key={key}>
|
||||
<span className={styles.symbol}>{key.toUpperCase()}</span>{' '}
|
||||
<span className={styles.symbol}>
|
||||
{key === 'eth'
|
||||
? mainCurrency
|
||||
: key === 'ocean' && networkId === 137
|
||||
? 'mOCEAN'
|
||||
: key.toUpperCase()}
|
||||
</span>{' '}
|
||||
{formatCurrency(Number(value), '', locale, false, {
|
||||
significantFigures: 4
|
||||
})}
|
||||
|
@ -1,7 +1,7 @@
|
||||
import React, { ReactElement } from 'react'
|
||||
import { useOcean } from '../../../providers/Ocean'
|
||||
import Status from '../../atoms/Status'
|
||||
import styles from './Feedback.module.css'
|
||||
import { useOcean } from '@oceanprotocol/react'
|
||||
|
||||
export declare type Web3Error = {
|
||||
status: 'error' | 'warning' | 'success'
|
||||
@ -14,10 +14,8 @@ export default function Web3Feedback({
|
||||
}: {
|
||||
isBalanceSufficient?: boolean
|
||||
}): ReactElement {
|
||||
const { account, status } = useOcean()
|
||||
const isOceanConnectionError = status === -1
|
||||
const showFeedback =
|
||||
!account || isOceanConnectionError || isBalanceSufficient === false
|
||||
const { account, ocean } = useOcean()
|
||||
const showFeedback = !account || !ocean || isBalanceSufficient === false
|
||||
|
||||
const state = !account
|
||||
? 'error'
|
||||
@ -27,7 +25,7 @@ export default function Web3Feedback({
|
||||
|
||||
const title = !account
|
||||
? 'No account connected'
|
||||
: isOceanConnectionError
|
||||
: !ocean
|
||||
? 'Error connecting to Ocean'
|
||||
: account
|
||||
? isBalanceSufficient === false
|
||||
@ -37,7 +35,7 @@ export default function Web3Feedback({
|
||||
|
||||
const message = !account
|
||||
? 'Please connect your Web3 wallet.'
|
||||
: isOceanConnectionError
|
||||
: !ocean
|
||||
? 'Please try again.'
|
||||
: isBalanceSufficient === false
|
||||
? 'You do not have enough OCEAN in your wallet to purchase this asset.'
|
||||
|
@ -1,43 +1,19 @@
|
||||
import React, { useState, useEffect, ReactElement } from 'react'
|
||||
import { useOcean } from '@oceanprotocol/react'
|
||||
import { useOcean } from '../../../providers/Ocean'
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
import { useWeb3 } from '../../../providers/Web3'
|
||||
|
||||
export default function Network(): ReactElement {
|
||||
const data = useStaticQuery(networksQuery)
|
||||
const networksList: { node: EthereumListsChain }[] =
|
||||
data.allNetworksMetadataJson.edges
|
||||
|
||||
const { config, networkId } = useOcean()
|
||||
const { networkId, networkDisplayName, isTestnet } = useWeb3()
|
||||
const { config } = 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(() => {
|
||||
@ -51,23 +27,16 @@ export default function Network(): ReactElement {
|
||||
// to figure out if network is supported.
|
||||
const isSupportedNetwork = Boolean(new ConfigHelper().getConfig(network))
|
||||
setIsSupportedNetwork(isSupportedNetwork)
|
||||
}, [networkId, networkIdConfig])
|
||||
|
||||
// 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 ? (
|
||||
return !isEthMainnet && networkDisplayName ? (
|
||||
<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>
|
||||
<span className={styles.name}>{networkDisplayName}</span>
|
||||
{isTestnet && <Badge label="Test" className={styles.badge} />}
|
||||
</div>
|
||||
) : null
|
||||
|
@ -3,11 +3,11 @@ import Account from './Account'
|
||||
import Details from './Details'
|
||||
import Tooltip from '../../atoms/Tooltip'
|
||||
import Network from './Network'
|
||||
import { useOcean } from '@oceanprotocol/react'
|
||||
import styles from './index.module.css'
|
||||
import { useWeb3 } from '../../../providers/Web3'
|
||||
|
||||
export default function Wallet(): ReactElement {
|
||||
const { accountId } = useOcean()
|
||||
const { accountId } = useWeb3()
|
||||
|
||||
return (
|
||||
<div className={styles.wallet}>
|
||||
|
@ -1,22 +1,18 @@
|
||||
import React, { useState, ReactElement, ChangeEvent, useEffect } from 'react'
|
||||
import { DDO, Logger } from '@oceanprotocol/lib'
|
||||
import { DDO } from '@oceanprotocol/lib'
|
||||
import Loader from '../../atoms/Loader'
|
||||
import Web3Feedback from '../../molecules/Wallet/Feedback'
|
||||
import Dropzone from '../../atoms/Dropzone'
|
||||
import Price from '../../atoms/Price'
|
||||
import File from '../../atoms/File'
|
||||
import {
|
||||
computeOptions,
|
||||
useCompute,
|
||||
readFileContent,
|
||||
useOcean,
|
||||
usePricing
|
||||
} from '@oceanprotocol/react'
|
||||
import { computeOptions, useCompute } from '../../../hooks/useCompute'
|
||||
import styles from './Compute.module.css'
|
||||
import Input from '../../atoms/Input'
|
||||
import Alert from '../../atoms/Alert'
|
||||
import { useSiteMetadata } from '../../../hooks/useSiteMetadata'
|
||||
import checkPreviousOrder from '../../../utils/checkPreviousOrder'
|
||||
import { useOcean } from '../../../providers/Ocean'
|
||||
import { useWeb3 } from '../../../providers/Web3'
|
||||
import { usePricing } from '../../../hooks/usePricing'
|
||||
import { useAsset } from '../../../providers/Asset'
|
||||
|
||||
export default function Compute({
|
||||
@ -29,12 +25,12 @@ export default function Compute({
|
||||
dtBalance: string
|
||||
}): ReactElement {
|
||||
const { marketFeeAddress } = useSiteMetadata()
|
||||
|
||||
const { accountId } = useWeb3()
|
||||
const { ocean } = useOcean()
|
||||
const { type } = useAsset()
|
||||
const { ocean, accountId } = useOcean()
|
||||
const { compute, isLoading, computeStepText, computeError } = useCompute()
|
||||
const { buyDT, dtSymbol } = usePricing(ddo)
|
||||
|
||||
const { price } = useAsset()
|
||||
const computeService = ddo.findServiceByType('compute')
|
||||
const metadataService = ddo.findServiceByType('metadata')
|
||||
|
||||
@ -68,12 +64,6 @@ export default function Compute({
|
||||
checkPreviousOrders()
|
||||
}, [ocean, ddo, accountId])
|
||||
|
||||
const onDrop = async (files: File[]) => {
|
||||
setFile(files[0])
|
||||
const fileText = await readFileContent(files[0])
|
||||
setAlgorithmRawCode(fileText)
|
||||
}
|
||||
|
||||
const handleSelectChange = (event: ChangeEvent<HTMLSelectElement>) => {
|
||||
const comType = event.target.value
|
||||
setComputeType(comType)
|
||||
@ -83,36 +73,36 @@ export default function Compute({
|
||||
setComputeContainer(selectedComputeOption.value)
|
||||
}
|
||||
|
||||
const startJob = async () => {
|
||||
try {
|
||||
if (!ocean) return
|
||||
// const startJob = async () => {
|
||||
// try {
|
||||
// if (!ocean) return
|
||||
|
||||
setIsJobStarting(true)
|
||||
setIsPublished(false)
|
||||
setError('')
|
||||
// setIsJobStarting(true)
|
||||
// setIsPublished(false)
|
||||
// setError('')
|
||||
|
||||
!hasPreviousOrder && !hasDatatoken && (await buyDT('1'))
|
||||
// !hasPreviousOrder && !hasDatatoken && (await buyDT('1'))
|
||||
|
||||
await compute(
|
||||
ddo.id,
|
||||
computeService,
|
||||
ddo.dataToken,
|
||||
algorithmRawCode,
|
||||
computeContainer,
|
||||
marketFeeAddress,
|
||||
previousOrderId
|
||||
)
|
||||
// await compute(
|
||||
// ddo.id,
|
||||
// computeService,
|
||||
// ddo.dataToken,
|
||||
// algorithmRawCode,
|
||||
// computeContainer,
|
||||
// marketFeeAddress,
|
||||
// previousOrderId
|
||||
// )
|
||||
|
||||
setHasPreviousOrder(true)
|
||||
setIsPublished(true)
|
||||
setFile(null)
|
||||
} catch (error) {
|
||||
setError('Failed to start job!')
|
||||
Logger.error(error.message)
|
||||
} finally {
|
||||
setIsJobStarting(false)
|
||||
}
|
||||
}
|
||||
// setHasPreviousOrder(true)
|
||||
// setIsPublished(true)
|
||||
// setFile(null)
|
||||
// } catch (error) {
|
||||
// setError('Failed to start job!')
|
||||
// Logger.error(error.message)
|
||||
// } finally {
|
||||
// setIsJobStarting(false)
|
||||
// }
|
||||
// }
|
||||
|
||||
return (
|
||||
<>
|
||||
@ -121,7 +111,7 @@ export default function Compute({
|
||||
<File file={metadataService.attributes.main.files[0]} small />
|
||||
</div>
|
||||
<div className={styles.pricewrapper}>
|
||||
<Price ddo={ddo} conversion />
|
||||
<Price price={price} conversion />
|
||||
{hasDatatoken && (
|
||||
<div className={styles.hasTokens}>
|
||||
You own {dtBalance} {dtSymbol} allowing you to use this data set
|
||||
@ -154,7 +144,6 @@ export default function Compute({
|
||||
onChange={handleSelectChange}
|
||||
/>
|
||||
)}
|
||||
<Dropzone multiple={false} handleOnDrop={onDrop} />
|
||||
|
||||
<div className={styles.actions}>
|
||||
{isLoading ? (
|
||||
|
@ -7,14 +7,16 @@ import Price from '../../atoms/Price'
|
||||
import Web3Feedback from '../../molecules/Wallet/Feedback'
|
||||
import styles from './Consume.module.css'
|
||||
import Loader from '../../atoms/Loader'
|
||||
import { useOcean, useConsume, usePricing } from '@oceanprotocol/react'
|
||||
import { useSiteMetadata } from '../../../hooks/useSiteMetadata'
|
||||
import checkPreviousOrder from '../../../utils/checkPreviousOrder'
|
||||
import { useAsset } from '../../../providers/Asset'
|
||||
import { secondsToString } from '../../../utils/metadata'
|
||||
import { gql, useQuery } from '@apollo/client'
|
||||
import { OrdersData } from '../../../@types/apollo/OrdersData'
|
||||
import BigNumber from 'bignumber.js'
|
||||
import { useOcean } from '../../../providers/Ocean'
|
||||
import { useWeb3 } from '../../../providers/Web3'
|
||||
import { usePricing } from '../../../hooks/usePricing'
|
||||
import { useConsume } from '../../../hooks/useConsume'
|
||||
|
||||
const previousOrderQuery = gql`
|
||||
query PreviousOrder($id: String!, $account: String!) {
|
||||
@ -61,7 +63,8 @@ export default function Consume({
|
||||
isBalanceSufficient: boolean
|
||||
dtBalance: string
|
||||
}): ReactElement {
|
||||
const { ocean, accountId } = useOcean()
|
||||
const { accountId } = useWeb3()
|
||||
const { ocean } = useOcean()
|
||||
const { marketFeeAddress } = useSiteMetadata()
|
||||
const [hasPreviousOrder, setHasPreviousOrder] = useState(false)
|
||||
const [previousOrderId, setPreviousOrderId] = useState<string>()
|
||||
@ -141,7 +144,7 @@ export default function Consume({
|
||||
])
|
||||
|
||||
async function handleConsume() {
|
||||
!hasPreviousOrder && !hasDatatoken && (await buyDT('1'))
|
||||
!hasPreviousOrder && !hasDatatoken && (await buyDT('1', price))
|
||||
await consume(
|
||||
ddo.id,
|
||||
ddo.dataToken,
|
||||
@ -191,7 +194,7 @@ export default function Consume({
|
||||
<File file={file} />
|
||||
</div>
|
||||
<div className={styles.pricewrapper}>
|
||||
<Price ddo={ddo} conversion />
|
||||
<Price price={price} conversion />
|
||||
{!isInPurgatory && <PurchaseButton />}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -3,10 +3,11 @@ import styles from './FormEditMetadata.module.css'
|
||||
import { Field, Form, FormikContextType, useFormikContext } from 'formik'
|
||||
import Button from '../../../atoms/Button'
|
||||
import Input from '../../../atoms/Input'
|
||||
import { useOcean } from '@oceanprotocol/react'
|
||||
import { FormFieldProps } from '../../../../@types/Form'
|
||||
import { MetadataPublishFormDataset } from '../../../../@types/MetaData'
|
||||
import { checkIfTimeoutInPredefinedValues } from '../../../../utils/metadata'
|
||||
import { useOcean } from '../../../../providers/Ocean'
|
||||
import { useWeb3 } from '../../../../providers/Web3'
|
||||
|
||||
function handleTimeoutCustomOption(
|
||||
data: FormFieldProps[],
|
||||
@ -53,7 +54,8 @@ export default function FormEditMetadata({
|
||||
setTimeoutStringValue: (value: string) => void
|
||||
values: Partial<MetadataPublishFormDataset>
|
||||
}): ReactElement {
|
||||
const { ocean, accountId } = useOcean()
|
||||
const { accountId } = useWeb3()
|
||||
const { ocean } = useOcean()
|
||||
const {
|
||||
isValid,
|
||||
validateField,
|
||||
|
@ -1,4 +1,3 @@
|
||||
import { useOcean } from '@oceanprotocol/react'
|
||||
import { Formik } from 'formik'
|
||||
import React, { ReactElement, useState } from 'react'
|
||||
import { MetadataEditForm } from '../../../../@types/MetaData'
|
||||
@ -17,6 +16,8 @@ import styles from './index.module.css'
|
||||
import { Logger } from '@oceanprotocol/lib'
|
||||
import MetadataFeedback from '../../../molecules/MetadataFeedback'
|
||||
import { graphql, useStaticQuery } from 'gatsby'
|
||||
import { useWeb3 } from '../../../../providers/Web3'
|
||||
import { useOcean } from '../../../../providers/Ocean'
|
||||
|
||||
const contentQuery = graphql`
|
||||
query EditMetadataQuery {
|
||||
@ -57,7 +58,8 @@ export default function Edit({
|
||||
const content = data.content.edges[0].node.childPagesJson
|
||||
|
||||
const { debug } = useUserPreferences()
|
||||
const { ocean, accountId } = useOcean()
|
||||
const { accountId } = useWeb3()
|
||||
const { ocean } = useOcean()
|
||||
const { metadata, ddo, refreshDdo } = useAsset()
|
||||
const [success, setSuccess] = useState<string>()
|
||||
const [error, setError] = useState<string>()
|
||||
|
@ -2,9 +2,10 @@ import React, { ReactElement } from 'react'
|
||||
import Loader from '../../../atoms/Loader'
|
||||
import Button from '../../../atoms/Button'
|
||||
import styles from './Actions.module.css'
|
||||
import EtherscanLink from '../../../atoms/EtherscanLink'
|
||||
import ExplorerLink from '../../../atoms/ExplorerLink'
|
||||
import SuccessConfetti from '../../../atoms/SuccessConfetti'
|
||||
import { useOcean } from '@oceanprotocol/react'
|
||||
import { useOcean } from '../../../../providers/Ocean'
|
||||
import { useWeb3 } from '../../../../providers/Web3'
|
||||
|
||||
export default function Actions({
|
||||
isLoading,
|
||||
@ -23,7 +24,8 @@ export default function Actions({
|
||||
action: () => void
|
||||
isDisabled?: boolean
|
||||
}): ReactElement {
|
||||
const { networkId, ocean } = useOcean()
|
||||
const { networkId } = useWeb3()
|
||||
const { ocean } = useOcean()
|
||||
|
||||
return (
|
||||
<>
|
||||
@ -46,9 +48,9 @@ export default function Actions({
|
||||
className={styles.success}
|
||||
success={successMessage}
|
||||
action={
|
||||
<EtherscanLink networkId={networkId} path={`/tx/${txId}`}>
|
||||
See on Etherscan
|
||||
</EtherscanLink>
|
||||
<ExplorerLink networkId={networkId} path={`/tx/${txId}`}>
|
||||
View transaction
|
||||
</ExplorerLink>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
|
@ -10,9 +10,9 @@ import {
|
||||
import Button from '../../../../atoms/Button'
|
||||
import CoinSelect from '../CoinSelect'
|
||||
import { FormAddLiquidity } from '.'
|
||||
import { useOcean } from '@oceanprotocol/react'
|
||||
import TokenBalance from '../../../../../@types/TokenBalance'
|
||||
import { PoolBalance } from '../../../../../@types/TokenBalance'
|
||||
import UserLiquidity from '../../../../atoms/UserLiquidity'
|
||||
import { useOcean } from '../../../../../providers/Ocean'
|
||||
|
||||
export default function FormAdd({
|
||||
coin,
|
||||
@ -32,7 +32,7 @@ export default function FormAdd({
|
||||
amountMax: string
|
||||
setCoin: (value: string) => void
|
||||
totalPoolTokens: string
|
||||
totalBalance: TokenBalance
|
||||
totalBalance: PoolBalance
|
||||
poolAddress: string
|
||||
setNewPoolTokens: (value: string) => void
|
||||
setNewPoolShare: (value: string) => void
|
||||
|
@ -2,7 +2,7 @@ import { FormikContextType, useFormikContext } from 'formik'
|
||||
import { graphql, useStaticQuery } from 'gatsby'
|
||||
import React, { ReactElement, useEffect, useState } from 'react'
|
||||
import { FormAddLiquidity } from '.'
|
||||
import TokenBalance from '../../../../../@types/TokenBalance'
|
||||
import { PoolBalance } from '../../../../../@types/TokenBalance'
|
||||
import FormHelp from '../../../../atoms/Input/Help'
|
||||
import Token from '../Token'
|
||||
import styles from './Output.module.css'
|
||||
@ -44,7 +44,7 @@ export default function Output({
|
||||
swapFee: string
|
||||
dtSymbol: string
|
||||
totalPoolTokens: string
|
||||
totalBalance: TokenBalance
|
||||
totalBalance: PoolBalance
|
||||
coin: string
|
||||
}): ReactElement {
|
||||
const data = useStaticQuery(contentQuery)
|
||||
|
@ -1,5 +1,4 @@
|
||||
import React, { ReactElement, useState, useEffect } from 'react'
|
||||
import { useOcean } from '@oceanprotocol/react'
|
||||
import Header from '../Header'
|
||||
import { toast } from 'react-toastify'
|
||||
import Actions from '../Actions'
|
||||
@ -9,10 +8,12 @@ import { Formik } from 'formik'
|
||||
import FormAdd from './FormAdd'
|
||||
import styles from './index.module.css'
|
||||
import Alert from '../../../../atoms/Alert'
|
||||
import TokenBalance from '../../../../../@types/TokenBalance'
|
||||
import { PoolBalance } from '../../../../../@types/TokenBalance'
|
||||
import { useUserPreferences } from '../../../../../providers/UserPreferences'
|
||||
import Output from './Output'
|
||||
import DebugOutput from '../../../../atoms/DebugOutput'
|
||||
import { useOcean } from '../../../../../providers/Ocean'
|
||||
import { useWeb3 } from '../../../../../providers/Web3'
|
||||
|
||||
const contentQuery = graphql`
|
||||
query PoolAddQuery {
|
||||
@ -56,7 +57,7 @@ export default function Add({
|
||||
refreshInfo: () => void
|
||||
poolAddress: string
|
||||
totalPoolTokens: string
|
||||
totalBalance: TokenBalance
|
||||
totalBalance: PoolBalance
|
||||
swapFee: string
|
||||
dtSymbol: string
|
||||
dtAddress: string
|
||||
@ -64,7 +65,8 @@ export default function Add({
|
||||
const data = useStaticQuery(contentQuery)
|
||||
const content = data.content.edges[0].node.childContentJson.pool.add
|
||||
|
||||
const { ocean, accountId, balance } = useOcean()
|
||||
const { accountId } = useWeb3()
|
||||
const { ocean, balance } = useOcean()
|
||||
const { debug } = useUserPreferences()
|
||||
const [txId, setTxId] = useState<string>()
|
||||
const [coin, setCoin] = useState('OCEAN')
|
||||
|
@ -7,7 +7,6 @@ import React, {
|
||||
useRef
|
||||
} from 'react'
|
||||
import styles from './Remove.module.css'
|
||||
import { useOcean } from '@oceanprotocol/react'
|
||||
import Header from './Header'
|
||||
import { toast } from 'react-toastify'
|
||||
import Actions from './Actions'
|
||||
@ -19,6 +18,8 @@ import { getMaxPercentRemove } from './utils'
|
||||
import { graphql, useStaticQuery } from 'gatsby'
|
||||
import debounce from 'lodash.debounce'
|
||||
import UserLiquidity from '../../../atoms/UserLiquidity'
|
||||
import { useOcean } from '../../../../providers/Ocean'
|
||||
import { useWeb3 } from '../../../../providers/Web3'
|
||||
|
||||
const contentQuery = graphql`
|
||||
query PoolRemoveQuery {
|
||||
@ -63,7 +64,8 @@ export default function Remove({
|
||||
const data = useStaticQuery(contentQuery)
|
||||
const content = data.content.edges[0].node.childContentJson.pool.remove
|
||||
|
||||
const { ocean, accountId } = useOcean()
|
||||
const { accountId } = useWeb3()
|
||||
const { ocean } = useOcean()
|
||||
const [amountPercent, setAmountPercent] = useState('0')
|
||||
const [amountMaxPercent, setAmountMaxPercent] = useState('100')
|
||||
const [amountPoolShares, setAmountPoolShares] = useState('0')
|
||||
|
@ -1,5 +1,4 @@
|
||||
import React, { ReactElement, useEffect, useState } from 'react'
|
||||
import { useOcean } from '@oceanprotocol/react'
|
||||
import { Logger } from '@oceanprotocol/lib'
|
||||
import styles from './index.module.css'
|
||||
import stylesActions from './Actions.module.css'
|
||||
@ -8,16 +7,18 @@ import Button from '../../../atoms/Button'
|
||||
import Add from './Add'
|
||||
import Remove from './Remove'
|
||||
import Tooltip from '../../../atoms/Tooltip'
|
||||
import EtherscanLink from '../../../atoms/EtherscanLink'
|
||||
import ExplorerLink from '../../../atoms/ExplorerLink'
|
||||
import Token from './Token'
|
||||
import TokenList from './TokenList'
|
||||
import { graphql, useStaticQuery } from 'gatsby'
|
||||
import TokenBalance from '../../../../@types/TokenBalance'
|
||||
import { PoolBalance } from '../../../../@types/TokenBalance'
|
||||
import Transactions from './Transactions'
|
||||
import Graph from './Graph'
|
||||
import { useAsset } from '../../../../providers/Asset'
|
||||
import { gql, useQuery } from '@apollo/client'
|
||||
import { PoolLiquidity } from '../../../../@types/apollo/PoolLiquidity'
|
||||
import { useOcean } from '../../../../providers/Ocean'
|
||||
import { useWeb3 } from '../../../../providers/Web3'
|
||||
|
||||
const contentQuery = graphql`
|
||||
query PoolQuery {
|
||||
@ -60,20 +61,14 @@ export default function Pool(): ReactElement {
|
||||
const data = useStaticQuery(contentQuery)
|
||||
const content = data.content.edges[0].node.childContentJson.pool
|
||||
|
||||
const { ocean, accountId, networkId } = useOcean()
|
||||
const {
|
||||
isInPurgatory,
|
||||
ddo,
|
||||
owner,
|
||||
price,
|
||||
refreshInterval,
|
||||
refreshPrice
|
||||
} = useAsset()
|
||||
const { accountId, networkId } = useWeb3()
|
||||
const { ocean } = useOcean()
|
||||
const { isInPurgatory, ddo, owner, price, refreshInterval } = useAsset()
|
||||
const dtSymbol = ddo?.dataTokenInfo.symbol
|
||||
|
||||
const [poolTokens, setPoolTokens] = useState<string>()
|
||||
const [totalPoolTokens, setTotalPoolTokens] = useState<string>()
|
||||
const [userLiquidity, setUserLiquidity] = useState<TokenBalance>()
|
||||
const [userLiquidity, setUserLiquidity] = useState<PoolBalance>()
|
||||
const [swapFee, setSwapFee] = useState<string>()
|
||||
const [weightOcean, setWeightOcean] = useState<string>()
|
||||
const [weightDt, setWeightDt] = useState<string>()
|
||||
@ -91,7 +86,7 @@ export default function Pool(): ReactElement {
|
||||
creatorTotalLiquidityInOcean,
|
||||
setCreatorTotalLiquidityInOcean
|
||||
] = useState(0)
|
||||
const [creatorLiquidity, setCreatorLiquidity] = useState<TokenBalance>()
|
||||
const [creatorLiquidity, setCreatorLiquidity] = useState<PoolBalance>()
|
||||
const [creatorPoolTokens, setCreatorPoolTokens] = useState<string>()
|
||||
const [creatorPoolShare, setCreatorPoolShare] = useState<string>()
|
||||
|
||||
@ -209,7 +204,9 @@ export default function Pool(): ReactElement {
|
||||
|
||||
const refreshInfo = async () => {
|
||||
setRefreshPool(!refreshPool)
|
||||
await refreshPrice()
|
||||
|
||||
// need some form of replacement or something.
|
||||
// await refreshPrice()
|
||||
}
|
||||
|
||||
return (
|
||||
@ -244,18 +241,22 @@ export default function Pool(): ReactElement {
|
||||
<PriceUnit price={`${price?.value}`} />
|
||||
<Tooltip content={content.tooltips.price} />
|
||||
<div className={styles.dataTokenLinks}>
|
||||
<EtherscanLink
|
||||
<ExplorerLink
|
||||
networkId={networkId}
|
||||
path={`address/${price?.address}`}
|
||||
>
|
||||
Pool
|
||||
</EtherscanLink>
|
||||
<EtherscanLink
|
||||
</ExplorerLink>
|
||||
<ExplorerLink
|
||||
networkId={networkId}
|
||||
path={`token/${ddo.dataToken}`}
|
||||
path={
|
||||
networkId === 137
|
||||
? `tokens/${ddo.dataToken}`
|
||||
: `token/${ddo.dataToken}`
|
||||
}
|
||||
>
|
||||
Datatoken
|
||||
</EtherscanLink>
|
||||
</ExplorerLink>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -1,5 +1,4 @@
|
||||
import React, { ReactElement, useState } from 'react'
|
||||
import { useOcean } from '@oceanprotocol/react'
|
||||
import { BestPrice, DDO, Logger } from '@oceanprotocol/lib'
|
||||
import * as Yup from 'yup'
|
||||
import { Formik } from 'formik'
|
||||
@ -8,11 +7,13 @@ import { graphql, useStaticQuery } from 'gatsby'
|
||||
import { useUserPreferences } from '../../../../providers/UserPreferences'
|
||||
import { toast } from 'react-toastify'
|
||||
import Swap from './Swap'
|
||||
import TokenBalance from '../../../../@types/TokenBalance'
|
||||
import { PoolBalance } from '../../../../@types/TokenBalance'
|
||||
import Alert from '../../../atoms/Alert'
|
||||
import styles from './FormTrade.module.css'
|
||||
import { FormTradeData, initialValues } from '../../../../models/FormTrade'
|
||||
import Decimal from 'decimal.js'
|
||||
import { useOcean } from '../../../../providers/Ocean'
|
||||
import { useWeb3 } from '../../../../providers/Web3'
|
||||
|
||||
const contentQuery = graphql`
|
||||
query TradeQuery {
|
||||
@ -39,14 +40,15 @@ export default function FormTrade({
|
||||
price
|
||||
}: {
|
||||
ddo: DDO
|
||||
balance: TokenBalance
|
||||
balance: PoolBalance
|
||||
maxDt: number
|
||||
maxOcean: number
|
||||
price: BestPrice
|
||||
}): ReactElement {
|
||||
const data = useStaticQuery(contentQuery)
|
||||
const content = data.content.edges[0].node.childContentJson.trade
|
||||
const { ocean, accountId } = useOcean()
|
||||
const { accountId } = useWeb3()
|
||||
const { ocean } = useOcean()
|
||||
const { debug } = useUserPreferences()
|
||||
const [txId, setTxId] = useState<string>()
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { useOcean } from '@oceanprotocol/react'
|
||||
import { FormikContextType, useFormikContext } from 'formik'
|
||||
import React, { ReactElement, useEffect, useState } from 'react'
|
||||
import { FormTradeData } from '../../../../models/FormTrade'
|
||||
import { useOcean } from '../../../../providers/Ocean'
|
||||
import Token from '../Pool/Token'
|
||||
import styles from './Output.module.css'
|
||||
|
||||
|
@ -1,15 +1,15 @@
|
||||
import React, { ReactElement, useEffect, useState } from 'react'
|
||||
import { useOcean } from '@oceanprotocol/react'
|
||||
import { BestPrice, DDO } from '@oceanprotocol/lib'
|
||||
import styles from './Swap.module.css'
|
||||
import TradeInput from './TradeInput'
|
||||
import Button from '../../../atoms/Button'
|
||||
import { ReactComponent as Arrow } from '../../../../images/arrow.svg'
|
||||
import { FormikContextType, useFormikContext } from 'formik'
|
||||
import TokenBalance from '../../../../@types/TokenBalance'
|
||||
import { PoolBalance } from '../../../../@types/TokenBalance'
|
||||
import Output from './Output'
|
||||
import Slippage from './Slippage'
|
||||
import { FormTradeData, TradeItem } from '../../../../models/FormTrade'
|
||||
import { useOcean } from '../../../../providers/Ocean'
|
||||
|
||||
export default function Swap({
|
||||
ddo,
|
||||
@ -23,7 +23,7 @@ export default function Swap({
|
||||
ddo: DDO
|
||||
maxDt: number
|
||||
maxOcean: number
|
||||
balance: TokenBalance
|
||||
balance: PoolBalance
|
||||
price: BestPrice
|
||||
setMaximumDt: (value: number) => void
|
||||
setMaximumOcean: (value: number) => void
|
||||
|
@ -1,18 +1,16 @@
|
||||
import React, { ChangeEvent, ReactElement } from 'react'
|
||||
import styles from './TradeInput.module.css'
|
||||
|
||||
import {
|
||||
Field,
|
||||
FieldInputProps,
|
||||
FormikContextType,
|
||||
useFormikContext
|
||||
} from 'formik'
|
||||
|
||||
import { useOcean } from '@oceanprotocol/react'
|
||||
import Input from '../../../atoms/Input'
|
||||
import Button from '../../../atoms/Button'
|
||||
import UserLiquidity from '../../../atoms/UserLiquidity'
|
||||
import { FormTradeData, TradeItem } from '../../../../models/FormTrade'
|
||||
import { useOcean } from '../../../../providers/Ocean'
|
||||
|
||||
export default function TradeInput({
|
||||
name,
|
||||
|
@ -1,12 +1,14 @@
|
||||
import React, { ReactElement, useEffect, useState } from 'react'
|
||||
import { useOcean } from '@oceanprotocol/react'
|
||||
import FormTrade from './FormTrade'
|
||||
import TokenBalance from '../../../../@types/TokenBalance'
|
||||
import { PoolBalance } from '../../../../@types/TokenBalance'
|
||||
import { useAsset } from '../../../../providers/Asset'
|
||||
import { useOcean } from '../../../../providers/Ocean'
|
||||
import { useWeb3 } from '../../../../providers/Web3'
|
||||
|
||||
export default function Trade(): ReactElement {
|
||||
const { ocean, balance, accountId } = useOcean()
|
||||
const [tokenBalance, setTokenBalance] = useState<TokenBalance>()
|
||||
const { accountId } = useWeb3()
|
||||
const { ocean, balance } = useOcean()
|
||||
const [tokenBalance, setTokenBalance] = useState<PoolBalance>()
|
||||
const { price, ddo } = useAsset()
|
||||
const [maxDt, setMaxDt] = useState(0)
|
||||
const [maxOcean, setMaxOcean] = useState(0)
|
||||
|
@ -4,14 +4,16 @@ import Compute from './Compute'
|
||||
import Consume from './Consume'
|
||||
import { Logger } from '@oceanprotocol/lib'
|
||||
import Tabs from '../../atoms/Tabs'
|
||||
import { useOcean } from '@oceanprotocol/react'
|
||||
import compareAsBN from '../../../utils/compareAsBN'
|
||||
import Pool from './Pool'
|
||||
import Trade from './Trade'
|
||||
import { useAsset } from '../../../providers/Asset'
|
||||
import { useOcean } from '../../../providers/Ocean'
|
||||
import { useWeb3 } from '../../../providers/Web3'
|
||||
|
||||
export default function AssetActions(): ReactElement {
|
||||
const { ocean, balance, accountId } = useOcean()
|
||||
const { accountId } = useWeb3()
|
||||
const { ocean, balance, account } = useOcean()
|
||||
const { price, ddo, metadata } = useAsset()
|
||||
|
||||
const [isBalanceSufficient, setIsBalanceSufficient] = useState<boolean>()
|
||||
@ -39,7 +41,7 @@ export default function AssetActions(): ReactElement {
|
||||
|
||||
// Check user balance against price
|
||||
useEffect(() => {
|
||||
if (!price?.value || !accountId || !balance?.ocean || !dtBalance) return
|
||||
if (!price?.value || !account || !balance?.ocean || !dtBalance) return
|
||||
|
||||
setIsBalanceSufficient(
|
||||
compareAsBN(balance.ocean, `${price.value}`) || Number(dtBalance) >= 1
|
||||
@ -48,7 +50,7 @@ export default function AssetActions(): ReactElement {
|
||||
return () => {
|
||||
setIsBalanceSufficient(false)
|
||||
}
|
||||
}, [balance, accountId, price, dtBalance])
|
||||
}, [balance, account, price, dtBalance])
|
||||
|
||||
const UseContent = isCompute ? (
|
||||
<Compute
|
||||
|
@ -2,8 +2,8 @@ import { useUserPreferences } from '../../../providers/UserPreferences'
|
||||
import React, { ReactElement } from 'react'
|
||||
import styles from './Bookmark.module.css'
|
||||
import { ReactComponent as BookmarkIcon } from '../../../images/bookmark.svg'
|
||||
import { useOcean } from '@oceanprotocol/react'
|
||||
import { ConfigHelperConfig } from '@oceanprotocol/lib/dist/node/utils/ConfigHelper'
|
||||
import { useOcean } from '../../../providers/Ocean'
|
||||
|
||||
export default function Bookmark({ did }: { did: string }): ReactElement {
|
||||
const { config } = useOcean()
|
||||
|
@ -1,17 +1,15 @@
|
||||
import { useOcean } from '@oceanprotocol/react'
|
||||
import React, { ReactElement, useEffect, useState } from 'react'
|
||||
import { useAsset } from '../../../providers/Asset'
|
||||
import EtherscanLink from '../../atoms/EtherscanLink'
|
||||
import ExplorerLink from '../../atoms/ExplorerLink'
|
||||
import Time from '../../atoms/Time'
|
||||
import styles from './EditHistory.module.css'
|
||||
import { gql, useQuery } from '@apollo/client'
|
||||
import { ReceiptData_datatokens_updates as ReceiptData } from '../../../@types/apollo/ReceiptData'
|
||||
import { useWeb3 } from '../../../providers/Web3'
|
||||
|
||||
const getReceipts = gql`
|
||||
query ReceiptData($address: ID!) {
|
||||
datatokens(where: { id: $address }) {
|
||||
createTime
|
||||
tx
|
||||
updates(orderBy: timestamp, orderDirection: desc) {
|
||||
id
|
||||
tx
|
||||
@ -22,7 +20,7 @@ const getReceipts = gql`
|
||||
`
|
||||
|
||||
export default function EditHistory(): ReactElement {
|
||||
const { networkId } = useOcean()
|
||||
const { networkId } = useWeb3()
|
||||
const { ddo } = useAsset()
|
||||
const { data } = useQuery(getReceipts, {
|
||||
variables: { address: ddo?.dataToken.toLowerCase() }
|
||||
@ -33,8 +31,15 @@ export default function EditHistory(): ReactElement {
|
||||
|
||||
useEffect(() => {
|
||||
if (!data || data.datatokens.length === 0) return
|
||||
setReceipts(data.datatokens[0].updates)
|
||||
setCreationTx(data.datatokens[0].tx)
|
||||
|
||||
const receiptCollectionLength = data.datatokens[0].updates.length
|
||||
const creationData = data.datatokens[0].updates[receiptCollectionLength - 1]
|
||||
setCreationTx(creationData.tx)
|
||||
|
||||
const receiptCollection = [...data.datatokens[0].updates]
|
||||
receiptCollection.splice(-1, 1)
|
||||
|
||||
setReceipts(receiptCollection)
|
||||
}, [data])
|
||||
|
||||
return (
|
||||
@ -43,16 +48,16 @@ export default function EditHistory(): ReactElement {
|
||||
<ul className={styles.history}>
|
||||
{receipts?.map((receipt) => (
|
||||
<li key={receipt.id} className={styles.item}>
|
||||
<EtherscanLink networkId={networkId} path={`/tx/${receipt.tx}`}>
|
||||
<ExplorerLink networkId={networkId} path={`/tx/${receipt.tx}`}>
|
||||
edited{' '}
|
||||
<Time date={receipt.timestamp.toString()} relative isUnix />
|
||||
</EtherscanLink>
|
||||
</ExplorerLink>
|
||||
</li>
|
||||
))}
|
||||
<li className={styles.item}>
|
||||
<EtherscanLink networkId={networkId} path={`/tx/${creationTx}`}>
|
||||
<ExplorerLink networkId={networkId} path={`/tx/${creationTx}`}>
|
||||
published <Time date={ddo.created} relative />
|
||||
</EtherscanLink>
|
||||
</ExplorerLink>
|
||||
</li>
|
||||
</ul>
|
||||
</>
|
||||
|
@ -1,5 +1,4 @@
|
||||
import React, { ReactElement } from 'react'
|
||||
import Time from '../../atoms/Time'
|
||||
import MetaItem from './MetaItem'
|
||||
import styles from './MetaFull.module.css'
|
||||
import Publisher from '../../atoms/Publisher'
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { useOcean } from '@oceanprotocol/react'
|
||||
import React, { ReactElement } from 'react'
|
||||
import { useAsset } from '../../../providers/Asset'
|
||||
import EtherscanLink from '../../atoms/EtherscanLink'
|
||||
import { useWeb3 } from '../../../providers/Web3'
|
||||
import ExplorerLink from '../../atoms/ExplorerLink'
|
||||
import Publisher from '../../atoms/Publisher'
|
||||
import Time from '../../atoms/Time'
|
||||
import styles from './MetaMain.module.css'
|
||||
@ -9,16 +9,23 @@ import AssetType from '../../atoms/AssetType'
|
||||
|
||||
export default function MetaMain(): ReactElement {
|
||||
const { ddo, owner, type } = useAsset()
|
||||
const { networkId } = useOcean()
|
||||
const { networkId } = useWeb3()
|
||||
const isCompute = Boolean(ddo?.findServiceByType('compute'))
|
||||
const accessType = isCompute ? 'compute' : 'access'
|
||||
|
||||
return (
|
||||
<aside className={styles.meta}>
|
||||
<p>
|
||||
<EtherscanLink networkId={networkId} path={`token/${ddo?.dataToken}`}>
|
||||
<ExplorerLink
|
||||
networkId={networkId}
|
||||
path={
|
||||
networkId === 137
|
||||
? `tokens/${ddo?.dataToken}`
|
||||
: `token/${ddo?.dataToken}`
|
||||
}
|
||||
>
|
||||
{`${ddo?.dataTokenInfo.name} — ${ddo?.dataTokenInfo.symbol}`}
|
||||
</EtherscanLink>
|
||||
</ExplorerLink>
|
||||
</p>
|
||||
<div>
|
||||
Published By <Publisher account={owner} />
|
||||
|
@ -1,10 +1,10 @@
|
||||
import React, { ChangeEvent, ReactElement } from 'react'
|
||||
import React, { ReactElement } from 'react'
|
||||
import stylesIndex from './index.module.css'
|
||||
import styles from './Coin.module.css'
|
||||
import InputElement from '../../../../atoms/Input/InputElement'
|
||||
import { ReactComponent as Logo } from '../../../../../images/logo.svg'
|
||||
import Conversion from '../../../../atoms/Price/Conversion'
|
||||
import { DataTokenOptions } from '@oceanprotocol/react'
|
||||
import { DataTokenOptions } from '../../../../../hooks/usePublish'
|
||||
import { useField } from 'formik'
|
||||
import Error from './Error'
|
||||
|
||||
|
@ -1,4 +1,3 @@
|
||||
import { useOcean, usePricing } from '@oceanprotocol/react'
|
||||
import PriceUnit from '../../../../atoms/Price/PriceUnit'
|
||||
import React, { ReactElement, useEffect, useState } from 'react'
|
||||
import Alert from '../../../../atoms/Alert'
|
||||
@ -14,8 +13,8 @@ import { PriceOptionsMarket } from '../../../../../@types/MetaData'
|
||||
import { DDO } from '@oceanprotocol/lib'
|
||||
import Price from './Price'
|
||||
import Decimal from 'decimal.js'
|
||||
|
||||
const refreshInterval = 10000 // 10 sec.
|
||||
import { useOcean } from '../../../../../providers/Ocean'
|
||||
import { useWeb3 } from '../../../../../providers/Web3'
|
||||
|
||||
export default function Dynamic({
|
||||
ddo,
|
||||
@ -24,7 +23,8 @@ export default function Dynamic({
|
||||
ddo: DDO
|
||||
content: any
|
||||
}): ReactElement {
|
||||
const { account, balance, networkId, refreshBalance } = useOcean()
|
||||
const { networkId } = useWeb3()
|
||||
const { account, balance } = useOcean()
|
||||
const [firstPrice, setFirstPrice] = useState<string>()
|
||||
|
||||
// Connect with form
|
||||
@ -69,18 +69,6 @@ export default function Dynamic({
|
||||
}
|
||||
}, [price, networkId, account, balance])
|
||||
|
||||
// refetch balance periodically
|
||||
useEffect(() => {
|
||||
if (!account) return
|
||||
|
||||
refreshBalance()
|
||||
const balanceInterval = setInterval(() => refreshBalance(), refreshInterval)
|
||||
|
||||
return () => {
|
||||
clearInterval(balanceInterval)
|
||||
}
|
||||
}, [networkId, account])
|
||||
|
||||
return (
|
||||
<div className={styles.dynamic}>
|
||||
<FormHelp className={stylesIndex.help}>{content.info}</FormHelp>
|
||||
|
@ -1,4 +1,3 @@
|
||||
import { usePricing } from '@oceanprotocol/react'
|
||||
import Conversion from '../../../../atoms/Price/Conversion'
|
||||
import { useField } from 'formik'
|
||||
import React, { ReactElement } from 'react'
|
||||
@ -7,6 +6,7 @@ import styles from './Price.module.css'
|
||||
import Error from './Error'
|
||||
import { DDO } from '@oceanprotocol/lib'
|
||||
import PriceUnit from '../../../../atoms/Price/PriceUnit'
|
||||
import usePricing from '../../../../../hooks/usePricing'
|
||||
|
||||
export default function Price({
|
||||
ddo,
|
||||
|
@ -2,7 +2,6 @@ import React, { FormEvent, ReactElement, useState } from 'react'
|
||||
import { Formik } from 'formik'
|
||||
import { initialValues, validationSchema } from '../../../../models/FormPricing'
|
||||
import { DDO, Logger } from '@oceanprotocol/lib'
|
||||
import { usePricing } from '@oceanprotocol/react'
|
||||
import { PriceOptionsMarket } from '../../../../@types/MetaData'
|
||||
import Alert from '../../../atoms/Alert'
|
||||
import styles from './index.module.css'
|
||||
@ -10,6 +9,7 @@ import FormPricing from './FormPricing'
|
||||
import { toast } from 'react-toastify'
|
||||
import Feedback from './Feedback'
|
||||
import { graphql, useStaticQuery } from 'gatsby'
|
||||
import { usePricing } from '../../../../hooks/usePricing'
|
||||
|
||||
const query = graphql`
|
||||
query PricingQuery {
|
||||
|
@ -7,7 +7,6 @@ import styles from './index.module.css'
|
||||
import AssetActions from '../AssetActions'
|
||||
import { useUserPreferences } from '../../../providers/UserPreferences'
|
||||
import Pricing from './Pricing'
|
||||
import { useOcean } from '@oceanprotocol/react'
|
||||
import Bookmark from './Bookmark'
|
||||
import { useAsset } from '../../../providers/Asset'
|
||||
import Alert from '../../atoms/Alert'
|
||||
@ -16,6 +15,7 @@ import Edit from '../AssetActions/Edit'
|
||||
import DebugOutput from '../../atoms/DebugOutput'
|
||||
import MetaMain from './MetaMain'
|
||||
import EditHistory from './EditHistory'
|
||||
import { useWeb3 } from '../../../providers/Web3'
|
||||
|
||||
export interface AssetContentProps {
|
||||
path?: string
|
||||
@ -42,7 +42,7 @@ export default function AssetContent(props: AssetContentProps): ReactElement {
|
||||
const data = useStaticQuery(contentQuery)
|
||||
const content = data.purgatory.edges[0].node.childContentJson.asset
|
||||
const { debug } = useUserPreferences()
|
||||
const { accountId } = useOcean()
|
||||
const { accountId } = useWeb3()
|
||||
const { owner, isInPurgatory, purgatoryData } = useAsset()
|
||||
const [showPricing, setShowPricing] = useState(false)
|
||||
const [showEdit, setShowEdit] = useState<boolean>()
|
||||
|
@ -1,5 +1,4 @@
|
||||
import { Logger } from '@oceanprotocol/lib'
|
||||
import { useOcean } from '@oceanprotocol/react'
|
||||
import React, { ReactElement, useEffect, useState } from 'react'
|
||||
import Loader from '../../atoms/Loader'
|
||||
import Modal from '../../atoms/Modal'
|
||||
@ -9,6 +8,7 @@ import shortid from 'shortid'
|
||||
import styles from './ComputeDetails.module.css'
|
||||
import { Status } from './ComputeJobs'
|
||||
import { ListItem } from '../../atoms/Lists'
|
||||
import { useOcean } from '../../../providers/Ocean'
|
||||
|
||||
export default function ComputeDetailsModal({
|
||||
computeJob,
|
||||
@ -19,7 +19,7 @@ export default function ComputeDetailsModal({
|
||||
isOpen: boolean
|
||||
onToggleModal: () => void
|
||||
}): ReactElement {
|
||||
const { ocean, status, account } = useOcean()
|
||||
const { ocean, account } = useOcean()
|
||||
const [isLoading, setIsLoading] = useState(false)
|
||||
|
||||
const isFinished = computeJob.dateFinished !== null
|
||||
@ -48,7 +48,7 @@ export default function ComputeDetailsModal({
|
||||
}
|
||||
}
|
||||
getDetails()
|
||||
}, [ocean, status, account, isOpen, computeJob, isFinished])
|
||||
}, [ocean, account, isOpen, computeJob, isFinished])
|
||||
|
||||
return (
|
||||
<Modal
|
||||
|
@ -1,4 +1,3 @@
|
||||
import { useOcean } from '@oceanprotocol/react'
|
||||
import React, { ReactElement, useEffect, useState } from 'react'
|
||||
import Time from '../../atoms/Time'
|
||||
import styles from './ComputeJobs.module.css'
|
||||
@ -9,6 +8,7 @@ import { Link } from 'gatsby'
|
||||
import { Logger } from '@oceanprotocol/lib'
|
||||
import Dotdotdot from 'react-dotdotdot'
|
||||
import Table from '../../atoms/Table'
|
||||
import { useOcean } from '../../../providers/Ocean'
|
||||
|
||||
function DetailsButton({ row }: { row: ComputeJobMetaData }): ReactElement {
|
||||
const [isDialogOpen, setIsDialogOpen] = useState(false)
|
||||
|
@ -1,11 +1,11 @@
|
||||
import React, { ReactElement, useEffect, useState } from 'react'
|
||||
import { useOcean } from '@oceanprotocol/react'
|
||||
import Table from '../../atoms/Table'
|
||||
import { gql, useQuery } from '@apollo/client'
|
||||
import Time from '../../atoms/Time'
|
||||
import { OrdersData_tokenOrders as OrdersDataTokenOrders } from '../../../@types/apollo/OrdersData'
|
||||
import web3 from 'web3'
|
||||
import AssetTitle from '../../molecules/AssetListTitle'
|
||||
import { useWeb3 } from '../../../providers/Web3'
|
||||
|
||||
const getTokenOrders = gql`
|
||||
query OrdersData($user: String!) {
|
||||
@ -50,7 +50,7 @@ const columns = [
|
||||
]
|
||||
|
||||
export default function ComputeDownloads(): ReactElement {
|
||||
const { accountId } = useOcean()
|
||||
const { accountId } = useWeb3()
|
||||
const [orders, setOrders] = useState<OrdersDataTokenOrders[]>()
|
||||
const { data } = useQuery(getTokenOrders, {
|
||||
variables: { user: accountId?.toLowerCase() }
|
||||
|
@ -1,4 +1,3 @@
|
||||
import { useOcean } from '@oceanprotocol/react'
|
||||
import React, { ReactElement, useEffect, useState } from 'react'
|
||||
import Table from '../../atoms/Table'
|
||||
import Conversion from '../../atoms/Price/Conversion'
|
||||
@ -12,6 +11,7 @@ import {
|
||||
} from '../../../@types/apollo/PoolShares'
|
||||
import web3 from 'web3'
|
||||
import Token from '../../organisms/AssetActions/Pool/Token'
|
||||
import { useWeb3 } from '../../../providers/Web3'
|
||||
|
||||
const poolSharesQuery = gql`
|
||||
query PoolShares($user: String) {
|
||||
@ -139,7 +139,7 @@ const columns = [
|
||||
]
|
||||
|
||||
export default function PoolShares(): ReactElement {
|
||||
const { accountId } = useOcean()
|
||||
const { accountId } = useWeb3()
|
||||
const [assets, setAssets] = useState<Asset[]>()
|
||||
const { data, loading } = useQuery<PoolSharesList>(poolSharesQuery, {
|
||||
variables: {
|
||||
|
@ -1,20 +1,23 @@
|
||||
import { Logger } from '@oceanprotocol/lib'
|
||||
import { QueryResult } from '@oceanprotocol/lib/dist/node/metadatacache/MetadataCache'
|
||||
import { useOcean } from '@oceanprotocol/react'
|
||||
import React, { ReactElement, useEffect, useState } from 'react'
|
||||
import Loader from '../../atoms/Loader'
|
||||
import AssetList from '../../organisms/AssetList'
|
||||
import axios from 'axios'
|
||||
import { queryMetadata } from '../../../utils/aquarius'
|
||||
import { useWeb3 } from '../../../providers/Web3'
|
||||
import { useOcean } from '../../../providers/Ocean'
|
||||
|
||||
export default function PublishedList(): ReactElement {
|
||||
const { accountId } = useOcean()
|
||||
const { accountId } = useWeb3()
|
||||
const { config } = useOcean()
|
||||
|
||||
const [queryResult, setQueryResult] = useState<QueryResult>()
|
||||
const [isLoading, setIsLoading] = useState(false)
|
||||
const { config } = useOcean()
|
||||
const source = axios.CancelToken.source()
|
||||
const [page, setPage] = useState<number>(1)
|
||||
|
||||
const source = axios.CancelToken.source()
|
||||
|
||||
useEffect(() => {
|
||||
async function getPublished() {
|
||||
if (!accountId) return
|
||||
|
@ -5,7 +5,7 @@ import AssetList from '../organisms/AssetList'
|
||||
import { QueryResult } from '@oceanprotocol/lib/dist/node/metadatacache/MetadataCache'
|
||||
import Container from '../atoms/Container'
|
||||
import Loader from '../atoms/Loader'
|
||||
import { useOcean } from '@oceanprotocol/react'
|
||||
import { useOcean } from '../../providers/Ocean'
|
||||
import Button from '../atoms/Button'
|
||||
import Bookmarks from '../molecules/Bookmarks'
|
||||
import axios from 'axios'
|
||||
|
@ -7,7 +7,7 @@ import React, {
|
||||
} from 'react'
|
||||
import { useStaticQuery, graphql } from 'gatsby'
|
||||
import styles from './FormPublish.module.css'
|
||||
import { useOcean } from '@oceanprotocol/react'
|
||||
import { useOcean } from '../../../providers/Ocean'
|
||||
import { useFormikContext, Field, Form, FormikContextType } from 'formik'
|
||||
import Input from '../../atoms/Input'
|
||||
import Button from '../../atoms/Button'
|
||||
|
@ -1,14 +1,14 @@
|
||||
import React, { ReactElement, useEffect, FormEvent, ChangeEvent } from 'react'
|
||||
import { useStaticQuery, graphql } from 'gatsby'
|
||||
import styles from './FormPublish.module.css'
|
||||
import { useOcean } from '@oceanprotocol/react'
|
||||
import { useFormikContext, Field, Form, FormikContextType } from 'formik'
|
||||
import Input from '../../atoms/Input'
|
||||
import Button from '../../atoms/Button'
|
||||
import { FormContent, FormFieldProps } from '../../../@types/Form'
|
||||
import { MetadataPublishFormDataset } from '../../../@types/MetaData'
|
||||
import { initialValues as initialValuesDataset } from '../../../models/FormAlgoPublish'
|
||||
import { useOcean } from '../../../providers/Ocean'
|
||||
import stylesIndex from './index.module.css'
|
||||
import styles from './FormPublish.module.css'
|
||||
|
||||
const query = graphql`
|
||||
query {
|
||||
|
@ -1,6 +1,6 @@
|
||||
import React, { ReactElement, useState, useEffect } from 'react'
|
||||
import { Formik, FormikState } from 'formik'
|
||||
import { usePublish, useOcean } from '@oceanprotocol/react'
|
||||
import { usePublish } from '../../../hooks/usePublish'
|
||||
import styles from './index.module.css'
|
||||
import FormPublish from './FormPublish'
|
||||
import FormAlgoPublish from './FormAlgoPublish'
|
||||
@ -31,6 +31,9 @@ import { Persist } from '../../atoms/FormikPersist'
|
||||
import Debug from './Debug'
|
||||
import Alert from '../../atoms/Alert'
|
||||
import MetadataFeedback from '../../molecules/MetadataFeedback'
|
||||
import { useAccountPurgatory } from '../../../hooks/useAccountPurgatory'
|
||||
import { useWeb3 } from '../../../providers/Web3'
|
||||
import { useSiteMetadata } from '../../../hooks/useSiteMetadata'
|
||||
|
||||
const formNameDatasets = 'ocean-publish-form-datasets'
|
||||
const formNameAlgorithms = 'ocean-publish-form-algorithms'
|
||||
@ -66,9 +69,11 @@ export default function PublishPage({
|
||||
}: {
|
||||
content: { warning: string }
|
||||
}): ReactElement {
|
||||
const { warningPolygonPublish } = useSiteMetadata()
|
||||
const { debug } = useUserPreferences()
|
||||
const { accountId, networkId } = useWeb3()
|
||||
const { isInPurgatory, purgatoryData } = useAccountPurgatory(accountId)
|
||||
const { publish, publishError, isLoading, publishStepText } = usePublish()
|
||||
const { isInPurgatory, purgatoryData } = useOcean()
|
||||
const [success, setSuccess] = useState<string>()
|
||||
const [error, setError] = useState<string>()
|
||||
const [title, setTitle] = useState<string>()
|
||||
|
@ -10,7 +10,7 @@ import { getResults } from './utils'
|
||||
import { navigate } from 'gatsby'
|
||||
import { updateQueryStringParameter } from '../../../utils'
|
||||
import Loader from '../../atoms/Loader'
|
||||
import { useOcean } from '@oceanprotocol/react'
|
||||
import { useOcean } from '../../../providers/Ocean'
|
||||
|
||||
export default function SearchPage({
|
||||
location,
|
||||
|
@ -1,101 +0,0 @@
|
||||
import React, { ReactElement, useEffect } from 'react'
|
||||
import { useOcean } from '@oceanprotocol/react'
|
||||
import { getOceanConfig } from './wrapRootElement'
|
||||
import { Logger } from '@oceanprotocol/lib'
|
||||
import { ConfigHelperConfig } from '@oceanprotocol/lib/dist/node/utils/ConfigHelper'
|
||||
import contractAddresses from '@oceanprotocol/contracts/artifacts/address.json'
|
||||
|
||||
const refreshInterval = 5000 // 5 sec.
|
||||
|
||||
export function getDevelopmentConfig(): Partial<ConfigHelperConfig> {
|
||||
return {
|
||||
factoryAddress: contractAddresses.development?.DTFactory,
|
||||
poolFactoryAddress: contractAddresses.development?.BFactory,
|
||||
fixedRateExchangeAddress: contractAddresses.development?.FixedRateExchange,
|
||||
metadataContractAddress: contractAddresses.development?.Metadata,
|
||||
oceanTokenAddress: contractAddresses.development?.Ocean,
|
||||
// There is no subgraph in barge so we hardcode the Rinkeby one for now
|
||||
subgraphUri: 'https://subgraph.rinkeby.oceanprotocol.com'
|
||||
}
|
||||
}
|
||||
|
||||
export function NetworkMonitor(): ReactElement {
|
||||
const {
|
||||
connect,
|
||||
web3Provider,
|
||||
web3,
|
||||
networkId,
|
||||
config,
|
||||
refreshBalance,
|
||||
account
|
||||
} = useOcean()
|
||||
|
||||
async function handleNetworkChanged(chainId: string | number) {
|
||||
const initialNewConfig = getOceanConfig(
|
||||
typeof chainId === 'string' ? Number(chainId.replace('0x', '')) : chainId
|
||||
)
|
||||
|
||||
const newConfig = {
|
||||
...initialNewConfig,
|
||||
|
||||
// add local dev values
|
||||
...(chainId === '8996' && {
|
||||
...getDevelopmentConfig()
|
||||
})
|
||||
}
|
||||
|
||||
try {
|
||||
await connect(newConfig)
|
||||
} catch (error) {
|
||||
Logger.error(error.message)
|
||||
}
|
||||
}
|
||||
|
||||
// Periodically refresh wallet balance
|
||||
useEffect(() => {
|
||||
if (!account) return
|
||||
|
||||
refreshBalance()
|
||||
const balanceInterval = setInterval(() => refreshBalance(), refreshInterval)
|
||||
|
||||
return () => {
|
||||
clearInterval(balanceInterval)
|
||||
}
|
||||
}, [networkId, account])
|
||||
|
||||
// Re-connect on mount when network is different from user network.
|
||||
// Bit nasty to just overwrite the initialConfig passed to OceanProvider
|
||||
// while it's connecting to that, but YOLO.
|
||||
useEffect(() => {
|
||||
if (!web3 || !networkId) return
|
||||
|
||||
async function init() {
|
||||
const chainIdWeb3 = await web3.eth.getChainId()
|
||||
const chainIdConfig = (config as ConfigHelperConfig).networkId
|
||||
|
||||
// HEADS UP! MetaMask built-in `Localhost 8545` network selection
|
||||
// will have `1337` as chainId but we use `8996` in our config
|
||||
if (
|
||||
chainIdWeb3 === chainIdConfig ||
|
||||
(chainIdWeb3 === 1337 && chainIdConfig === 8996)
|
||||
)
|
||||
return
|
||||
|
||||
await handleNetworkChanged(networkId)
|
||||
}
|
||||
init()
|
||||
}, [web3, networkId])
|
||||
|
||||
// Handle network change events
|
||||
useEffect(() => {
|
||||
if (!web3Provider) return
|
||||
|
||||
web3Provider.on('chainChanged', handleNetworkChanged)
|
||||
|
||||
return () => {
|
||||
web3Provider.removeListener('chainChanged', handleNetworkChanged)
|
||||
}
|
||||
}, [web3Provider])
|
||||
|
||||
return <></>
|
||||
}
|
@ -1,25 +1,11 @@
|
||||
import React, { ReactElement } from 'react'
|
||||
import { OceanProvider } from '@oceanprotocol/react'
|
||||
import { ConfigHelper, Config } from '@oceanprotocol/lib'
|
||||
import { web3ModalOpts } from '../utils/wallet'
|
||||
import { getDevelopmentConfig, NetworkMonitor } from './NetworkMonitor'
|
||||
import Web3Provider from '../providers/Web3'
|
||||
import appConfig from '../../app.config'
|
||||
import {
|
||||
ConfigHelperNetworkName,
|
||||
ConfigHelperNetworkId
|
||||
} from '@oceanprotocol/lib/dist/node/utils/ConfigHelper'
|
||||
import { UserPreferencesProvider } from '../providers/UserPreferences'
|
||||
import PricesProvider from '../providers/Prices'
|
||||
import ApolloClientProvider from '../providers/ApolloClientProvider'
|
||||
|
||||
export function getOceanConfig(
|
||||
network: ConfigHelperNetworkName | ConfigHelperNetworkId
|
||||
): Config {
|
||||
return new ConfigHelper().getConfig(
|
||||
network,
|
||||
process.env.GATSBY_INFURA_PROJECT_ID
|
||||
)
|
||||
}
|
||||
import OceanProvider from '../providers/Ocean'
|
||||
import { getDevelopmentConfig, getOceanConfig } from '../utils/ocean'
|
||||
|
||||
export default function wrapRootElement({
|
||||
element
|
||||
@ -37,16 +23,14 @@ export default function wrapRootElement({
|
||||
}
|
||||
|
||||
return (
|
||||
<OceanProvider
|
||||
initialConfig={oceanInitialConfig}
|
||||
web3ModalOpts={web3ModalOpts}
|
||||
>
|
||||
<Web3Provider>
|
||||
<OceanProvider initialConfig={oceanInitialConfig}>
|
||||
<ApolloClientProvider>
|
||||
<UserPreferencesProvider>
|
||||
<NetworkMonitor />
|
||||
<PricesProvider>{element}</PricesProvider>
|
||||
</UserPreferencesProvider>
|
||||
</ApolloClientProvider>
|
||||
</OceanProvider>
|
||||
</Web3Provider>
|
||||
)
|
||||
}
|
||||
|
51
src/hooks/useAccountPurgatory.ts
Normal file
51
src/hooks/useAccountPurgatory.ts
Normal file
@ -0,0 +1,51 @@
|
||||
import { useCallback, useEffect, useState } from 'react'
|
||||
import { Logger } from '@oceanprotocol/lib'
|
||||
import {
|
||||
PurgatoryDataAccount,
|
||||
getAccountPurgatoryData
|
||||
} from '../utils/purgatory'
|
||||
|
||||
interface UseAccountPurgatory {
|
||||
isInPurgatory: boolean
|
||||
purgatoryData: PurgatoryDataAccount
|
||||
isLoading: boolean
|
||||
}
|
||||
|
||||
function useAccountPurgatory(accountId: string): UseAccountPurgatory {
|
||||
const [isInPurgatory, setIsInPurgatory] = useState(false)
|
||||
const [purgatoryData, setPurgatoryData] = useState<PurgatoryDataAccount>()
|
||||
const [isLoading, setIsLoading] = useState(false)
|
||||
|
||||
const setAccountPurgatory = useCallback(
|
||||
async (address: string): Promise<void> => {
|
||||
if (!address) return
|
||||
|
||||
try {
|
||||
setIsLoading(true)
|
||||
const result = await getAccountPurgatoryData(address)
|
||||
const isInPurgatory = result?.address !== undefined
|
||||
setIsInPurgatory(isInPurgatory)
|
||||
isInPurgatory && setPurgatoryData(result)
|
||||
} catch (error) {
|
||||
Logger.error(error)
|
||||
} finally {
|
||||
setIsLoading(false)
|
||||
}
|
||||
},
|
||||
[]
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
if (!accountId) return
|
||||
setAccountPurgatory(accountId)
|
||||
}, [accountId, setAccountPurgatory])
|
||||
|
||||
return {
|
||||
isInPurgatory,
|
||||
purgatoryData,
|
||||
isLoading
|
||||
}
|
||||
}
|
||||
|
||||
export { useAccountPurgatory, UseAccountPurgatory }
|
||||
export default useAccountPurgatory
|
156
src/hooks/useCompute.ts
Normal file
156
src/hooks/useCompute.ts
Normal file
@ -0,0 +1,156 @@
|
||||
import { useState } from 'react'
|
||||
import { Logger, ServiceCompute } from '@oceanprotocol/lib'
|
||||
import { MetadataAlgorithm } from '@oceanprotocol/lib/dist/node/ddo/interfaces/MetadataAlgorithm'
|
||||
import { ComputeJob } from '@oceanprotocol/lib/dist/node/ocean/interfaces/ComputeJob'
|
||||
import { computeFeedback } from '../utils/feedback'
|
||||
import { useOcean } from '../providers/Ocean'
|
||||
import { useWeb3 } from '../providers/Web3'
|
||||
|
||||
interface ComputeValue {
|
||||
entrypoint: string
|
||||
image: string
|
||||
tag: string
|
||||
}
|
||||
interface ComputeOption {
|
||||
name: string
|
||||
value: ComputeValue
|
||||
}
|
||||
|
||||
const computeOptions: ComputeOption[] = [
|
||||
{
|
||||
name: 'nodejs',
|
||||
value: {
|
||||
entrypoint: 'node $ALGO',
|
||||
image: 'node',
|
||||
tag: '10'
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'python3.7',
|
||||
value: {
|
||||
entrypoint: 'python $ALGO',
|
||||
image: 'oceanprotocol/algo_dockers',
|
||||
tag: 'python-panda'
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
interface UseCompute {
|
||||
compute: (
|
||||
did: string,
|
||||
computeService: ServiceCompute,
|
||||
dataTokenAddress: string,
|
||||
algorithmRawCode: string,
|
||||
computeContainer: ComputeValue,
|
||||
marketFeeAddress?: string,
|
||||
orderId?: string
|
||||
) => Promise<ComputeJob | void>
|
||||
computeStep?: number
|
||||
computeStepText?: string
|
||||
computeError?: string
|
||||
isLoading: boolean
|
||||
}
|
||||
|
||||
const rawAlgorithmMeta: MetadataAlgorithm = {
|
||||
rawcode: `console.log('Hello world'!)`,
|
||||
format: 'docker-image',
|
||||
version: '0.1',
|
||||
container: {
|
||||
entrypoint: '',
|
||||
image: '',
|
||||
tag: ''
|
||||
}
|
||||
}
|
||||
|
||||
function useCompute(): UseCompute {
|
||||
const { accountId } = useWeb3()
|
||||
const { ocean, account } = useOcean()
|
||||
const [computeStep, setComputeStep] = useState<number | undefined>()
|
||||
const [computeStepText, setComputeStepText] = useState<string | undefined>()
|
||||
const [computeError, setComputeError] = useState<string | undefined>()
|
||||
const [isLoading, setIsLoading] = useState(false)
|
||||
|
||||
function setStep(index?: number) {
|
||||
if (!index) {
|
||||
setComputeStep(undefined)
|
||||
setComputeStepText(undefined)
|
||||
return
|
||||
}
|
||||
|
||||
setComputeStep(index)
|
||||
setComputeStepText(computeFeedback[index])
|
||||
}
|
||||
|
||||
async function compute(
|
||||
did: string,
|
||||
computeService: ServiceCompute,
|
||||
dataTokenAddress: string,
|
||||
algorithmRawCode: string,
|
||||
computeContainer: ComputeValue,
|
||||
marketFeeAddress?: string,
|
||||
orderId?: string
|
||||
): Promise<ComputeJob | void> {
|
||||
if (!ocean || !account) return
|
||||
setComputeError(undefined)
|
||||
try {
|
||||
setIsLoading(true)
|
||||
setStep(0)
|
||||
rawAlgorithmMeta.container = computeContainer
|
||||
rawAlgorithmMeta.rawcode = algorithmRawCode
|
||||
const output = {}
|
||||
if (!orderId) {
|
||||
const userOwnedTokens = await ocean.accounts.getTokenBalance(
|
||||
dataTokenAddress,
|
||||
account
|
||||
)
|
||||
if (parseFloat(userOwnedTokens) < 1) {
|
||||
setComputeError('Not enough datatokens')
|
||||
} else {
|
||||
Logger.log(
|
||||
'compute order',
|
||||
accountId,
|
||||
did,
|
||||
computeService,
|
||||
rawAlgorithmMeta,
|
||||
marketFeeAddress
|
||||
)
|
||||
orderId = await ocean.compute.orderAsset(
|
||||
accountId,
|
||||
did,
|
||||
computeService.index,
|
||||
undefined,
|
||||
rawAlgorithmMeta,
|
||||
marketFeeAddress
|
||||
)
|
||||
setStep(1)
|
||||
}
|
||||
}
|
||||
setStep(2)
|
||||
if (orderId) {
|
||||
const response = await ocean.compute.start(
|
||||
did,
|
||||
orderId,
|
||||
dataTokenAddress,
|
||||
account,
|
||||
undefined,
|
||||
rawAlgorithmMeta,
|
||||
output,
|
||||
`${computeService.index}`,
|
||||
computeService.type
|
||||
)
|
||||
return response
|
||||
}
|
||||
} catch (error) {
|
||||
Logger.error(error)
|
||||
setComputeError(error.message)
|
||||
} finally {
|
||||
setStep(undefined)
|
||||
setIsLoading(false)
|
||||
}
|
||||
}
|
||||
|
||||
return { compute, computeStep, computeStepText, computeError, isLoading }
|
||||
}
|
||||
|
||||
export { useCompute, UseCompute, ComputeValue, ComputeOption, computeOptions }
|
||||
export default UseCompute
|
93
src/hooks/useConsume.ts
Normal file
93
src/hooks/useConsume.ts
Normal file
@ -0,0 +1,93 @@
|
||||
import { useState } from 'react'
|
||||
import { consumeFeedback } from '../utils/feedback'
|
||||
import { DID, Logger, ServiceType } from '@oceanprotocol/lib'
|
||||
import { useOcean } from '../providers/Ocean'
|
||||
import { useWeb3 } from '../providers/Web3'
|
||||
|
||||
interface UseConsume {
|
||||
consume: (
|
||||
did: DID | string,
|
||||
dataTokenAddress: string,
|
||||
serviceType: ServiceType,
|
||||
marketFeeAddress: string,
|
||||
orderId?: string
|
||||
) => Promise<void>
|
||||
consumeStep?: number
|
||||
consumeStepText?: string
|
||||
consumeError?: string
|
||||
isLoading: boolean
|
||||
}
|
||||
|
||||
function useConsume(): UseConsume {
|
||||
const { accountId } = useWeb3()
|
||||
const { ocean, account } = useOcean()
|
||||
const [isLoading, setIsLoading] = useState(false)
|
||||
const [consumeStep, setConsumeStep] = useState<number | undefined>()
|
||||
const [consumeStepText, setConsumeStepText] = useState<string | undefined>()
|
||||
const [consumeError, setConsumeError] = useState<string | undefined>()
|
||||
|
||||
function setStep(index: number) {
|
||||
setConsumeStep(index)
|
||||
setConsumeStepText(consumeFeedback[index])
|
||||
}
|
||||
|
||||
async function consume(
|
||||
did: DID | string,
|
||||
dataTokenAddress: string,
|
||||
serviceType: ServiceType = 'access',
|
||||
marketFeeAddress: string,
|
||||
orderId?: string
|
||||
): Promise<void> {
|
||||
if (!ocean || !account || !accountId) return
|
||||
|
||||
setIsLoading(true)
|
||||
setConsumeError(undefined)
|
||||
|
||||
try {
|
||||
setStep(0)
|
||||
if (!orderId) {
|
||||
// if we don't have a previous valid order, get one
|
||||
const userOwnedTokens = await ocean.accounts.getTokenBalance(
|
||||
dataTokenAddress,
|
||||
account
|
||||
)
|
||||
if (parseFloat(userOwnedTokens) < 1) {
|
||||
setConsumeError('Not enough datatokens')
|
||||
} else {
|
||||
setStep(1)
|
||||
orderId = await ocean.assets.order(
|
||||
did as string,
|
||||
serviceType,
|
||||
accountId,
|
||||
undefined,
|
||||
marketFeeAddress
|
||||
)
|
||||
Logger.log('order created', orderId)
|
||||
setStep(2)
|
||||
}
|
||||
}
|
||||
setStep(3)
|
||||
if (orderId)
|
||||
await ocean.assets.download(
|
||||
did as string,
|
||||
orderId,
|
||||
dataTokenAddress,
|
||||
account,
|
||||
''
|
||||
)
|
||||
setStep(4)
|
||||
} catch (error) {
|
||||
setConsumeError(error.message)
|
||||
Logger.error(error)
|
||||
} finally {
|
||||
setConsumeStep(undefined)
|
||||
setConsumeStepText(undefined)
|
||||
setIsLoading(false)
|
||||
}
|
||||
}
|
||||
|
||||
return { consume, consumeStep, consumeStepText, consumeError, isLoading }
|
||||
}
|
||||
|
||||
export { useConsume, UseConsume }
|
||||
export default useConsume
|
299
src/hooks/usePricing.ts
Normal file
299
src/hooks/usePricing.ts
Normal file
@ -0,0 +1,299 @@
|
||||
import { DDO, Logger, BestPrice } from '@oceanprotocol/lib'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { TransactionReceipt } from 'web3-core'
|
||||
import { Decimal } from 'decimal.js'
|
||||
import { getFirstPoolPrice } from '../utils/dtUtils'
|
||||
import {
|
||||
getCreatePricingPoolFeedback,
|
||||
getCreatePricingExchangeFeedback,
|
||||
getBuyDTFeedback,
|
||||
getSellDTFeedback
|
||||
} from '../utils/feedback'
|
||||
import { sleep } from '../utils'
|
||||
|
||||
import { useOcean } from '../providers/Ocean'
|
||||
import { useWeb3 } from '../providers/Web3'
|
||||
|
||||
interface PriceOptions {
|
||||
price: number
|
||||
dtAmount: number
|
||||
oceanAmount: number
|
||||
type: 'fixed' | 'dynamic' | string
|
||||
weightOnDataToken: string
|
||||
swapFee: string
|
||||
}
|
||||
|
||||
interface UsePricing {
|
||||
dtSymbol?: string
|
||||
dtName?: string
|
||||
createPricing: (
|
||||
priceOptions: PriceOptions
|
||||
) => Promise<TransactionReceipt | string | void>
|
||||
sellDT: (dtAmount: number | string) => Promise<TransactionReceipt | void>
|
||||
mint: (tokensToMint: string) => Promise<TransactionReceipt | void>
|
||||
buyDT: (
|
||||
dtAmount: number | string,
|
||||
price: BestPrice
|
||||
) => Promise<TransactionReceipt | void>
|
||||
pricingStep?: number
|
||||
pricingStepText?: string
|
||||
pricingError?: string
|
||||
pricingIsLoading: boolean
|
||||
}
|
||||
|
||||
function usePricing(ddo: DDO): UsePricing {
|
||||
const { accountId } = useWeb3()
|
||||
const { ocean, config } = useOcean()
|
||||
const [pricingIsLoading, setPricingIsLoading] = useState(false)
|
||||
const [pricingStep, setPricingStep] = useState<number>()
|
||||
const [pricingStepText, setPricingStepText] = useState<string>()
|
||||
const [pricingError, setPricingError] = useState<string>()
|
||||
const [dtSymbol, setDtSymbol] = useState<string>()
|
||||
const [dtName, setDtName] = useState<string>()
|
||||
|
||||
const { dataToken, dataTokenInfo } = ddo
|
||||
|
||||
// Get Datatoken info, from DDO first, then from chain
|
||||
useEffect(() => {
|
||||
if (!dataToken) return
|
||||
|
||||
async function init() {
|
||||
const dtSymbol = dataTokenInfo
|
||||
? dataTokenInfo.symbol
|
||||
: await ocean?.datatokens.getSymbol(dataToken)
|
||||
setDtSymbol(dtSymbol)
|
||||
|
||||
const dtName = dataTokenInfo
|
||||
? dataTokenInfo.name
|
||||
: await ocean?.datatokens.getName(dataToken)
|
||||
setDtName(dtName)
|
||||
}
|
||||
init()
|
||||
}, [ocean, dataToken, dataTokenInfo])
|
||||
|
||||
// Helper for setting steps & feedback for all flows
|
||||
function setStep(index: number, type: 'pool' | 'exchange' | 'buy' | 'sell') {
|
||||
setPricingStep(index)
|
||||
if (!dtSymbol) return
|
||||
|
||||
let messages
|
||||
|
||||
switch (type) {
|
||||
case 'pool':
|
||||
messages = getCreatePricingPoolFeedback(dtSymbol)
|
||||
break
|
||||
case 'exchange':
|
||||
messages = getCreatePricingExchangeFeedback(dtSymbol)
|
||||
break
|
||||
case 'buy':
|
||||
messages = getBuyDTFeedback(dtSymbol)
|
||||
break
|
||||
case 'sell':
|
||||
messages = getSellDTFeedback(dtSymbol)
|
||||
break
|
||||
}
|
||||
|
||||
setPricingStepText(messages[index])
|
||||
}
|
||||
|
||||
async function mint(
|
||||
tokensToMint: string
|
||||
): Promise<TransactionReceipt | void> {
|
||||
Logger.log('mint function', dataToken, accountId)
|
||||
const balance = new Decimal(
|
||||
await ocean.datatokens.balance(dataToken, accountId)
|
||||
)
|
||||
const tokens = new Decimal(tokensToMint)
|
||||
if (tokens.greaterThan(balance)) {
|
||||
const mintAmount = tokens.minus(balance)
|
||||
const tx = await ocean.datatokens.mint(
|
||||
dataToken,
|
||||
accountId,
|
||||
mintAmount.toString()
|
||||
)
|
||||
return tx
|
||||
}
|
||||
}
|
||||
|
||||
async function buyDT(
|
||||
dtAmount: number | string,
|
||||
price: BestPrice
|
||||
): Promise<TransactionReceipt | void> {
|
||||
if (!ocean || !accountId) return
|
||||
|
||||
let tx
|
||||
|
||||
try {
|
||||
setPricingIsLoading(true)
|
||||
setPricingError(undefined)
|
||||
setStep(1, 'buy')
|
||||
|
||||
Logger.log('Price found for buying', price)
|
||||
switch (price?.type) {
|
||||
case 'pool': {
|
||||
const oceanAmmount = new Decimal(price.value).times(1.05).toString()
|
||||
const maxPrice = new Decimal(price.value).times(2).toString()
|
||||
setStep(2, 'buy')
|
||||
Logger.log('Buying token from pool', price, accountId, price)
|
||||
tx = await ocean.pool.buyDT(
|
||||
accountId,
|
||||
price.address,
|
||||
String(dtAmount),
|
||||
oceanAmmount,
|
||||
maxPrice
|
||||
)
|
||||
setStep(3, 'buy')
|
||||
Logger.log('DT buy response', tx)
|
||||
break
|
||||
}
|
||||
case 'exchange': {
|
||||
if (!config.oceanTokenAddress) {
|
||||
Logger.error(`'oceanTokenAddress' not set in config`)
|
||||
return
|
||||
}
|
||||
if (!config.fixedRateExchangeAddress) {
|
||||
Logger.error(`'fixedRateExchangeAddress' not set in config`)
|
||||
return
|
||||
}
|
||||
Logger.log('Buying token from exchange', price, accountId)
|
||||
await ocean.datatokens.approve(
|
||||
config.oceanTokenAddress,
|
||||
config.fixedRateExchangeAddress,
|
||||
`${price.value}`,
|
||||
accountId
|
||||
)
|
||||
setStep(2, 'buy')
|
||||
tx = await ocean.fixedRateExchange.buyDT(
|
||||
price.address,
|
||||
`${dtAmount}`,
|
||||
accountId
|
||||
)
|
||||
setStep(3, 'buy')
|
||||
Logger.log('DT exchange buy response', tx)
|
||||
break
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
setPricingError(error.message)
|
||||
Logger.error(error)
|
||||
} finally {
|
||||
setStep(0, 'buy')
|
||||
setPricingStepText(undefined)
|
||||
setPricingIsLoading(false)
|
||||
}
|
||||
|
||||
return tx
|
||||
}
|
||||
|
||||
async function sellDT(
|
||||
dtAmount: number | string
|
||||
): Promise<TransactionReceipt | void> {
|
||||
if (!ocean || !accountId) return
|
||||
|
||||
if (!config.oceanTokenAddress) {
|
||||
Logger.error(`'oceanTokenAddress' not set in config`)
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
setPricingIsLoading(true)
|
||||
setPricingError(undefined)
|
||||
setStep(1, 'sell')
|
||||
const pool = await getFirstPoolPrice(ocean, dataToken)
|
||||
if (!pool || pool.value === 0) return
|
||||
const price = new Decimal(pool.value).times(0.95).toString()
|
||||
setStep(2, 'sell')
|
||||
Logger.log('Selling token to pool', pool, accountId, price)
|
||||
const tx = await ocean.pool.sellDT(
|
||||
accountId,
|
||||
pool.address,
|
||||
`${dtAmount}`,
|
||||
price
|
||||
)
|
||||
setStep(3, 'sell')
|
||||
Logger.log('DT sell response', tx)
|
||||
return tx
|
||||
} catch (error) {
|
||||
setPricingError(error.message)
|
||||
Logger.error(error)
|
||||
} finally {
|
||||
setStep(0, 'sell')
|
||||
setPricingStepText(undefined)
|
||||
setPricingIsLoading(false)
|
||||
}
|
||||
}
|
||||
|
||||
async function createPricing(
|
||||
priceOptions: PriceOptions
|
||||
): Promise<TransactionReceipt | void> {
|
||||
if (!ocean || !accountId || !dtSymbol) return
|
||||
|
||||
const {
|
||||
type,
|
||||
oceanAmount,
|
||||
price,
|
||||
weightOnDataToken,
|
||||
swapFee
|
||||
} = priceOptions
|
||||
|
||||
let { dtAmount } = priceOptions
|
||||
const isPool = type === 'dynamic'
|
||||
|
||||
if (!isPool && !config.fixedRateExchangeAddress) {
|
||||
Logger.error(`'fixedRateExchangeAddress' not set in config.`)
|
||||
return
|
||||
}
|
||||
|
||||
setPricingIsLoading(true)
|
||||
setPricingError(undefined)
|
||||
|
||||
setStep(99, 'pool')
|
||||
|
||||
try {
|
||||
// if fixedPrice set dt to max amount
|
||||
if (!isPool) dtAmount = 1000
|
||||
await mint(`${dtAmount}`)
|
||||
|
||||
// dtAmount for fixed price is set to max
|
||||
const tx = isPool
|
||||
? await ocean.pool
|
||||
.create(
|
||||
accountId,
|
||||
dataToken,
|
||||
`${dtAmount}`,
|
||||
weightOnDataToken,
|
||||
`${oceanAmount}`,
|
||||
swapFee
|
||||
)
|
||||
.next((step: number) => setStep(step, 'pool'))
|
||||
: await ocean.fixedRateExchange
|
||||
.create(dataToken, `${price}`, accountId, `${dtAmount}`)
|
||||
.next((step: number) => setStep(step, 'exchange'))
|
||||
await sleep(20000)
|
||||
return tx
|
||||
} catch (error) {
|
||||
setPricingError(error.message)
|
||||
Logger.error(error)
|
||||
} finally {
|
||||
setPricingStep(0)
|
||||
setPricingStepText(undefined)
|
||||
setPricingIsLoading(false)
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
dtSymbol,
|
||||
dtName,
|
||||
createPricing,
|
||||
buyDT,
|
||||
sellDT,
|
||||
mint,
|
||||
pricingStep,
|
||||
pricingStepText,
|
||||
pricingIsLoading,
|
||||
pricingError
|
||||
}
|
||||
}
|
||||
|
||||
export { usePricing, UsePricing, PriceOptions }
|
||||
export default usePricing
|
171
src/hooks/usePublish.ts
Normal file
171
src/hooks/usePublish.ts
Normal file
@ -0,0 +1,171 @@
|
||||
import { DDO, Logger, Metadata } from '@oceanprotocol/lib'
|
||||
import {
|
||||
Service,
|
||||
ServiceComputePrivacy,
|
||||
ServiceType
|
||||
} from '@oceanprotocol/lib/dist/node/ddo/interfaces/Service'
|
||||
import { useState } from 'react'
|
||||
import { sleep } from '../utils'
|
||||
import { publishFeedback } from '../utils/feedback'
|
||||
import { useOcean } from '../providers/Ocean'
|
||||
|
||||
interface DataTokenOptions {
|
||||
cap?: string
|
||||
name?: string
|
||||
symbol?: string
|
||||
}
|
||||
|
||||
interface UsePublish {
|
||||
publish: (
|
||||
asset: Metadata,
|
||||
serviceType: ServiceType,
|
||||
dataTokenOptions?: DataTokenOptions,
|
||||
timeout?: number,
|
||||
providerUri?: string
|
||||
) => Promise<DDO | undefined | null>
|
||||
publishStep?: number
|
||||
publishStepText?: string
|
||||
publishError?: string
|
||||
isLoading: boolean
|
||||
}
|
||||
|
||||
function usePublish(): UsePublish {
|
||||
const { ocean, account } = useOcean()
|
||||
const [isLoading, setIsLoading] = useState(false)
|
||||
const [publishStep, setPublishStep] = useState<number | undefined>()
|
||||
const [publishStepText, setPublishStepText] = useState<string | undefined>()
|
||||
const [publishError, setPublishError] = useState<string | undefined>()
|
||||
|
||||
function setStep(index?: number) {
|
||||
setPublishStep(index)
|
||||
index && setPublishStepText(publishFeedback[index])
|
||||
}
|
||||
/**
|
||||
* Publish an asset. It also creates the datatoken, mints tokens and gives the market allowance
|
||||
* @param {Metadata} asset The metadata of the asset.
|
||||
* @param {PriceOptions} priceOptions : number of tokens to mint, datatoken weight , liquidity fee, type : fixed, dynamic
|
||||
* @param {ServiceType} serviceType Desired service type of the asset access or compute
|
||||
* @param {DataTokenOptions} dataTokenOptions custom name, symbol and cap for datatoken
|
||||
* @return {Promise<DDO>} Returns the newly published ddo
|
||||
*/
|
||||
async function publish(
|
||||
asset: Metadata,
|
||||
serviceType: ServiceType,
|
||||
dataTokenOptions?: DataTokenOptions,
|
||||
timeout?: number,
|
||||
providerUri?: string
|
||||
): Promise<DDO | undefined | null> {
|
||||
if (!ocean || !account) return null
|
||||
setIsLoading(true)
|
||||
setPublishError(undefined)
|
||||
setStep(0)
|
||||
|
||||
try {
|
||||
const publishedDate =
|
||||
new Date(Date.now()).toISOString().split('.')[0] + 'Z'
|
||||
const services: Service[] = []
|
||||
const price = '1'
|
||||
|
||||
switch (serviceType) {
|
||||
case 'access': {
|
||||
if (!timeout) timeout = 0
|
||||
const accessService = await ocean.assets.createAccessServiceAttributes(
|
||||
account,
|
||||
price,
|
||||
publishedDate,
|
||||
timeout,
|
||||
providerUri
|
||||
)
|
||||
Logger.log('access service created', accessService)
|
||||
services.push(accessService)
|
||||
break
|
||||
}
|
||||
case 'compute': {
|
||||
if (!timeout) timeout = 3600
|
||||
const cluster = ocean.compute.createClusterAttributes(
|
||||
'Kubernetes',
|
||||
'http://10.0.0.17/xxx'
|
||||
)
|
||||
const servers = [
|
||||
ocean.compute.createServerAttributes(
|
||||
'1',
|
||||
'xlsize',
|
||||
'50',
|
||||
'16',
|
||||
'0',
|
||||
'128gb',
|
||||
'160gb',
|
||||
timeout
|
||||
)
|
||||
]
|
||||
const containers = [
|
||||
ocean.compute.createContainerAttributes(
|
||||
'tensorflow/tensorflow',
|
||||
'latest',
|
||||
'sha256:cb57ecfa6ebbefd8ffc7f75c0f00e57a7fa739578a429b6f72a0df19315deadc'
|
||||
)
|
||||
]
|
||||
const provider = ocean.compute.createProviderAttributes(
|
||||
'Azure',
|
||||
'Compute service with 16gb ram for each node.',
|
||||
cluster,
|
||||
containers,
|
||||
servers
|
||||
)
|
||||
const origComputePrivacy: ServiceComputePrivacy = {
|
||||
allowRawAlgorithm: true,
|
||||
allowNetworkAccess: false,
|
||||
publisherTrustedAlgorithms: []
|
||||
}
|
||||
const computeService = ocean.compute.createComputeService(
|
||||
account,
|
||||
price,
|
||||
publishedDate,
|
||||
provider,
|
||||
origComputePrivacy,
|
||||
timeout,
|
||||
providerUri
|
||||
)
|
||||
services.push(computeService)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
Logger.log('services created', services)
|
||||
|
||||
const ddo = await ocean.assets
|
||||
.create(
|
||||
asset,
|
||||
account,
|
||||
services,
|
||||
undefined,
|
||||
dataTokenOptions?.cap,
|
||||
dataTokenOptions?.name,
|
||||
dataTokenOptions?.symbol,
|
||||
providerUri
|
||||
)
|
||||
.next(setStep)
|
||||
Logger.log('ddo created', ddo)
|
||||
await sleep(20000)
|
||||
setStep(7)
|
||||
return ddo
|
||||
} catch (error) {
|
||||
setPublishError(error.message)
|
||||
Logger.error(error)
|
||||
setStep()
|
||||
} finally {
|
||||
setIsLoading(false)
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
publish,
|
||||
publishStep,
|
||||
publishStepText,
|
||||
isLoading,
|
||||
publishError
|
||||
}
|
||||
}
|
||||
|
||||
export { usePublish, UsePublish, DataTokenOptions }
|
||||
export default usePublish
|
@ -14,6 +14,8 @@ const query = graphql`
|
||||
link
|
||||
}
|
||||
warning
|
||||
warningPolygon
|
||||
warningPolygonPublish
|
||||
appConfig {
|
||||
infuraProjectId
|
||||
network
|
||||
|
@ -1,6 +1,6 @@
|
||||
import TokenBalance from '../@types/TokenBalance'
|
||||
import { PoolBalance } from '../@types/TokenBalance'
|
||||
|
||||
export interface FormTradeData extends TokenBalance {
|
||||
export interface FormTradeData extends PoolBalance {
|
||||
// in reference to datatoken, buy = swap from ocean to dt ( buy dt) , sell = swap from dt to ocean (sell dt)
|
||||
type: 'buy' | 'sell'
|
||||
slippage: string
|
||||
|
@ -3,7 +3,7 @@ import PageSearch from '../components/templates/Search'
|
||||
import { PageProps } from 'gatsby'
|
||||
import Page from '../components/templates/Page'
|
||||
import queryString from 'query-string'
|
||||
import { accountTruncate } from '../utils/wallet'
|
||||
import { accountTruncate } from '../utils/web3'
|
||||
import ethereumAddress from 'ethereum-address'
|
||||
|
||||
export default function PageGatsbySearch(props: PageProps): ReactElement {
|
||||
|
@ -7,7 +7,7 @@ import {
|
||||
} from '@apollo/client'
|
||||
import { Logger } from '@oceanprotocol/lib'
|
||||
import { ConfigHelperConfig } from '@oceanprotocol/lib/dist/node/utils/ConfigHelper'
|
||||
import { useOcean } from '@oceanprotocol/react'
|
||||
import { useOcean } from './Ocean'
|
||||
import fetch from 'cross-fetch'
|
||||
import React, { useState, useEffect, ReactNode, ReactElement } from 'react'
|
||||
|
||||
|
@ -9,12 +9,14 @@ import React, {
|
||||
} from 'react'
|
||||
import { Logger, DDO, BestPrice, MetadataMain } from '@oceanprotocol/lib'
|
||||
import { PurgatoryData } from '@oceanprotocol/lib/dist/node/ddo/interfaces/PurgatoryData'
|
||||
import { getDataTokenPrice, useOcean } from '@oceanprotocol/react'
|
||||
import getAssetPurgatoryData from '../utils/purgatory'
|
||||
import { ConfigHelperConfig } from '@oceanprotocol/lib/dist/node/utils/ConfigHelper'
|
||||
import axios, { CancelToken } from 'axios'
|
||||
import { retrieveDDO } from '../utils/aquarius'
|
||||
import { MetadataMarket } from '../@types/MetaData'
|
||||
import { useOcean } from './Ocean'
|
||||
import { gql, useQuery } from '@apollo/client'
|
||||
import { PoolPrice } from '../@types/apollo/PoolPrice'
|
||||
import { FrePrice } from '../@types/apollo/FrePrice'
|
||||
|
||||
interface AssetProviderValue {
|
||||
isInPurgatory: boolean
|
||||
@ -29,9 +31,24 @@ interface AssetProviderValue {
|
||||
error?: string
|
||||
refreshInterval: number
|
||||
refreshDdo: (token?: CancelToken) => Promise<void>
|
||||
refreshPrice: () => Promise<void>
|
||||
}
|
||||
|
||||
const poolQuery = gql`
|
||||
query PoolPrice($datatoken: String) {
|
||||
pools(where: { datatokenAddress: $datatoken }) {
|
||||
spotPrice
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
const freQuery = gql`
|
||||
query FrePrice($datatoken: String) {
|
||||
fixedRateExchanges(orderBy: id, where: { datatoken: $datatoken }) {
|
||||
rate
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
const AssetContext = createContext({} as AssetProviderValue)
|
||||
|
||||
const refreshInterval = 10000 // 10 sec.
|
||||
@ -43,7 +60,7 @@ function AssetProvider({
|
||||
asset: string | DDO
|
||||
children: ReactNode
|
||||
}): ReactElement {
|
||||
const { ocean, status, config, networkId } = useOcean()
|
||||
const { config } = useOcean()
|
||||
const [isInPurgatory, setIsInPurgatory] = useState(false)
|
||||
const [purgatoryData, setPurgatoryData] = useState<PurgatoryData>()
|
||||
const [ddo, setDDO] = useState<DDO>()
|
||||
@ -54,27 +71,51 @@ function AssetProvider({
|
||||
const [owner, setOwner] = useState<string>()
|
||||
const [error, setError] = useState<string>()
|
||||
const [type, setType] = useState<MetadataMain['type']>()
|
||||
const [variables, setVariables] = useState({})
|
||||
|
||||
const refreshPrice = useCallback(async () => {
|
||||
if (
|
||||
!ddo ||
|
||||
status !== 1 ||
|
||||
networkId !== (config as ConfigHelperConfig).networkId
|
||||
)
|
||||
return
|
||||
const {
|
||||
refetch: refetchFre,
|
||||
startPolling: startPollingFre,
|
||||
data: frePrice
|
||||
} = useQuery<FrePrice>(freQuery, {
|
||||
variables,
|
||||
skip: true
|
||||
})
|
||||
const {
|
||||
refetch: refetchPool,
|
||||
startPolling: startPollingPool,
|
||||
data: poolPrice
|
||||
} = useQuery<PoolPrice>(poolQuery, {
|
||||
variables,
|
||||
skip: true
|
||||
})
|
||||
|
||||
const newPrice = await getDataTokenPrice(
|
||||
ocean,
|
||||
ddo.dataToken,
|
||||
ddo?.price?.type,
|
||||
ddo.price.address
|
||||
)
|
||||
setPrice(newPrice)
|
||||
Logger.log(`Refreshed asset price: ${newPrice?.value}`, newPrice)
|
||||
}, [ocean, config, ddo, networkId, status])
|
||||
useEffect(() => {
|
||||
if (!ddo || !variables) return
|
||||
if (ddo.price.type === 'exchange') {
|
||||
refetchFre(variables)
|
||||
startPollingFre(refreshInterval)
|
||||
} else {
|
||||
refetchPool(variables)
|
||||
startPollingPool(refreshInterval)
|
||||
}
|
||||
}, [ddo, variables])
|
||||
|
||||
useEffect(() => {
|
||||
if (!frePrice || frePrice.fixedRateExchanges.length === 0) return
|
||||
price.value = frePrice.fixedRateExchanges[0].rate
|
||||
setPrice(price)
|
||||
}, [frePrice])
|
||||
|
||||
useEffect(() => {
|
||||
if (!poolPrice || poolPrice.pools.length === 0) return
|
||||
price.value = poolPrice.pools[0].spotPrice
|
||||
price.value = 3222222
|
||||
setPrice(price)
|
||||
}, [poolPrice])
|
||||
|
||||
const fetchDdo = async (token?: CancelToken) => {
|
||||
Logger.log('Init asset, get ddo')
|
||||
Logger.log('[asset] Init asset, get DDO')
|
||||
const ddo = await retrieveDDO(
|
||||
asset as string,
|
||||
config.metadataCacheUri,
|
||||
@ -83,7 +124,7 @@ function AssetProvider({
|
||||
|
||||
if (!ddo) {
|
||||
setError(
|
||||
`The DDO for ${asset} was not found in MetadataCache. If you just published a new data set, wait some seconds and refresh this page.`
|
||||
`[asset] The DDO for ${asset} was not found in MetadataCache. If you just published a new data set, wait some seconds and refresh this page.`
|
||||
)
|
||||
} else {
|
||||
setError(undefined)
|
||||
@ -93,9 +134,10 @@ function AssetProvider({
|
||||
|
||||
const refreshDdo = async (token?: CancelToken) => {
|
||||
const ddo = await fetchDdo(token)
|
||||
Logger.debug('DDO', ddo)
|
||||
Logger.debug('[asset] Got DDO', ddo)
|
||||
setDDO(ddo)
|
||||
}
|
||||
|
||||
//
|
||||
// Get and set DDO based on passed DDO or DID
|
||||
//
|
||||
@ -104,12 +146,11 @@ function AssetProvider({
|
||||
|
||||
const source = axios.CancelToken.source()
|
||||
let isMounted = true
|
||||
Logger.log('Init asset, get ddo')
|
||||
|
||||
async function init() {
|
||||
const ddo = await fetchDdo(source.token)
|
||||
if (!isMounted) return
|
||||
Logger.debug('DDO', ddo)
|
||||
Logger.debug('[asset] Got DDO', ddo)
|
||||
setDDO(ddo)
|
||||
setDID(asset as string)
|
||||
}
|
||||
@ -120,57 +161,37 @@ function AssetProvider({
|
||||
}
|
||||
}, [asset, config?.metadataCacheUri])
|
||||
|
||||
useEffect(() => {
|
||||
// Re-fetch price periodically, triggering re-calculation of everything
|
||||
let isMounted = true
|
||||
|
||||
const interval = setInterval(() => {
|
||||
if (!isMounted) return
|
||||
refreshPrice()
|
||||
}, refreshInterval)
|
||||
|
||||
return () => {
|
||||
clearInterval(interval)
|
||||
isMounted = false
|
||||
}
|
||||
}, [ddo, networkId, refreshPrice])
|
||||
|
||||
const setPurgatory = useCallback(async (did: string): Promise<void> => {
|
||||
if (!did) return
|
||||
|
||||
try {
|
||||
const result = await getAssetPurgatoryData(did)
|
||||
|
||||
if (result?.did !== undefined) {
|
||||
setIsInPurgatory(true)
|
||||
setPurgatoryData(result)
|
||||
return
|
||||
}
|
||||
|
||||
setIsInPurgatory(false)
|
||||
const isInPurgatory = result?.did !== undefined
|
||||
setIsInPurgatory(isInPurgatory)
|
||||
isInPurgatory && setPurgatoryData(result)
|
||||
} catch (error) {
|
||||
Logger.error(error)
|
||||
}
|
||||
}, [])
|
||||
|
||||
const initMetadata = useCallback(
|
||||
async (ddo: DDO): Promise<void> => {
|
||||
const initMetadata = useCallback(async (ddo: DDO): Promise<void> => {
|
||||
if (!ddo) return
|
||||
|
||||
Logger.log('Init metadata')
|
||||
// Set price & metadata from DDO first
|
||||
setPrice(ddo.price)
|
||||
setVariables({ datatoken: ddo?.dataToken.toLowerCase() })
|
||||
|
||||
// Get metadata from DDO
|
||||
const { attributes } = ddo.findServiceByType('metadata')
|
||||
setMetadata((attributes as unknown) as MetadataMarket)
|
||||
setTitle(attributes?.main.name)
|
||||
setType(attributes.main.type)
|
||||
setOwner(ddo.publicKey[0].owner)
|
||||
setIsInPurgatory(ddo.isInPurgatory === 'true')
|
||||
Logger.log('[asset] Got Metadata from DDO', attributes)
|
||||
|
||||
setIsInPurgatory(ddo.isInPurgatory === 'true')
|
||||
await setPurgatory(ddo.id)
|
||||
await refreshPrice()
|
||||
},
|
||||
[refreshPrice, setPurgatory]
|
||||
)
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
if (!ddo) return
|
||||
@ -192,8 +213,7 @@ function AssetProvider({
|
||||
isInPurgatory,
|
||||
purgatoryData,
|
||||
refreshInterval,
|
||||
refreshDdo,
|
||||
refreshPrice
|
||||
refreshDdo
|
||||
} as AssetProviderValue
|
||||
}
|
||||
>
|
||||
|
163
src/providers/Ocean.tsx
Normal file
163
src/providers/Ocean.tsx
Normal file
@ -0,0 +1,163 @@
|
||||
import React, {
|
||||
useContext,
|
||||
useState,
|
||||
createContext,
|
||||
ReactElement,
|
||||
useCallback,
|
||||
ReactNode,
|
||||
useEffect
|
||||
} from 'react'
|
||||
import { Ocean, Logger, Account, Config } from '@oceanprotocol/lib'
|
||||
import { ConfigHelperConfig } from '@oceanprotocol/lib/dist/node/utils/ConfigHelper'
|
||||
import { useWeb3 } from './Web3'
|
||||
import {
|
||||
getDevelopmentConfig,
|
||||
getOceanConfig,
|
||||
getUserInfo
|
||||
} from '../utils/ocean'
|
||||
import { UserBalance } from '../@types/TokenBalance'
|
||||
|
||||
const refreshInterval = 20000 // 20 sec.
|
||||
|
||||
interface OceanProviderValue {
|
||||
ocean: Ocean
|
||||
config: ConfigHelperConfig | Config
|
||||
account: Account
|
||||
balance: UserBalance
|
||||
connect: (config?: Config) => Promise<void>
|
||||
refreshBalance: () => Promise<void>
|
||||
}
|
||||
|
||||
const OceanContext = createContext({} as OceanProviderValue)
|
||||
|
||||
function OceanProvider({
|
||||
initialConfig,
|
||||
children
|
||||
}: {
|
||||
initialConfig: Config | ConfigHelperConfig
|
||||
children: ReactNode
|
||||
}): ReactElement {
|
||||
const { web3, accountId, networkId } = useWeb3()
|
||||
const [ocean, setOcean] = useState<Ocean>()
|
||||
const [account, setAccount] = useState<Account>()
|
||||
const [balance, setBalance] = useState<UserBalance>({
|
||||
eth: undefined,
|
||||
ocean: undefined
|
||||
})
|
||||
const [config, setConfig] = useState<ConfigHelperConfig | Config>(
|
||||
initialConfig
|
||||
)
|
||||
|
||||
// -----------------------------------
|
||||
// Create Ocean instance
|
||||
// -----------------------------------
|
||||
const connect = useCallback(
|
||||
async (newConfig?: ConfigHelperConfig | Config) => {
|
||||
try {
|
||||
const usedConfig = newConfig || config
|
||||
Logger.log('[ocean] Connecting Ocean...', usedConfig)
|
||||
|
||||
usedConfig.web3Provider = web3 || initialConfig.web3Provider
|
||||
|
||||
if (newConfig) {
|
||||
setConfig(usedConfig)
|
||||
}
|
||||
|
||||
if (usedConfig.web3Provider) {
|
||||
const newOcean = await Ocean.getInstance(usedConfig)
|
||||
setOcean(newOcean)
|
||||
Logger.log('[ocean] Ocean instance created.', newOcean)
|
||||
}
|
||||
} catch (error) {
|
||||
Logger.error('[ocean] Error: ', error.message)
|
||||
}
|
||||
},
|
||||
[web3, config, initialConfig.web3Provider]
|
||||
)
|
||||
|
||||
async function refreshBalance() {
|
||||
if (!ocean || !account || !web3) return
|
||||
|
||||
const { balance } = await getUserInfo(ocean)
|
||||
setBalance(balance)
|
||||
}
|
||||
|
||||
// -----------------------------------
|
||||
// Initial connection
|
||||
// -----------------------------------
|
||||
useEffect(() => {
|
||||
async function init() {
|
||||
await connect()
|
||||
}
|
||||
init()
|
||||
|
||||
// init periodic refresh of wallet balance
|
||||
const balanceInterval = setInterval(() => refreshBalance(), refreshInterval)
|
||||
|
||||
return () => {
|
||||
clearInterval(balanceInterval)
|
||||
}
|
||||
}, [])
|
||||
|
||||
// -----------------------------------
|
||||
// Get user info, handle account change from web3
|
||||
// -----------------------------------
|
||||
useEffect(() => {
|
||||
if (!ocean || !accountId || !web3) return
|
||||
|
||||
async function getInfo() {
|
||||
const { account, balance } = await getUserInfo(ocean)
|
||||
setAccount(account)
|
||||
setBalance(balance)
|
||||
}
|
||||
getInfo()
|
||||
}, [ocean, accountId, web3])
|
||||
|
||||
// -----------------------------------
|
||||
// Handle network change from web3
|
||||
// -----------------------------------
|
||||
useEffect(() => {
|
||||
if (!networkId) return
|
||||
|
||||
async function reconnect() {
|
||||
const newConfig = {
|
||||
...getOceanConfig(networkId),
|
||||
|
||||
// add local dev values
|
||||
...(networkId === 8996 && {
|
||||
...getDevelopmentConfig()
|
||||
})
|
||||
}
|
||||
|
||||
try {
|
||||
await connect(newConfig)
|
||||
} catch (error) {
|
||||
Logger.error('[ocean] Error: ', error.message)
|
||||
}
|
||||
}
|
||||
reconnect()
|
||||
}, [networkId])
|
||||
|
||||
return (
|
||||
<OceanContext.Provider
|
||||
value={
|
||||
{
|
||||
ocean,
|
||||
account,
|
||||
balance,
|
||||
config,
|
||||
connect,
|
||||
refreshBalance
|
||||
} as OceanProviderValue
|
||||
}
|
||||
>
|
||||
{children}
|
||||
</OceanContext.Provider>
|
||||
)
|
||||
}
|
||||
|
||||
// Helper hook to access the provider values
|
||||
const useOcean = (): OceanProviderValue => useContext(OceanContext)
|
||||
|
||||
export { OceanProvider, useOcean, OceanProviderValue, OceanContext }
|
||||
export default OceanProvider
|
@ -39,7 +39,7 @@ export default function PricesProvider({
|
||||
|
||||
const onSuccess = async (data: { [tokenId]: { [key: string]: number } }) => {
|
||||
if (!data) return
|
||||
Logger.log(`Got new prices. ${JSON.stringify(data[tokenId])}`)
|
||||
Logger.log('[prices] Got new OCEAN spot prices.', data[tokenId])
|
||||
setPrices(data[tokenId])
|
||||
}
|
||||
|
||||
|
@ -8,8 +8,9 @@ import React, {
|
||||
} from 'react'
|
||||
import { Logger } from '@oceanprotocol/lib'
|
||||
import { LogLevel } from '@oceanprotocol/lib/dist/node/utils/Logger'
|
||||
import { useOcean } from '@oceanprotocol/react'
|
||||
import { useOcean } from './Ocean'
|
||||
import { ConfigHelperConfig } from '@oceanprotocol/lib/dist/node/utils/ConfigHelper'
|
||||
import { isBrowser } from '../utils'
|
||||
|
||||
interface UserPreferencesValue {
|
||||
debug: boolean
|
||||
@ -30,14 +31,13 @@ const localStorageKey = 'ocean-user-preferences'
|
||||
|
||||
function getLocalStorage(): UserPreferencesValue {
|
||||
const storageParsed =
|
||||
typeof window !== 'undefined' &&
|
||||
JSON.parse(window.localStorage.getItem(localStorageKey))
|
||||
isBrowser && JSON.parse(window.localStorage.getItem(localStorageKey))
|
||||
return storageParsed
|
||||
}
|
||||
|
||||
function setLocalStorage(values: Partial<UserPreferencesValue>) {
|
||||
return (
|
||||
typeof window !== 'undefined' &&
|
||||
isBrowser &&
|
||||
window.localStorage.setItem(localStorageKey, JSON.stringify(values))
|
||||
)
|
||||
}
|
||||
|
253
src/providers/Web3.tsx
Normal file
253
src/providers/Web3.tsx
Normal file
@ -0,0 +1,253 @@
|
||||
import React, {
|
||||
useContext,
|
||||
useState,
|
||||
useEffect,
|
||||
createContext,
|
||||
ReactElement,
|
||||
ReactNode,
|
||||
useCallback
|
||||
} from 'react'
|
||||
import Web3 from 'web3'
|
||||
import Web3Modal from 'web3modal'
|
||||
import { infuraProjectId as infuraId, portisId } from '../../app.config'
|
||||
import WalletConnectProvider from '@walletconnect/web3-provider'
|
||||
import { Logger } from '@oceanprotocol/lib'
|
||||
import { isBrowser } from '../utils'
|
||||
import {
|
||||
EthereumListsChain,
|
||||
getNetworkData,
|
||||
getNetworkDisplayName
|
||||
} from '../utils/web3'
|
||||
import { graphql, useStaticQuery } from 'gatsby'
|
||||
|
||||
interface Web3ProviderValue {
|
||||
web3: Web3
|
||||
web3Provider: any
|
||||
web3Modal: Web3Modal
|
||||
accountId: string
|
||||
networkId: number
|
||||
networkDisplayName: string
|
||||
networkData: EthereumListsChain
|
||||
isTestnet: boolean
|
||||
connect: () => Promise<void>
|
||||
logout: () => Promise<void>
|
||||
}
|
||||
|
||||
const web3ModalTheme = {
|
||||
background: 'var(--background-body)',
|
||||
main: 'var(--font-color-heading)',
|
||||
secondary: 'var(--brand-grey-light)',
|
||||
border: 'var(--border-color)',
|
||||
hover: 'var(--background-highlight)'
|
||||
}
|
||||
|
||||
// HEADS UP! We inline-require some packages so the Gatsby SSR build does not break.
|
||||
// We only need them client-side.
|
||||
const providerOptions = isBrowser
|
||||
? {
|
||||
walletconnect: {
|
||||
package: WalletConnectProvider,
|
||||
options: { infuraId }
|
||||
},
|
||||
portis: {
|
||||
package: require('@portis/web3'),
|
||||
options: {
|
||||
id: portisId
|
||||
}
|
||||
}
|
||||
// torus: {
|
||||
// package: require('@toruslabs/torus-embed')
|
||||
// // options: {
|
||||
// // networkParams: {
|
||||
// // host: oceanConfig.url, // optional
|
||||
// // chainId: 1337, // optional
|
||||
// // networkId: 1337 // optional
|
||||
// // }
|
||||
// // }
|
||||
// }
|
||||
}
|
||||
: {}
|
||||
|
||||
export const web3ModalOpts = {
|
||||
cacheProvider: true,
|
||||
providerOptions,
|
||||
theme: web3ModalTheme
|
||||
}
|
||||
|
||||
const networksQuery = graphql`
|
||||
query {
|
||||
allNetworksMetadataJson {
|
||||
edges {
|
||||
node {
|
||||
chain
|
||||
network
|
||||
networkId
|
||||
chainId
|
||||
nativeCurrency {
|
||||
name
|
||||
symbol
|
||||
decimals
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
const Web3Context = createContext({} as Web3ProviderValue)
|
||||
|
||||
function Web3Provider({ children }: { children: ReactNode }): ReactElement {
|
||||
const data = useStaticQuery(networksQuery)
|
||||
const networksList: { node: EthereumListsChain }[] =
|
||||
data.allNetworksMetadataJson.edges
|
||||
|
||||
const [web3, setWeb3] = useState<Web3>()
|
||||
const [web3Provider, setWeb3Provider] = useState<any>()
|
||||
const [web3Modal, setWeb3Modal] = useState<Web3Modal>()
|
||||
const [networkId, setNetworkId] = useState<number>()
|
||||
const [networkDisplayName, setNetworkDisplayName] = useState<string>()
|
||||
const [networkData, setNetworkData] = useState<EthereumListsChain>()
|
||||
const [isTestnet, setIsTestnet] = useState<boolean>()
|
||||
const [accountId, setAccountId] = useState<string>()
|
||||
|
||||
const connect = useCallback(async () => {
|
||||
if (!web3Modal) return
|
||||
|
||||
try {
|
||||
Logger.log('[web3] Connecting Web3...')
|
||||
|
||||
const provider = await web3Modal?.connect()
|
||||
setWeb3Provider(provider)
|
||||
|
||||
const web3 = new Web3(provider)
|
||||
setWeb3(web3)
|
||||
Logger.log('[web3] Web3 created.', web3)
|
||||
|
||||
const networkId = await web3.eth.net.getId()
|
||||
setNetworkId(networkId)
|
||||
Logger.log('[web3] network id ', networkId)
|
||||
|
||||
const accountId = (await web3.eth.getAccounts())[0]
|
||||
setAccountId(accountId)
|
||||
Logger.log('[web3] account id', accountId)
|
||||
} catch (error) {
|
||||
Logger.error('[web3] Error: ', error.message)
|
||||
}
|
||||
}, [web3Modal])
|
||||
|
||||
// -----------------------------------
|
||||
// Create initial Web3Modal instance
|
||||
// -----------------------------------
|
||||
useEffect(() => {
|
||||
if (web3Modal) return
|
||||
|
||||
async function init() {
|
||||
// note: needs artificial await here so the log message is reached and output
|
||||
const web3ModalInstance = await new Web3Modal(web3ModalOpts)
|
||||
setWeb3Modal(web3ModalInstance)
|
||||
Logger.log('[web3] Web3Modal instance created.', web3ModalInstance)
|
||||
}
|
||||
init()
|
||||
}, [connect, web3Modal])
|
||||
|
||||
// -----------------------------------
|
||||
// Reconnect automatically for returning users
|
||||
// -----------------------------------
|
||||
useEffect(() => {
|
||||
if (!web3Modal?.cachedProvider) return
|
||||
|
||||
async function connectCached() {
|
||||
Logger.log(
|
||||
'[web3] Connecting to cached provider: ',
|
||||
web3Modal.cachedProvider
|
||||
)
|
||||
await connect()
|
||||
}
|
||||
connectCached()
|
||||
}, [connect, web3Modal])
|
||||
|
||||
// -----------------------------------
|
||||
// Get and set network metadata
|
||||
// -----------------------------------
|
||||
useEffect(() => {
|
||||
if (!networkId) return
|
||||
|
||||
const networkData = getNetworkData(networksList, networkId)
|
||||
setNetworkData(networkData)
|
||||
Logger.log('[web3] Network metadata found.', networkData)
|
||||
|
||||
// Construct network display name
|
||||
const networkDisplayName = getNetworkDisplayName(networkData, networkId)
|
||||
setNetworkDisplayName(networkDisplayName)
|
||||
|
||||
// Figure out if we're on a chain's testnet, or not
|
||||
setIsTestnet(networkData.network !== 'mainnet')
|
||||
|
||||
Logger.log(`[web3] Network display name set to: ${networkDisplayName}`)
|
||||
}, [networkId, networksList])
|
||||
|
||||
// -----------------------------------
|
||||
// Logout helper
|
||||
// -----------------------------------
|
||||
async function logout() {
|
||||
web3Modal?.clearCachedProvider()
|
||||
}
|
||||
|
||||
// -----------------------------------
|
||||
// Handle change events
|
||||
// -----------------------------------
|
||||
async function handleNetworkChanged(networkId: string) {
|
||||
Logger.log('[web3] Network changed', networkId)
|
||||
// const networkId = Number(chainId.replace('0x', ''))
|
||||
setNetworkId(Number(networkId))
|
||||
}
|
||||
|
||||
async function handleAccountsChanged(accounts: string[]) {
|
||||
Logger.log('[web3] Account changed', accounts[0])
|
||||
setAccountId(accounts[0])
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (!web3Provider || !web3) return
|
||||
|
||||
//
|
||||
// HEADS UP! We should rather listen to `chainChanged` exposing the `chainId`
|
||||
// but for whatever reason the exposed `chainId` is wildly different from
|
||||
// what is shown on https://chainid.network, in turn breaking our network/config
|
||||
// mapping. The networkChanged is deprecated but works as expected for our case.
|
||||
// See: https://eips.ethereum.org/EIPS/eip-1193#chainchanged
|
||||
//
|
||||
web3Provider.on('networkChanged', handleNetworkChanged)
|
||||
web3Provider.on('accountsChanged', handleAccountsChanged)
|
||||
|
||||
return () => {
|
||||
web3Provider.removeListener('networkChanged')
|
||||
web3Provider.removeListener('accountsChanged')
|
||||
}
|
||||
}, [web3Provider, web3])
|
||||
|
||||
return (
|
||||
<Web3Context.Provider
|
||||
value={{
|
||||
web3,
|
||||
web3Provider,
|
||||
web3Modal,
|
||||
accountId,
|
||||
networkId,
|
||||
networkDisplayName,
|
||||
networkData,
|
||||
isTestnet,
|
||||
connect,
|
||||
logout
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</Web3Context.Provider>
|
||||
)
|
||||
}
|
||||
|
||||
// Helper hook to access the provider values
|
||||
const useWeb3 = (): Web3ProviderValue => useContext(Web3Context)
|
||||
|
||||
export { Web3Provider, useWeb3, Web3ProviderValue, Web3Context }
|
||||
export default Web3Provider
|
93
src/utils/dtUtils.ts
Normal file
93
src/utils/dtUtils.ts
Normal file
@ -0,0 +1,93 @@
|
||||
import { Ocean, BestPrice, Logger } from '@oceanprotocol/lib'
|
||||
|
||||
const priceError: BestPrice = {
|
||||
type: '',
|
||||
address: '',
|
||||
pools: [],
|
||||
datatoken: 0,
|
||||
value: 0,
|
||||
isConsumable: ''
|
||||
}
|
||||
|
||||
export async function getFirstExchangePrice(
|
||||
ocean: Ocean,
|
||||
dataTokenAddress: string
|
||||
): Promise<BestPrice> {
|
||||
try {
|
||||
const tokenExchanges = await ocean.fixedRateExchange.searchforDT(
|
||||
dataTokenAddress,
|
||||
'1'
|
||||
)
|
||||
if (tokenExchanges === undefined || tokenExchanges.length === 0) {
|
||||
return priceError
|
||||
}
|
||||
|
||||
const [tokenExchange] = tokenExchanges
|
||||
|
||||
return {
|
||||
type: 'exchange',
|
||||
pools: [],
|
||||
address: tokenExchange.exchangeID || '',
|
||||
value: Number(tokenExchange.fixedRate),
|
||||
ocean: 0,
|
||||
datatoken: Number(tokenExchange.supply),
|
||||
isConsumable: Number(tokenExchange.supply) > 0 ? 'true' : 'false'
|
||||
}
|
||||
} catch (err) {
|
||||
Logger.log(err)
|
||||
return priceError
|
||||
}
|
||||
}
|
||||
|
||||
export async function getFirstPoolPrice(
|
||||
ocean: Ocean,
|
||||
dataTokenAddress: string,
|
||||
poolAddress?: string
|
||||
): Promise<BestPrice> {
|
||||
let firstPoolAddress = poolAddress
|
||||
if (!poolAddress) {
|
||||
const tokenPools = await ocean.pool.searchPoolforDT(dataTokenAddress)
|
||||
|
||||
if (tokenPools === undefined || tokenPools.length === 0) {
|
||||
return priceError
|
||||
}
|
||||
;[firstPoolAddress] = tokenPools
|
||||
}
|
||||
|
||||
if (!firstPoolAddress) return priceError
|
||||
|
||||
const firstPoolPrice = await ocean.pool.calcInGivenOut(
|
||||
firstPoolAddress,
|
||||
ocean.pool.oceanAddress,
|
||||
dataTokenAddress,
|
||||
'1'
|
||||
)
|
||||
const usePrice = await ocean.pool.getOceanNeeded(firstPoolAddress, '1')
|
||||
const oceanReserve = await ocean.pool.getOceanReserve(firstPoolAddress)
|
||||
|
||||
const dtReserve = await ocean.pool.getDTReserve(firstPoolAddress)
|
||||
|
||||
return {
|
||||
type: 'pool',
|
||||
pools: [firstPoolAddress],
|
||||
address: firstPoolAddress,
|
||||
value: Number(firstPoolPrice),
|
||||
ocean: Number(oceanReserve),
|
||||
datatoken: Number(dtReserve),
|
||||
isConsumable: Number(usePrice) > 0 ? 'true' : 'false'
|
||||
}
|
||||
}
|
||||
|
||||
export async function getDataTokenPrice(
|
||||
ocean: Ocean,
|
||||
dataTokenAddress: string,
|
||||
type: string,
|
||||
poolAddress?: string
|
||||
): Promise<BestPrice> {
|
||||
const price =
|
||||
type === 'pool'
|
||||
? await getFirstPoolPrice(ocean, dataTokenAddress, poolAddress)
|
||||
: await getFirstExchangePrice(ocean, dataTokenAddress)
|
||||
|
||||
return price
|
||||
}
|
69
src/utils/feedback.ts
Normal file
69
src/utils/feedback.ts
Normal file
@ -0,0 +1,69 @@
|
||||
export const feedback: { [key in number]: string } = {
|
||||
99: 'Decrypting file URL...',
|
||||
0: '1/3 Looking for data token. Buying if none found...',
|
||||
1: '2/3 Transfering data token.',
|
||||
2: '3/3 Payment confirmed. Requesting access...'
|
||||
}
|
||||
|
||||
export const publishFeedback: { [key in number]: string } = {
|
||||
0: '1/5 Creating datatoken ...',
|
||||
2: '2/5 Encrypting files ...',
|
||||
4: '3/5 Storing ddo ...',
|
||||
6: '4/5 Minting tokens ...',
|
||||
8: '5/5 Asset published succesfully'
|
||||
}
|
||||
|
||||
// TODO: do something with this object,
|
||||
// consumeStep should probably return one of those strings
|
||||
// instead of just a number
|
||||
export const consumeFeedback: { [key in number]: string } = {
|
||||
...feedback,
|
||||
3: '3/3 Access granted. Consuming file...'
|
||||
}
|
||||
|
||||
// TODO: customize for compute
|
||||
export const computeFeedback: { [key in number]: string } = {
|
||||
0: '1/3 Ordering asset...',
|
||||
1: '2/3 Transfering data token.',
|
||||
2: '3/3 Access granted. Starting job...'
|
||||
}
|
||||
|
||||
export function getCreatePricingPoolFeedback(
|
||||
dtSymbol: string
|
||||
): { [key: number]: string } {
|
||||
return {
|
||||
99: `Minting ${dtSymbol} ...`,
|
||||
0: 'Creating pool ...',
|
||||
1: `Approving ${dtSymbol} ...`,
|
||||
2: 'Approving OCEAN ...',
|
||||
3: 'Setup pool ...',
|
||||
4: 'Pool created.'
|
||||
}
|
||||
}
|
||||
|
||||
export function getCreatePricingExchangeFeedback(
|
||||
dtSymbol: string
|
||||
): { [key: number]: string } {
|
||||
return {
|
||||
99: `Minting ${dtSymbol} ...`,
|
||||
0: 'Creating exchange ...',
|
||||
1: `Approving ${dtSymbol} ...`,
|
||||
2: 'Fixed exchange created.'
|
||||
}
|
||||
}
|
||||
|
||||
export function getBuyDTFeedback(dtSymbol: string): { [key: number]: string } {
|
||||
return {
|
||||
1: '1/3 Approving OCEAN ...',
|
||||
2: `2/3 Buying ${dtSymbol} ...`,
|
||||
3: `3/3 ${dtSymbol} bought.`
|
||||
}
|
||||
}
|
||||
|
||||
export function getSellDTFeedback(dtSymbol: string): { [key: number]: string } {
|
||||
return {
|
||||
1: '1/3 Approving OCEAN ...',
|
||||
2: `2/3 Selling ${dtSymbol} ...`,
|
||||
3: `3/3 ${dtSymbol} sold.`
|
||||
}
|
||||
}
|
@ -54,16 +54,8 @@ export async function fetchData(url: string): Promise<AxiosResponse['data']> {
|
||||
}
|
||||
}
|
||||
|
||||
export function isDid(did: string | undefined): boolean {
|
||||
const didMatch = (did as string).match(/^did:op:([a-f0-9]{64})$/i)
|
||||
return !!didMatch
|
||||
}
|
||||
|
||||
export function formatBytes(a: number, b: number): string {
|
||||
if (a === 0) return '0 Bytes'
|
||||
const c = 1024
|
||||
const d = b || 2
|
||||
const e = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']
|
||||
const f = Math.floor(Math.log(a) / Math.log(c))
|
||||
return parseFloat((a / Math.pow(c, f)).toFixed(d)) + ' ' + e[f]
|
||||
export function sleep(ms: number): Promise<void> {
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(resolve, ms)
|
||||
})
|
||||
}
|
||||
|
47
src/utils/ocean.ts
Normal file
47
src/utils/ocean.ts
Normal file
@ -0,0 +1,47 @@
|
||||
import { Account, Config, Logger, Ocean } from '@oceanprotocol/lib'
|
||||
import contractAddresses from '@oceanprotocol/contracts/artifacts/address.json'
|
||||
import {
|
||||
ConfigHelper,
|
||||
ConfigHelperConfig,
|
||||
ConfigHelperNetworkId,
|
||||
ConfigHelperNetworkName
|
||||
} from '@oceanprotocol/lib/dist/node/utils/ConfigHelper'
|
||||
import { UserBalance } from '../@types/TokenBalance'
|
||||
|
||||
export function getOceanConfig(
|
||||
network: ConfigHelperNetworkName | ConfigHelperNetworkId
|
||||
): Config {
|
||||
return new ConfigHelper().getConfig(
|
||||
network,
|
||||
process.env.GATSBY_INFURA_PROJECT_ID
|
||||
)
|
||||
}
|
||||
|
||||
export function getDevelopmentConfig(): Partial<ConfigHelperConfig> {
|
||||
return {
|
||||
factoryAddress: contractAddresses.development?.DTFactory,
|
||||
poolFactoryAddress: contractAddresses.development?.BFactory,
|
||||
fixedRateExchangeAddress: contractAddresses.development?.FixedRateExchange,
|
||||
metadataContractAddress: contractAddresses.development?.Metadata,
|
||||
oceanTokenAddress: contractAddresses.development?.Ocean,
|
||||
// There is no subgraph in barge so we hardcode the Rinkeby one for now
|
||||
subgraphUri: 'https://subgraph.rinkeby.oceanprotocol.com'
|
||||
}
|
||||
}
|
||||
|
||||
export async function getUserInfo(
|
||||
ocean: Ocean
|
||||
): Promise<{ account: Account; balance: UserBalance }> {
|
||||
if (!ocean) return { account: null, balance: { eth: '0', ocean: '0' } }
|
||||
|
||||
const account = (await ocean.accounts.list())[0]
|
||||
Logger.log('[ocean] Account: ', account)
|
||||
|
||||
const balance = {
|
||||
eth: await account.getEtherBalance(),
|
||||
ocean: await account.getOceanBalance()
|
||||
}
|
||||
Logger.log('[ocean] Balance: ', JSON.stringify(balance))
|
||||
|
||||
return { account, balance }
|
||||
}
|
15
src/utils/pricingFeedback.ts
Normal file
15
src/utils/pricingFeedback.ts
Normal file
@ -0,0 +1,15 @@
|
||||
export function getBuyDTFeedback(dtSymbol: string): { [key: number]: string } {
|
||||
return {
|
||||
1: '1/3 Approving OCEAN ...',
|
||||
2: `2/3 Buying ${dtSymbol} ...`,
|
||||
3: `3/3 ${dtSymbol} bought.`
|
||||
}
|
||||
}
|
||||
|
||||
export function getSellDTFeedback(dtSymbol: string): { [key: number]: string } {
|
||||
return {
|
||||
1: '1/3 Approving OCEAN ...',
|
||||
2: `2/3 Selling ${dtSymbol} ...`,
|
||||
3: `3/3 ${dtSymbol} sold.`
|
||||
}
|
||||
}
|
@ -1,11 +1,23 @@
|
||||
import { PurgatoryData } from '@oceanprotocol/lib'
|
||||
import axios from 'axios'
|
||||
import { PurgatoryData as PurgatoryDataAsset } from '@oceanprotocol/lib'
|
||||
import { fetchData } from '.'
|
||||
|
||||
const purgatoryUrl = 'https://market-purgatory.oceanprotocol.com/api/'
|
||||
|
||||
export interface PurgatoryDataAccount {
|
||||
address: string
|
||||
reason: string
|
||||
}
|
||||
|
||||
export default async function getAssetPurgatoryData(
|
||||
did: string
|
||||
): Promise<PurgatoryData> {
|
||||
const response = await axios(`${purgatoryUrl}asset?did=${did}`)
|
||||
const responseJson = await response.data[0]
|
||||
return { did: responseJson?.did, reason: responseJson?.reason }
|
||||
): Promise<PurgatoryDataAsset> {
|
||||
const data = await fetchData(`${purgatoryUrl}asset?did=${did}`)
|
||||
return { did: data[0]?.did, reason: data[0]?.reason }
|
||||
}
|
||||
|
||||
export async function getAccountPurgatoryData(
|
||||
address: string
|
||||
): Promise<PurgatoryDataAccount> {
|
||||
const data = await fetchData(`${purgatoryUrl}account?address=${address}`)
|
||||
return { address: data[0]?.address, reason: data[0]?.reason }
|
||||
}
|
||||
|
@ -1,87 +0,0 @@
|
||||
import { infuraProjectId as infuraId, portisId } from '../../app.config'
|
||||
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 = {
|
||||
background: 'var(--background-body)',
|
||||
main: 'var(--font-color-heading)',
|
||||
secondary: 'var(--brand-grey-light)',
|
||||
border: 'var(--border-color)',
|
||||
hover: 'var(--background-highlight)'
|
||||
}
|
||||
|
||||
// HEADS UP! We inline-require some packages so the Gatsby SSR build does not break.
|
||||
// We only need them client-side.
|
||||
const providerOptions =
|
||||
typeof window !== 'undefined'
|
||||
? {
|
||||
walletconnect: {
|
||||
package: WalletConnectProvider,
|
||||
options: { infuraId }
|
||||
},
|
||||
portis: {
|
||||
package: require('@portis/web3'),
|
||||
options: {
|
||||
id: portisId
|
||||
}
|
||||
}
|
||||
// torus: {
|
||||
// package: require('@toruslabs/torus-embed')
|
||||
// // options: {
|
||||
// // networkParams: {
|
||||
// // host: oceanConfig.url, // optional
|
||||
// // chainId: 1337, // optional
|
||||
// // networkId: 1337 // optional
|
||||
// // }
|
||||
// // }
|
||||
// }
|
||||
}
|
||||
: {}
|
||||
|
||||
export const web3ModalOpts = {
|
||||
cacheProvider: true,
|
||||
providerOptions,
|
||||
theme: web3ModalTheme
|
||||
}
|
||||
|
||||
export function accountTruncate(account: string): string {
|
||||
if (!account) return
|
||||
const middle = account.substring(6, 38)
|
||||
const truncated = account.replace(middle, '…')
|
||||
return truncated
|
||||
}
|
||||
|
||||
export function getNetworkDisplayName(
|
||||
data: EthereumListsChain,
|
||||
networkId: number
|
||||
): string {
|
||||
const displayName = data
|
||||
? `${data.chain} ${data.network === 'mainnet' ? '' : data.network}`
|
||||
: networkId === 8996
|
||||
? 'Development'
|
||||
: 'Unknown'
|
||||
|
||||
return displayName
|
||||
}
|
||||
|
||||
export function getNetworkData(
|
||||
data: { node: EthereumListsChain }[],
|
||||
networkId: number
|
||||
): EthereumListsChain {
|
||||
const networkData = data.filter(
|
||||
({ node }: { node: EthereumListsChain }) => node.networkId === networkId
|
||||
)[0]
|
||||
return networkData.node
|
||||
}
|
42
src/utils/web3.ts
Normal file
42
src/utils/web3.ts
Normal file
@ -0,0 +1,42 @@
|
||||
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
|
||||
}
|
||||
|
||||
export function accountTruncate(account: string): string {
|
||||
if (!account) return
|
||||
const middle = account.substring(6, 38)
|
||||
const truncated = account.replace(middle, '…')
|
||||
return truncated
|
||||
}
|
||||
|
||||
export function getNetworkDisplayName(
|
||||
data: EthereumListsChain,
|
||||
networkId: number
|
||||
): string {
|
||||
const displayName = data
|
||||
? `${data.chain} ${data.network === 'mainnet' ? '' : data.network}`
|
||||
: networkId === 8996
|
||||
? 'Development'
|
||||
: 'Unknown'
|
||||
|
||||
return displayName
|
||||
}
|
||||
|
||||
export function getNetworkData(
|
||||
data: { node: EthereumListsChain }[],
|
||||
networkId: number
|
||||
): EthereumListsChain {
|
||||
const networkData = data.filter(
|
||||
({ node }: { node: EthereumListsChain }) => node.networkId === networkId
|
||||
)[0]
|
||||
return networkData.node
|
||||
}
|
@ -19,30 +19,7 @@ const reactMock = {
|
||||
accountId: '0x0000000011111111aaaaaaaabbbbbbbb22222222',
|
||||
balance: '0.12'
|
||||
}
|
||||
},
|
||||
useConsume: () => {
|
||||
return {
|
||||
consume: () => null as any,
|
||||
consumeStepText: '',
|
||||
isLoading: false
|
||||
}
|
||||
},
|
||||
useCompute: () => {
|
||||
return {
|
||||
compute: () => null as any,
|
||||
isLoading: false,
|
||||
computeStepText: 0,
|
||||
computeError: ''
|
||||
}
|
||||
},
|
||||
useMetadata: () => {
|
||||
return {
|
||||
getCuration: () => {
|
||||
return Promise.resolve({ rating: 0, numVotes: 0 })
|
||||
}
|
||||
}
|
||||
},
|
||||
computeOptions: ['', '']
|
||||
}
|
||||
|
||||
export default reactMock
|
||||
|
@ -1,7 +1,6 @@
|
||||
import '@testing-library/jest-dom/extend-expect'
|
||||
import * as Gatsby from 'gatsby'
|
||||
import siteMetadata from './__fixtures__/siteMetadata.json'
|
||||
// import mockReact from './__mocks__/@oceanprotocol/react'
|
||||
|
||||
if (typeof window.IntersectionObserver === 'undefined') {
|
||||
import('intersection-observer')
|
||||
@ -20,7 +19,6 @@ export const globalMock = {
|
||||
beforeAll(() => {
|
||||
jest.mock('web3')
|
||||
jest.mock('@oceanprotocol/lib')
|
||||
jest.mock('@oceanprotocol/react')
|
||||
|
||||
// useOcean.mockImplementation(() => mockReact.useOcean())
|
||||
useStaticQuery.mockImplementation(() => globalMock)
|
||||
|
@ -1,12 +1,4 @@
|
||||
import axios, { AxiosResponse } from 'axios'
|
||||
|
||||
import {
|
||||
toStringNoMS,
|
||||
updateQueryStringParameter,
|
||||
isDid
|
||||
} from '../../../src/utils'
|
||||
|
||||
jest.mock('axios')
|
||||
import { toStringNoMS, updateQueryStringParameter } from '../../../src/utils'
|
||||
|
||||
describe('updateQueryStringParameter()', () => {
|
||||
it('transform a URI', () => {
|
||||
@ -26,17 +18,3 @@ describe('toStringNoMS()', () => {
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('isDid()', () => {
|
||||
it('checks correct DID', () => {
|
||||
expect(
|
||||
isDid(
|
||||
'did:op:bb6b9e960b2e40e3840ca5eafc8eb97af431b4d190b54e2f9926e1f792cdc54f'
|
||||
)
|
||||
).toBe(true)
|
||||
})
|
||||
|
||||
it('errors when no DID', () => {
|
||||
expect(isDid('hello')).toBe(false)
|
||||
})
|
||||
})
|
||||
|
Loading…
Reference in New Issue
Block a user