mirror of
https://github.com/oceanprotocol/market.git
synced 2024-12-02 05:57:29 +01:00
Handle price fetching better (#265)
* fix price refresh, add AssetProvider Signed-off-by: mihaisc <mihai.scarlat@smartcontrol.ro> * price comment Signed-off-by: mihaisc <mihai.scarlat@smartcontrol.ro> * fix trade Signed-off-by: mihaisc <mihai.scarlat@smartcontrol.ro> * fix trade Signed-off-by: mihaisc <mihai.scarlat@smartcontrol.ro> * fix pool liquidity Signed-off-by: mihaisc <mihai.scarlat@smartcontrol.ro> * fix AssetProvider Signed-off-by: mihaisc <mihai.scarlat@smartcontrol.ro> * fix Signed-off-by: mihaisc <mihai.scarlat@smartcontrol.ro> * fix import Signed-off-by: mihaisc <mihai.scarlat@smartcontrol.ro> * remove console.log Signed-off-by: mihaisc <mihai.scarlat@smartcontrol.ro> * pool refresh fix * simplify, logging * handle errors * cleanup Co-authored-by: Matthias Kretschmann <m@kretschmann.io>
This commit is contained in:
parent
7325e093ad
commit
b5a11d6d0f
@ -3,7 +3,7 @@ module.exports = {
|
|||||||
// on start. App will automatically switch network configs when user switches
|
// on start. App will automatically switch network configs when user switches
|
||||||
// networks in their wallet.
|
// networks in their wallet.
|
||||||
// Ocean Protocol contracts are deployed for: 'mainnet', 'rinkeby', 'development'
|
// Ocean Protocol contracts are deployed for: 'mainnet', 'rinkeby', 'development'
|
||||||
network: process.env.GATSBY_NETWORK || 'rinkeby',
|
network: process.env.GATSBY_NETWORK || 'mainnet',
|
||||||
infuraProjectId: process.env.GATSBY_INFURA_PROJECT_ID || 'xxx',
|
infuraProjectId: process.env.GATSBY_INFURA_PROJECT_ID || 'xxx',
|
||||||
// The ETH address the marketplace fee will be sent to.
|
// The ETH address the marketplace fee will be sent to.
|
||||||
marketFeeAddress:
|
marketFeeAddress:
|
||||||
|
20
package-lock.json
generated
20
package-lock.json
generated
@ -3572,11 +3572,11 @@
|
|||||||
"integrity": "sha512-MMyy81FvnRGwl2cQ4+cucq/YWjUTGzStHyAUVM6P2pFA8zMc3jouuWN2WSAjmvhxeKZU7jvJRwZCoi+miEYKjw=="
|
"integrity": "sha512-MMyy81FvnRGwl2cQ4+cucq/YWjUTGzStHyAUVM6P2pFA8zMc3jouuWN2WSAjmvhxeKZU7jvJRwZCoi+miEYKjw=="
|
||||||
},
|
},
|
||||||
"@oceanprotocol/react": {
|
"@oceanprotocol/react": {
|
||||||
"version": "0.3.19",
|
"version": "0.3.20",
|
||||||
"resolved": "https://registry.npmjs.org/@oceanprotocol/react/-/react-0.3.19.tgz",
|
"resolved": "https://registry.npmjs.org/@oceanprotocol/react/-/react-0.3.20.tgz",
|
||||||
"integrity": "sha512-9esHRLJlfCtGRA8PRuohiYoCitos2DgZjGxY+og5k4udwiqSHKzHV1fJexu9rGknKQls7o+QIt4I/79jpnqETw==",
|
"integrity": "sha512-98mRBP0Ij20v6wYsbb/B7GM1H3HclUyrlWJKybRB/K+Hbk3AJW0+RQxJ+C4WkrkR4C5KquNjGccvgr5sZyQFoQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@oceanprotocol/lib": "^0.9.12",
|
"@oceanprotocol/lib": "^0.9.14",
|
||||||
"axios": "^0.21.0",
|
"axios": "^0.21.0",
|
||||||
"decimal.js": "^10.2.1",
|
"decimal.js": "^10.2.1",
|
||||||
"web3": "^1.3.0",
|
"web3": "^1.3.0",
|
||||||
@ -33970,9 +33970,9 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/node": {
|
"@types/node": {
|
||||||
"version": "12.19.3",
|
"version": "12.19.5",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-12.19.3.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-12.19.5.tgz",
|
||||||
"integrity": "sha512-8Jduo8wvvwDzEVJCOvS/G6sgilOLvvhn1eMmK3TW8/T217O7u1jdrK6ImKLv80tVryaPSVeKu6sjDEiFjd4/eg=="
|
"integrity": "sha512-Wgdl27uw/jUYUFyajUGKSjDNGxmJrZi9sjeG6UJImgUtKbJoO9aldx+1XODN1EpNDX9DirvbvHHmTsNlb8GwMA=="
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -34170,9 +34170,9 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/node": {
|
"@types/node": {
|
||||||
"version": "12.19.3",
|
"version": "12.19.5",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-12.19.3.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-12.19.5.tgz",
|
||||||
"integrity": "sha512-8Jduo8wvvwDzEVJCOvS/G6sgilOLvvhn1eMmK3TW8/T217O7u1jdrK6ImKLv80tVryaPSVeKu6sjDEiFjd4/eg=="
|
"integrity": "sha512-Wgdl27uw/jUYUFyajUGKSjDNGxmJrZi9sjeG6UJImgUtKbJoO9aldx+1XODN1EpNDX9DirvbvHHmTsNlb8GwMA=="
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -26,7 +26,7 @@
|
|||||||
"@oceanprotocol/art": "^3.0.0",
|
"@oceanprotocol/art": "^3.0.0",
|
||||||
"@oceanprotocol/lib": "^0.9.17",
|
"@oceanprotocol/lib": "^0.9.17",
|
||||||
"@oceanprotocol/list-datapartners": "^1.0.3",
|
"@oceanprotocol/list-datapartners": "^1.0.3",
|
||||||
"@oceanprotocol/react": "^0.3.19",
|
"@oceanprotocol/react": "^0.3.20",
|
||||||
"@oceanprotocol/typographies": "^0.1.0",
|
"@oceanprotocol/typographies": "^0.1.0",
|
||||||
"@sindresorhus/slugify": "^1.0.0",
|
"@sindresorhus/slugify": "^1.0.0",
|
||||||
"@tippyjs/react": "^4.2.0",
|
"@tippyjs/react": "^4.2.0",
|
||||||
|
@ -17,6 +17,7 @@ export default function Price({
|
|||||||
small?: boolean
|
small?: boolean
|
||||||
conversion?: boolean
|
conversion?: boolean
|
||||||
}): ReactElement {
|
}): ReactElement {
|
||||||
|
// price is not fetched from the chain anymore , will update one AssetProvider is implemented
|
||||||
const { price } = useMetadata(ddo)
|
const { price } = useMetadata(ddo)
|
||||||
|
|
||||||
return price?.value ? (
|
return price?.value ? (
|
||||||
|
@ -7,14 +7,10 @@ import Price from '../../atoms/Price'
|
|||||||
import Web3Feedback from '../../molecules/Wallet/Feedback'
|
import Web3Feedback from '../../molecules/Wallet/Feedback'
|
||||||
import styles from './Consume.module.css'
|
import styles from './Consume.module.css'
|
||||||
import Loader from '../../atoms/Loader'
|
import Loader from '../../atoms/Loader'
|
||||||
import {
|
import { useOcean, useConsume, usePricing } from '@oceanprotocol/react'
|
||||||
useOcean,
|
|
||||||
useConsume,
|
|
||||||
usePricing,
|
|
||||||
useAsset
|
|
||||||
} from '@oceanprotocol/react'
|
|
||||||
import { useSiteMetadata } from '../../../hooks/useSiteMetadata'
|
import { useSiteMetadata } from '../../../hooks/useSiteMetadata'
|
||||||
import checkPreviousOrder from '../../../utils/checkPreviousOrder'
|
import checkPreviousOrder from '../../../utils/checkPreviousOrder'
|
||||||
|
import { useAsset } from '../../../providers/Asset'
|
||||||
|
|
||||||
export default function Consume({
|
export default function Consume({
|
||||||
ddo,
|
ddo,
|
||||||
|
@ -1,11 +1,6 @@
|
|||||||
import React, { ReactElement, useEffect, useState } from 'react'
|
import React, { ReactElement, useEffect, useState } from 'react'
|
||||||
import {
|
import { useOcean, useMetadata, usePricing } from '@oceanprotocol/react'
|
||||||
useOcean,
|
import { BestPrice, DDO, Logger } from '@oceanprotocol/lib'
|
||||||
useMetadata,
|
|
||||||
usePricing,
|
|
||||||
useAsset
|
|
||||||
} from '@oceanprotocol/react'
|
|
||||||
import { DDO, Logger } from '@oceanprotocol/lib'
|
|
||||||
import styles from './index.module.css'
|
import styles from './index.module.css'
|
||||||
import stylesActions from './Actions.module.css'
|
import stylesActions from './Actions.module.css'
|
||||||
import PriceUnit from '../../../atoms/Price/PriceUnit'
|
import PriceUnit from '../../../atoms/Price/PriceUnit'
|
||||||
@ -21,6 +16,7 @@ import TokenBalance from '../../../../@types/TokenBalance'
|
|||||||
import Transactions from './Transactions'
|
import Transactions from './Transactions'
|
||||||
import Graph, { ChartDataLiqudity } from './Graph'
|
import Graph, { ChartDataLiqudity } from './Graph'
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
|
import { useAsset } from '../../../../providers/Asset'
|
||||||
|
|
||||||
const contentQuery = graphql`
|
const contentQuery = graphql`
|
||||||
query PoolQuery {
|
query PoolQuery {
|
||||||
@ -41,16 +37,15 @@ const contentQuery = graphql`
|
|||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
const refreshInterval = 15000 // 15 sec.
|
|
||||||
|
|
||||||
export default function Pool({ ddo }: { ddo: DDO }): ReactElement {
|
export default function Pool({ ddo }: { ddo: DDO }): ReactElement {
|
||||||
const data = useStaticQuery(contentQuery)
|
const data = useStaticQuery(contentQuery)
|
||||||
const content = data.content.edges[0].node.childContentJson.pool
|
const content = data.content.edges[0].node.childContentJson.pool
|
||||||
|
|
||||||
const { ocean, accountId, networkId, config } = useOcean()
|
const { ocean, accountId, networkId, config } = useOcean()
|
||||||
const { price, refreshPrice, owner } = useMetadata(ddo)
|
const { owner } = useMetadata(ddo)
|
||||||
|
|
||||||
const { dtSymbol } = usePricing(ddo)
|
const { dtSymbol } = usePricing(ddo)
|
||||||
const { isInPurgatory } = useAsset()
|
const { isInPurgatory, price, refreshInterval, refreshPrice } = useAsset()
|
||||||
|
|
||||||
const [poolTokens, setPoolTokens] = useState<string>()
|
const [poolTokens, setPoolTokens] = useState<string>()
|
||||||
const [totalPoolTokens, setTotalPoolTokens] = useState<string>()
|
const [totalPoolTokens, setTotalPoolTokens] = useState<string>()
|
||||||
@ -80,12 +75,6 @@ export default function Pool({ ddo }: { ddo: DDO }): ReactElement {
|
|||||||
// the purpose of the value is just to trigger the effect
|
// the purpose of the value is just to trigger the effect
|
||||||
const [refreshPool, setRefreshPool] = useState(false)
|
const [refreshPool, setRefreshPool] = useState(false)
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
// Re-fetch price periodically, triggering re-calculation of everything
|
|
||||||
const interval = setInterval(() => refreshPrice(), refreshInterval)
|
|
||||||
return () => clearInterval(interval)
|
|
||||||
}, [ddo, refreshPrice])
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setIsRemoveDisabled(isInPurgatory && owner === accountId)
|
setIsRemoveDisabled(isInPurgatory && owner === accountId)
|
||||||
}, [isInPurgatory, owner, accountId])
|
}, [isInPurgatory, owner, accountId])
|
||||||
@ -108,7 +97,6 @@ export default function Pool({ ddo }: { ddo: DDO }): ReactElement {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!ocean || !accountId || !price) return
|
if (!ocean || !accountId || !price) return
|
||||||
|
|
||||||
async function init() {
|
async function init() {
|
||||||
try {
|
try {
|
||||||
//
|
//
|
||||||
@ -195,10 +183,6 @@ export default function Pool({ ddo }: { ddo: DDO }): ReactElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
init()
|
init()
|
||||||
|
|
||||||
// Re-fetch price periodically, triggering re-calculation of everything
|
|
||||||
const interval = setInterval(() => refreshPrice(), refreshInterval)
|
|
||||||
return () => clearInterval(interval)
|
|
||||||
}, [ocean, accountId, price, ddo, refreshPool, owner])
|
}, [ocean, accountId, price, ddo, refreshPool, owner])
|
||||||
|
|
||||||
// Get graph history data
|
// Get graph history data
|
||||||
@ -248,7 +232,10 @@ export default function Pool({ ddo }: { ddo: DDO }): ReactElement {
|
|||||||
refreshInfo={refreshInfo}
|
refreshInfo={refreshInfo}
|
||||||
poolAddress={price.address}
|
poolAddress={price.address}
|
||||||
totalPoolTokens={totalPoolTokens}
|
totalPoolTokens={totalPoolTokens}
|
||||||
totalBalance={{ ocean: price.ocean, datatoken: price.datatoken }}
|
totalBalance={{
|
||||||
|
ocean: price.ocean,
|
||||||
|
datatoken: price.datatoken
|
||||||
|
}}
|
||||||
swapFee={swapFee}
|
swapFee={swapFee}
|
||||||
dtSymbol={dtSymbol}
|
dtSymbol={dtSymbol}
|
||||||
dtAddress={ddo.dataToken}
|
dtAddress={ddo.dataToken}
|
||||||
|
@ -1,15 +1,14 @@
|
|||||||
import React, { ReactElement, useEffect, useState } from 'react'
|
import React, { ReactElement, useEffect, useState } from 'react'
|
||||||
import { useOcean, useMetadata } from '@oceanprotocol/react'
|
import { useOcean } from '@oceanprotocol/react'
|
||||||
import { DDO } from '@oceanprotocol/lib'
|
import { DDO } from '@oceanprotocol/lib'
|
||||||
import FormTrade from './FormTrade'
|
import FormTrade from './FormTrade'
|
||||||
import TokenBalance from '../../../../@types/TokenBalance'
|
import TokenBalance from '../../../../@types/TokenBalance'
|
||||||
|
import { useAsset } from '../../../../providers/Asset'
|
||||||
const refreshInterval = 10000 // 10 sec, if the interval is bellow 3-5 seconds the price will be 0 all the time
|
|
||||||
|
|
||||||
export default function Trade({ ddo }: { ddo: DDO }): ReactElement {
|
export default function Trade({ ddo }: { ddo: DDO }): ReactElement {
|
||||||
const { ocean, balance, accountId, networkId, refreshBalance } = useOcean()
|
const { ocean, balance, accountId } = useOcean()
|
||||||
const [tokenBalance, setTokenBalance] = useState<TokenBalance>()
|
const [tokenBalance, setTokenBalance] = useState<TokenBalance>()
|
||||||
const { price, refreshPrice } = useMetadata(ddo)
|
const { price } = useAsset()
|
||||||
const [maxDt, setMaxDt] = useState(0)
|
const [maxDt, setMaxDt] = useState(0)
|
||||||
const [maxOcean, setMaxOcean] = useState(0)
|
const [maxOcean, setMaxOcean] = useState(0)
|
||||||
|
|
||||||
@ -27,18 +26,6 @@ export default function Trade({ ddo }: { ddo: DDO }): ReactElement {
|
|||||||
getTokenBalance()
|
getTokenBalance()
|
||||||
}, [balance.ocean, ocean, accountId, ddo.dataToken])
|
}, [balance.ocean, ocean, accountId, ddo.dataToken])
|
||||||
|
|
||||||
// Re-fetch price & balance periodically, triggering re-calculation of everything
|
|
||||||
useEffect(() => {
|
|
||||||
if (!ocean || !networkId || !accountId) return
|
|
||||||
|
|
||||||
const interval = setInterval(async () => {
|
|
||||||
refreshPrice()
|
|
||||||
refreshBalance()
|
|
||||||
}, refreshInterval)
|
|
||||||
|
|
||||||
return () => clearInterval(interval)
|
|
||||||
}, [ocean, ddo, networkId, accountId, refreshPrice, refreshBalance])
|
|
||||||
|
|
||||||
// Get maximum amount for either OCEAN or datatoken
|
// Get maximum amount for either OCEAN or datatoken
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!ocean || !price || price.value === 0) return
|
if (!ocean || !price || price.value === 0) return
|
||||||
|
@ -4,14 +4,15 @@ import Compute from './Compute'
|
|||||||
import Consume from './Consume'
|
import Consume from './Consume'
|
||||||
import { DDO, Logger } from '@oceanprotocol/lib'
|
import { DDO, Logger } from '@oceanprotocol/lib'
|
||||||
import Tabs from '../../atoms/Tabs'
|
import Tabs from '../../atoms/Tabs'
|
||||||
import { useOcean, useMetadata } from '@oceanprotocol/react'
|
import { useOcean } from '@oceanprotocol/react'
|
||||||
import compareAsBN from '../../../utils/compareAsBN'
|
import compareAsBN from '../../../utils/compareAsBN'
|
||||||
import Pool from './Pool'
|
import Pool from './Pool'
|
||||||
import Trade from './Trade'
|
import Trade from './Trade'
|
||||||
|
import { useAsset } from '../../../providers/Asset'
|
||||||
|
|
||||||
export default function AssetActions({ ddo }: { ddo: DDO }): ReactElement {
|
export default function AssetActions({ ddo }: { ddo: DDO }): ReactElement {
|
||||||
const { ocean, balance, accountId } = useOcean()
|
const { ocean, balance, accountId } = useOcean()
|
||||||
const { price } = useMetadata(ddo)
|
const { price } = useAsset()
|
||||||
const [isBalanceSufficient, setIsBalanceSufficient] = useState<boolean>()
|
const [isBalanceSufficient, setIsBalanceSufficient] = useState<boolean>()
|
||||||
const [dtBalance, setDtBalance] = useState<string>()
|
const [dtBalance, setDtBalance] = useState<string>()
|
||||||
|
|
||||||
@ -21,7 +22,6 @@ export default function AssetActions({ ddo }: { ddo: DDO }): ReactElement {
|
|||||||
// Get and set user DT balance
|
// Get and set user DT balance
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!ocean || !accountId) return
|
if (!ocean || !accountId) return
|
||||||
|
|
||||||
async function init() {
|
async function init() {
|
||||||
try {
|
try {
|
||||||
const dtBalance = await ocean.datatokens.balance(
|
const dtBalance = await ocean.datatokens.balance(
|
||||||
|
@ -3,61 +3,32 @@ import { Router } from '@reach/router'
|
|||||||
import AssetContent from '../organisms/AssetContent'
|
import AssetContent from '../organisms/AssetContent'
|
||||||
import Page from './Page'
|
import Page from './Page'
|
||||||
import { MetadataMarket } from '../../@types/MetaData'
|
import { MetadataMarket } from '../../@types/MetaData'
|
||||||
import { MetadataCache, Logger, DDO } from '@oceanprotocol/lib'
|
|
||||||
import Alert from '../atoms/Alert'
|
import Alert from '../atoms/Alert'
|
||||||
import Loader from '../atoms/Loader'
|
import Loader from '../atoms/Loader'
|
||||||
import { useAsset, useOcean } from '@oceanprotocol/react'
|
import { useAsset } from '../../providers/Asset'
|
||||||
|
|
||||||
export default function PageTemplateAssetDetails({
|
export default function PageTemplateAssetDetails({
|
||||||
did,
|
|
||||||
uri
|
uri
|
||||||
}: {
|
}: {
|
||||||
did: string
|
|
||||||
uri: string
|
uri: string
|
||||||
}): ReactElement {
|
}): ReactElement {
|
||||||
const { config } = useOcean()
|
|
||||||
const { isInPurgatory, purgatoryData } = useAsset()
|
const { isInPurgatory, purgatoryData } = useAsset()
|
||||||
const [metadata, setMetadata] = useState<MetadataMarket>()
|
const [metadata, setMetadata] = useState<MetadataMarket>()
|
||||||
const [title, setTitle] = useState<string>()
|
const [title, setTitle] = useState<string>()
|
||||||
const [error, setError] = useState<string>()
|
const { ddo, error } = useAsset()
|
||||||
const [ddo, setDdo] = useState<DDO>()
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!config?.metadataCacheUri) return
|
if (!ddo || error) {
|
||||||
|
|
||||||
async function init() {
|
|
||||||
if (ddo) return
|
|
||||||
|
|
||||||
try {
|
|
||||||
const metadataCache = new MetadataCache(config.metadataCacheUri, Logger)
|
|
||||||
const ddo = await metadataCache.retrieveDDO(did)
|
|
||||||
|
|
||||||
if (!ddo) {
|
|
||||||
setTitle('Could not retrieve asset')
|
setTitle('Could not retrieve asset')
|
||||||
setError(
|
|
||||||
`The DDO for ${did} was not found in MetadataCache. If you just published a new data set, wait some seconds and refresh this page.`
|
|
||||||
)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
setDdo(ddo)
|
|
||||||
|
|
||||||
const { attributes } = ddo.findServiceByType('metadata')
|
const { attributes } = ddo.findServiceByType('metadata')
|
||||||
setTitle(attributes.main.name)
|
setTitle(attributes.main.name)
|
||||||
setMetadata((attributes as unknown) as MetadataMarket)
|
setMetadata((attributes as unknown) as MetadataMarket)
|
||||||
} catch (error) {
|
}, [ddo, error])
|
||||||
setTitle('Error retrieving asset')
|
|
||||||
setError(error.message)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
init()
|
|
||||||
|
|
||||||
// Periodically try to get DDO when not present yet
|
return ddo && metadata ? (
|
||||||
const timer = !ddo && setInterval(() => init(), 5000)
|
|
||||||
return () => clearInterval(timer)
|
|
||||||
}, [ddo, did, config.metadataCacheUri])
|
|
||||||
|
|
||||||
return did && metadata ? (
|
|
||||||
<>
|
<>
|
||||||
{isInPurgatory && purgatoryData && (
|
{isInPurgatory && purgatoryData && (
|
||||||
<Alert
|
<Alert
|
||||||
|
@ -27,7 +27,6 @@ export default function wrapRootElement({
|
|||||||
}): ReactElement {
|
}): ReactElement {
|
||||||
const { network } = appConfig
|
const { network } = appConfig
|
||||||
const oceanInitialConfig = getOceanConfig(network)
|
const oceanInitialConfig = getOceanConfig(network)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<OceanProvider
|
<OceanProvider
|
||||||
initialConfig={oceanInitialConfig}
|
initialConfig={oceanInitialConfig}
|
||||||
|
@ -1,14 +1,18 @@
|
|||||||
import React, { ReactElement } from 'react'
|
import React, { ReactElement, useEffect, useState } from 'react'
|
||||||
import { PageProps } from 'gatsby'
|
import { PageProps } from 'gatsby'
|
||||||
import PageTemplateAssetDetails from '../../components/templates/PageAssetDetails'
|
import PageTemplateAssetDetails from '../../components/templates/PageAssetDetails'
|
||||||
import { AssetProvider } from '@oceanprotocol/react'
|
import AssetProvider from '../../providers/Asset'
|
||||||
|
|
||||||
export default function PageGatsbyAssetDetails(props: PageProps): ReactElement {
|
export default function PageGatsbyAssetDetails(props: PageProps): ReactElement {
|
||||||
const did = props.location.pathname.split('/')[2]
|
const [did, setDid] = useState<string>()
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setDid(props.location.pathname.split('/')[2])
|
||||||
|
}, [props.location.pathname])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AssetProvider asset={did}>
|
<AssetProvider asset={did}>
|
||||||
<PageTemplateAssetDetails did={did} uri={props.location.pathname} />
|
<PageTemplateAssetDetails uri={props.location.pathname} />
|
||||||
</AssetProvider>
|
</AssetProvider>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
206
src/providers/Asset.tsx
Normal file
206
src/providers/Asset.tsx
Normal file
@ -0,0 +1,206 @@
|
|||||||
|
import React, {
|
||||||
|
useContext,
|
||||||
|
useState,
|
||||||
|
useEffect,
|
||||||
|
createContext,
|
||||||
|
ReactElement,
|
||||||
|
useCallback,
|
||||||
|
ReactNode
|
||||||
|
} from 'react'
|
||||||
|
import { Logger, DDO, Metadata, BestPrice } 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'
|
||||||
|
|
||||||
|
interface AssetProviderValue {
|
||||||
|
isInPurgatory: boolean
|
||||||
|
purgatoryData: PurgatoryData
|
||||||
|
ddo: DDO | undefined
|
||||||
|
did: string | undefined
|
||||||
|
metadata: Metadata | undefined
|
||||||
|
title: string | undefined
|
||||||
|
owner: string | undefined
|
||||||
|
price: BestPrice | undefined
|
||||||
|
error?: string
|
||||||
|
refreshInterval: number
|
||||||
|
refreshPrice: () => Promise<void>
|
||||||
|
}
|
||||||
|
|
||||||
|
const AssetContext = createContext({} as AssetProviderValue)
|
||||||
|
|
||||||
|
const refreshInterval = 10000 // 10 sec.
|
||||||
|
|
||||||
|
function AssetProvider({
|
||||||
|
asset,
|
||||||
|
children
|
||||||
|
}: {
|
||||||
|
asset: string | DDO
|
||||||
|
children: ReactNode
|
||||||
|
}): ReactElement {
|
||||||
|
const { ocean, status, config, networkId } = useOcean()
|
||||||
|
const [isInPurgatory, setIsInPurgatory] = useState(false)
|
||||||
|
const [purgatoryData, setPurgatoryData] = useState<PurgatoryData>()
|
||||||
|
const [ddo, setDDO] = useState<DDO>()
|
||||||
|
const [did, setDID] = useState<string>()
|
||||||
|
const [metadata, setMetadata] = useState<Metadata>()
|
||||||
|
const [title, setTitle] = useState<string>()
|
||||||
|
const [price, setPrice] = useState<BestPrice>()
|
||||||
|
const [owner, setOwner] = useState<string>()
|
||||||
|
const [error, setError] = useState<string>()
|
||||||
|
|
||||||
|
const refreshPrice = useCallback(async () => {
|
||||||
|
if (
|
||||||
|
!ddo ||
|
||||||
|
status !== 1 ||
|
||||||
|
networkId !== (config as ConfigHelperConfig).networkId
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
const newPrice = await getDataTokenPrice(
|
||||||
|
ocean,
|
||||||
|
ddo.dataToken,
|
||||||
|
ddo?.price?.type,
|
||||||
|
ddo.price.pools[0]
|
||||||
|
)
|
||||||
|
setPrice(newPrice)
|
||||||
|
Logger.log(`Refreshed asset price: ${newPrice?.value}`)
|
||||||
|
}, [ocean, config, ddo, networkId, status])
|
||||||
|
|
||||||
|
const getDDO = useCallback(
|
||||||
|
async (did: string, cancelToken: CancelToken): Promise<DDO | undefined> => {
|
||||||
|
if (!config.metadataCacheUri) return
|
||||||
|
|
||||||
|
try {
|
||||||
|
const request = await axios.get(
|
||||||
|
`${config.metadataCacheUri}/api/v1/aquarius/assets/ddo/${did}`,
|
||||||
|
{ cancelToken }
|
||||||
|
)
|
||||||
|
const ddo = request.data as DDO
|
||||||
|
return new DDO(ddo)
|
||||||
|
} catch (error) {
|
||||||
|
Logger.error(error.message)
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[config.metadataCacheUri]
|
||||||
|
)
|
||||||
|
|
||||||
|
//
|
||||||
|
// Get and set DDO based on passed DDO or DID
|
||||||
|
//
|
||||||
|
useEffect(() => {
|
||||||
|
if (!asset) return
|
||||||
|
|
||||||
|
const source = axios.CancelToken.source()
|
||||||
|
let isMounted = true
|
||||||
|
Logger.log('Init asset, get ddo')
|
||||||
|
|
||||||
|
async function init(): Promise<void> {
|
||||||
|
const ddo = await getDDO(asset as string, source.token)
|
||||||
|
|
||||||
|
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.`
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
setError(undefined)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isMounted) return
|
||||||
|
Logger.debug('DDO', ddo)
|
||||||
|
setDDO(ddo)
|
||||||
|
setDID(asset as string)
|
||||||
|
}
|
||||||
|
init()
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
isMounted = false
|
||||||
|
source.cancel()
|
||||||
|
}
|
||||||
|
}, [asset, getDDO])
|
||||||
|
|
||||||
|
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)
|
||||||
|
} else {
|
||||||
|
setIsInPurgatory(false)
|
||||||
|
}
|
||||||
|
setPurgatoryData(result)
|
||||||
|
} catch (error) {
|
||||||
|
Logger.error(error)
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const initMetadata = useCallback(
|
||||||
|
async (ddo: DDO): Promise<void> => {
|
||||||
|
if (!ddo) return
|
||||||
|
|
||||||
|
Logger.log('Init metadata')
|
||||||
|
// Set price & metadata from DDO first
|
||||||
|
setPrice(ddo.price)
|
||||||
|
const { attributes } = ddo.findServiceByType('metadata')
|
||||||
|
setMetadata(attributes)
|
||||||
|
setTitle(attributes?.main.name)
|
||||||
|
setOwner(ddo.publicKey[0].owner)
|
||||||
|
|
||||||
|
await setPurgatory(ddo.id)
|
||||||
|
refreshPrice()
|
||||||
|
},
|
||||||
|
[refreshPrice, setPurgatory]
|
||||||
|
)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!ddo) return
|
||||||
|
initMetadata(ddo)
|
||||||
|
}, [ddo, initMetadata])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<AssetContext.Provider
|
||||||
|
value={
|
||||||
|
{
|
||||||
|
ddo,
|
||||||
|
did,
|
||||||
|
metadata,
|
||||||
|
title,
|
||||||
|
owner,
|
||||||
|
price,
|
||||||
|
error,
|
||||||
|
isInPurgatory,
|
||||||
|
purgatoryData,
|
||||||
|
refreshInterval,
|
||||||
|
refreshPrice
|
||||||
|
} as AssetProviderValue
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</AssetContext.Provider>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper hook to access the provider values
|
||||||
|
const useAsset = (): AssetProviderValue => useContext(AssetContext)
|
||||||
|
|
||||||
|
export { AssetProvider, useAsset, AssetProviderValue, AssetContext }
|
||||||
|
export default AssetProvider
|
11
src/utils/purgatory.ts
Normal file
11
src/utils/purgatory.ts
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import { PurgatoryData } from '@oceanprotocol/lib'
|
||||||
|
import axios from 'axios'
|
||||||
|
const purgatoryUrl = 'https://market-purgatory.oceanprotocol.com/api/'
|
||||||
|
|
||||||
|
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 }
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user