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

Refactor pricing and various components that are involved (#1046)

* update

* merge pr #1012

* fix header

* fix

* abort controller

* up next.8

* build fix

* update lock

* fix

* another fix

* ssh fix

* another ssh fix

* remove optional

* order mock

* small cleanup

* fix package

* price updates

* finish getPrice

* fix consume

* fix consume

* getConsumeDetails  comments

* restore functionality after consumeDetails

* fix some compute typings

* more price fetching updates

* 'minor' refactors and fixed build

* package-lock fix

* minor comments

* minor naming changes

* fix

* fix pool badge

* remove console.log
This commit is contained in:
mihaisc 2022-02-03 13:29:39 +02:00 committed by GitHub
parent 77c4ed42cc
commit 57be62a6b1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
53 changed files with 4998 additions and 5149 deletions

8592
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -25,7 +25,6 @@
"@oceanprotocol/typographies": "^0.1.0", "@oceanprotocol/typographies": "^0.1.0",
"@portis/web3": "^4.0.6", "@portis/web3": "^4.0.6",
"@tippyjs/react": "^4.2.6", "@tippyjs/react": "^4.2.6",
"@urql/introspection": "^0.3.1",
"@walletconnect/web3-provider": "^1.7.1", "@walletconnect/web3-provider": "^1.7.1",
"axios": "^0.25.0", "axios": "^0.25.0",
"bignumber.js": "^9.0.2", "bignumber.js": "^9.0.2",
@ -36,7 +35,6 @@
"decimal.js": "^10.3.1", "decimal.js": "^10.3.1",
"dom-confetti": "^0.2.2", "dom-confetti": "^0.2.2",
"dotenv": "^15.0.0", "dotenv": "^15.0.0",
"ethereum-address": "0.0.4",
"ethereum-blockies": "github:MyEtherWallet/blockies", "ethereum-blockies": "github:MyEtherWallet/blockies",
"filesize": "^8.0.6", "filesize": "^8.0.6",
"formik": "^2.2.9", "formik": "^2.2.9",
@ -48,7 +46,6 @@
"lodash.omit": "^4.5.0", "lodash.omit": "^4.5.0",
"next": "^12.0.9", "next": "^12.0.9",
"query-string": "^7.1.0", "query-string": "^7.1.0",
"querystring": "^0.2.1",
"react": "^17.0.2", "react": "^17.0.2",
"react-chartjs-2": "^4.0.1", "react-chartjs-2": "^4.0.1",
"react-clipboard.js": "^2.0.16", "react-clipboard.js": "^2.0.16",

View File

@ -9,26 +9,27 @@ import React, {
} from 'react' } from 'react'
import { Asset, Config, LoggerInstance, Purgatory } from '@oceanprotocol/lib' import { Asset, Config, LoggerInstance, Purgatory } from '@oceanprotocol/lib'
import { CancelToken } from 'axios' import { CancelToken } from 'axios'
import { retrieveDDO } from '@utils/aquarius' import { retrieveAsset } from '@utils/aquarius'
import { getPrice } from '@utils/subgraph'
import { useWeb3 } from './Web3' import { useWeb3 } from './Web3'
import { useSiteMetadata } from '@hooks/useSiteMetadata' import { useSiteMetadata } from '@hooks/useSiteMetadata'
import { useCancelToken } from '@hooks/useCancelToken' import { useCancelToken } from '@hooks/useCancelToken'
import { getOceanConfig, getDevelopmentConfig } from '@utils/ocean' import { getOceanConfig, getDevelopmentConfig } from '@utils/ocean'
import { AssetExtended } from 'src/@types/AssetExtended'
import { getAccessDetails } from '@utils/accessDetailsAndPricing'
interface AssetProviderValue { interface AssetProviderValue {
isInPurgatory: boolean isInPurgatory: boolean
purgatoryData: Purgatory purgatoryData: Purgatory
ddo: Asset assetExtended: AssetExtended
title: string title: string
owner: string owner: string
price: BestPrice accessDetails: AccessDetails
error?: string error?: string
refreshInterval: number refreshInterval: number
isAssetNetwork: boolean isAssetNetwork: boolean
oceanConfig: Config oceanConfig: Config
loading: boolean loading: boolean
refreshDdo: (token?: CancelToken) => Promise<void> refreshAsset: (token?: CancelToken) => Promise<void>
} }
const AssetContext = createContext({} as AssetProviderValue) const AssetContext = createContext({} as AssetProviderValue)
@ -44,12 +45,12 @@ function AssetProvider({
}): ReactElement { }): ReactElement {
const { appConfig } = useSiteMetadata() const { appConfig } = useSiteMetadata()
const { networkId } = useWeb3() const { networkId, accountId } = useWeb3()
const [isInPurgatory, setIsInPurgatory] = useState(false) const [isInPurgatory, setIsInPurgatory] = useState(false)
const [purgatoryData, setPurgatoryData] = useState<Purgatory>() const [purgatoryData, setPurgatoryData] = useState<Purgatory>()
const [ddo, setDDO] = useState<Asset>() const [assetExtended, setAssetExtended] = useState<Asset>()
const [title, setTitle] = useState<string>() const [title, setTitle] = useState<string>()
const [price, setPrice] = useState<BestPrice>() const [accessDetails, setConsumeDetails] = useState<AccessDetails>()
const [owner, setOwner] = useState<string>() const [owner, setOwner] = useState<string>()
const [error, setError] = useState<string>() const [error, setError] = useState<string>()
const [loading, setLoading] = useState(false) const [loading, setLoading] = useState(false)
@ -58,32 +59,35 @@ function AssetProvider({
const newCancelToken = useCancelToken() const newCancelToken = useCancelToken()
const fetchDdo = async (token?: CancelToken) => { const fetchAsset = useCallback(
LoggerInstance.log('[asset] Init asset, get DDO') async (token?: CancelToken) => {
LoggerInstance.log('[asset] Init asset, get assetExtended')
setLoading(true) setLoading(true)
const ddo = await retrieveDDO(did, token) const assetExtended = await retrieveAsset(did, token)
if (!ddo) { if (!assetExtended) {
setError( setError(
`[asset] The DDO for ${did} was not found in MetadataCache. If you just published a new data set, wait some seconds and refresh this page.` `[asset] The assetExtended for ${did} was not found in MetadataCache. If you just published a new data set, wait some seconds and refresh this page.`
) )
} else { } else {
setError(undefined) setError(undefined)
} }
setLoading(false) setLoading(false)
return ddo return assetExtended
} },
[did]
)
const refreshDdo = async (token?: CancelToken) => { const refreshAsset = async (token?: CancelToken) => {
setLoading(true) setLoading(true)
const ddo = await fetchDdo(token) const assetExtended = await fetchAsset(token)
LoggerInstance.debug('[asset] Got DDO', ddo) LoggerInstance.debug('[asset] Got assetExtended', assetExtended)
setDDO(ddo) setAssetExtended(assetExtended)
setLoading(false) setLoading(false)
} }
// ----------------------------------- // -----------------------------------
// Get and set DDO based on passed DID // Get and set assetExtended based on passed DID
// ----------------------------------- // -----------------------------------
useEffect(() => { useEffect(() => {
if (!did || !appConfig.metadataCacheUri) return if (!did || !appConfig.metadataCacheUri) return
@ -91,77 +95,89 @@ function AssetProvider({
let isMounted = true let isMounted = true
async function init() { async function init() {
const ddo = await fetchDdo(newCancelToken()) const assetExtended = await fetchAsset(newCancelToken())
if (!isMounted || !ddo) return if (!isMounted || !assetExtended) return
LoggerInstance.debug('[asset] Got DDO', ddo) LoggerInstance.debug('[asset] Got assetExtended', assetExtended)
setDDO(ddo) setAssetExtended(assetExtended)
setTitle(ddo.metadata.name) setTitle(assetExtended.metadata.name)
setOwner(ddo.nft.owner) setOwner(assetExtended.nft.owner)
setIsInPurgatory((ddo.purgatory?.state as unknown as string) === 'true') setIsInPurgatory(
setPurgatoryData(ddo.purgatory) (assetExtended.purgatory?.state as unknown as string) === 'true'
)
setPurgatoryData(assetExtended.purgatory)
} }
init() init()
return () => { return () => {
isMounted = false isMounted = false
} }
}, [did, appConfig.metadataCacheUri]) }, [did, appConfig.metadataCacheUri, fetchAsset, newCancelToken])
// ----------------------------------- // -----------------------------------
// Attach price to asset // Attach price to asset
// ----------------------------------- // -----------------------------------
const initPrice = useCallback(async (ddo: Asset): Promise<void> => { const initPrice = useCallback(
if (!ddo) return async (assetExtended: AssetExtended, accountId: string): Promise<void> => {
const returnedPrice = await getPrice(ddo) if (!assetExtended) return
setPrice({ ...returnedPrice }) const accessDetails = await getAccessDetails(
}, []) assetExtended.chainId,
assetExtended.services[0].datatokenAddress,
assetExtended.services[0].timeout,
accountId
)
assetExtended.accessDetails = accessDetails
setConsumeDetails({ ...accessDetails })
setAssetExtended(assetExtended)
},
[]
)
useEffect(() => { useEffect(() => {
if (!ddo) return if (!assetExtended) return
initPrice(ddo) initPrice(assetExtended, accountId)
}, [ddo, initPrice]) }, [accountId, assetExtended, initPrice])
// ----------------------------------- // -----------------------------------
// Check user network against asset network // Check user network against asset network
// ----------------------------------- // -----------------------------------
useEffect(() => { useEffect(() => {
if (!networkId || !ddo) return if (!networkId || !assetExtended) return
const isAssetNetwork = networkId === ddo?.chainId const isAssetNetwork = networkId === assetExtended?.chainId
setIsAssetNetwork(isAssetNetwork) setIsAssetNetwork(isAssetNetwork)
}, [networkId, ddo]) }, [networkId, assetExtended])
// ----------------------------------- // -----------------------------------
// Load ocean config based on asset network // Load ocean config based on asset network
// ----------------------------------- // -----------------------------------
useEffect(() => { useEffect(() => {
if (!ddo?.chainId) return if (!assetExtended?.chainId) return
const oceanConfig = { const oceanConfig = {
...getOceanConfig(ddo?.chainId), ...getOceanConfig(assetExtended?.chainId),
// add local dev values // add local dev values
...(ddo?.chainId === 8996 && { ...(assetExtended?.chainId === 8996 && {
...getDevelopmentConfig() ...getDevelopmentConfig()
}) })
} }
setOceanConfig(oceanConfig) setOceanConfig(oceanConfig)
}, [ddo]) }, [assetExtended])
return ( return (
<AssetContext.Provider <AssetContext.Provider
value={ value={
{ {
ddo, assetExtended,
did, did,
title, title,
owner, owner,
price, accessDetails,
error, error,
isInPurgatory, isInPurgatory,
purgatoryData, purgatoryData,
refreshInterval, refreshInterval,
loading, loading,
refreshDdo, refreshAsset,
isAssetNetwork, isAssetNetwork,
oceanConfig oceanConfig
} as AssetProviderValue } as AssetProviderValue

View File

@ -19,7 +19,6 @@ import { getDownloadAssets, getPublishedAssets } from '@utils/aquarius'
import { useSiteMetadata } from '@hooks/useSiteMetadata' import { useSiteMetadata } from '@hooks/useSiteMetadata'
import { accountTruncate } from '@utils/web3' import { accountTruncate } from '@utils/web3'
import axios, { CancelToken } from 'axios' import axios, { CancelToken } from 'axios'
import ethereumAddress from 'ethereum-address'
import get3BoxProfile from '@utils/profile' import get3BoxProfile from '@utils/profile'
import web3 from 'web3' import web3 from 'web3'
@ -59,7 +58,7 @@ function ProfileProvider({
// when accountId is no ETH address // when accountId is no ETH address
// //
useEffect(() => { useEffect(() => {
const isEthAddress = ethereumAddress.isAddress(accountId) const isEthAddress = web3.utils.isAddress(accountId)
setIsEthAddress(isEthAddress) setIsEthAddress(isEthAddress)
}, [accountId]) }, [accountId])

View File

@ -1,7 +1,19 @@
import { useState } from 'react' import { useState } from 'react'
import { consumeFeedback } from '@utils/feedback' import { consumeFeedback } from '@utils/feedback'
import { LoggerInstance } from '@oceanprotocol/lib' import {
approve,
Datatoken,
FreOrderParams,
LoggerInstance,
OrderParams,
Pool,
ProviderFees,
ProviderInstance,
signHash,
ZERO_ADDRESS
} from '@oceanprotocol/lib'
import { useWeb3 } from '@context/Web3' import { useWeb3 } from '@context/Web3'
import { getOceanConfig } from '@utils/ocean'
interface UseConsume { interface UseConsume {
consume: ( consume: (
@ -18,7 +30,7 @@ interface UseConsume {
} }
function useConsume(): UseConsume { function useConsume(): UseConsume {
const { accountId } = useWeb3() const { accountId, web3, chainId } = useWeb3()
const [isLoading, setIsLoading] = useState(false) const [isLoading, setIsLoading] = useState(false)
const [consumeStep, setConsumeStep] = useState<number | undefined>() const [consumeStep, setConsumeStep] = useState<number | undefined>()
const [consumeStepText, setConsumeStepText] = useState<string | undefined>() const [consumeStepText, setConsumeStepText] = useState<string | undefined>()
@ -29,9 +41,10 @@ function useConsume(): UseConsume {
setConsumeStepText(consumeFeedback[index]) setConsumeStepText(consumeFeedback[index])
} }
// TODO: this will be done in another PR
async function consume( async function consume(
did: string, did: string,
dataTokenAddress: string, datatokenAddress: string,
serviceType = 'access', serviceType = 'access',
marketFeeAddress: string, marketFeeAddress: string,
orderId?: string orderId?: string
@ -43,38 +56,82 @@ function useConsume(): UseConsume {
try { try {
setStep(0) setStep(0)
// if (!orderId) { if (!orderId) {
const datatoken = new Datatoken(web3)
// if we don't have a previous valid order, get one // if we don't have a previous valid order, get one
// const userOwnedTokens = await ocean.accounts.getTokenBalance( const userOwnedTokens = await datatoken.balance(
// dataTokenAddress, datatokenAddress,
// account accountId
// ) )
// if (parseFloat(userOwnedTokens) < 1) {
// setConsumeError('Not enough datatokens') setStep(1)
// return 'Not enough datatokens' try {
// } else { const config = getOceanConfig(chainId)
// setStep(1) // const txApprove = await approve(
// try { // web3,
// orderId = await ocean.assets.order(
// did as string,
// serviceType,
// accountId, // accountId,
// undefined, // config.oceanTokenAddress,
// marketFeeAddress, // accountId,
// undefined, // '1',
// null,
// false // false
// ) // )
// LoggerInstance.log('ordercreated', orderId) // console.log('approve tx', txApprove)
// setStep(2)
// } catch (error) { // const txApprove1 = await approve(
// setConsumeError(error.message) // web3,
// return error.message // accountId,
// } // config.oceanTokenAddress,
// } // datatokenAddress,
// } // '1',
// false
// )
// console.log('approve tx', txApprove1)
// diference between timeout and validUntil?
const initializeData = await ProviderInstance.initialize(
did,
'fca052c239a62523be30ab8ee70c4046867f6cd89f228185fe2996ded3d23c3c',
0,
accountId,
'https://providerv4.rinkeby.oceanprotocol.com'
)
const orderParams = {
consumer: accountId,
serviceIndex: 1,
_providerFees: initializeData.providerFee
} as OrderParams
const freParams = {
exchangeContract: config.fixedRateExchangeAddress,
exchangeId:
'0x7ac824fef114255e5e3521a161ef692ec32003916fb6f3fe985cb74790d053ca',
maxBaseTokenAmount: web3.utils.toWei('2'),
swapMarketFee: web3.utils.toWei('0'),
marketFeeAddress: ZERO_ADDRESS
} as FreOrderParams
const esttx = await datatoken.estGasBuyFromFreAndOrder(
datatokenAddress,
accountId,
orderParams,
freParams
)
const tx = await datatoken.buyFromFreAndOrder(
datatokenAddress,
accountId,
orderParams,
freParams
)
LoggerInstance.log('ordercreated', orderId)
setStep(2)
} catch (error) {
setConsumeError(error.message)
return error.message
}
}
setStep(3) setStep(3)
// if (orderId) if (orderId)
// await ocean.assets.download( // await ocean.assets.download(
// did as string, // did as string,
// orderId, // orderId,

View File

@ -39,6 +39,7 @@ async function getBlockHead(config: Config) {
} }
// for everything else, create new web3 instance with infura // for everything else, create new web3 instance with infura
// TODO: this fails randomly , WHY!?!?!?!?!
const web3Instance = new Web3(config.nodeUri) const web3Instance = new Web3(config.nodeUri)
const blockHead = await web3Instance.eth.getBlockNumber() const blockHead = await web3Instance.eth.getBlockNumber()
return blockHead return blockHead

View File

@ -9,21 +9,16 @@ import {
getCreateFreePricingFeedback, getCreateFreePricingFeedback,
getDispenseFeedback getDispenseFeedback
} from '@utils/feedback' } from '@utils/feedback'
import { sleep } from '@utils/index'
import { useWeb3 } from '@context/Web3' import { useWeb3 } from '@context/Web3'
import { getOceanConfig } from '@utils/ocean' import { getOceanConfig } from '@utils/ocean'
interface UsePricing { interface UsePricing {
getDTSymbol: (ddo: Asset) => Promise<string> getDTSymbol: (ddo: Asset) => Promise<string>
getDTName: (ddo: Asset) => Promise<string> getDTName: (ddo: Asset) => Promise<string>
createPricing: (
priceOptions: PriceOptions,
ddo: Asset
) => Promise<TransactionReceipt | string | void>
mint: (tokensToMint: string, ddo: Asset) => Promise<TransactionReceipt | void> mint: (tokensToMint: string, ddo: Asset) => Promise<TransactionReceipt | void>
buyDT: ( buyDT: (
amountDataToken: number | string, amountDataToken: number | string,
price: BestPrice, accessDetails: AccessDetails,
ddo: Asset ddo: Asset
) => Promise<TransactionReceipt | void> ) => Promise<TransactionReceipt | void>
pricingStep?: number pricingStep?: number
@ -123,7 +118,7 @@ function usePricing(): UsePricing {
async function buyDT( async function buyDT(
amountDataToken: number | string, amountDataToken: number | string,
price: BestPrice, accessDetails: AccessDetails,
ddo: Asset ddo: Asset
): Promise<TransactionReceipt | void> { ): Promise<TransactionReceipt | void> {
if (!accountId) return if (!accountId) return
@ -135,18 +130,20 @@ function usePricing(): UsePricing {
setPricingError(undefined) setPricingError(undefined)
setStep(1, 'buy', ddo) setStep(1, 'buy', ddo)
LoggerInstance.log('Price found for buying', price) LoggerInstance.log('Price found for buying', accessDetails)
Decimal.set({ precision: 18 }) Decimal.set({ precision: 18 })
switch (price?.type) { switch (accessDetails?.type) {
case 'dynamic': { case 'dynamic': {
const oceanAmmount = new Decimal(price.value).times(1.05).toString() const oceanAmmount = new Decimal(accessDetails.price)
const maxPrice = new Decimal(price.value).times(2).toString() .times(1.05)
.toString()
const maxPrice = new Decimal(accessDetails.price).times(2).toString()
setStep(2, 'buy', ddo) setStep(2, 'buy', ddo)
LoggerInstance.log( LoggerInstance.log(
'Buying token from pool', 'Buying token from pool',
price, accessDetails,
accountId, accountId,
oceanAmmount, oceanAmmount,
maxPrice maxPrice
@ -173,7 +170,11 @@ function usePricing(): UsePricing {
) )
return return
} }
LoggerInstance.log('Buying token from exchange', price, accountId) LoggerInstance.log(
'Buying token from exchange',
accessDetails,
accountId
)
// await ocean.datatokens.approve( // await ocean.datatokens.approve(
// oceanConfig.oceanTokenAddress, // oceanConfig.oceanTokenAddress,
// oceanConfig.fixedRateExchangeAddress, // oceanConfig.fixedRateExchangeAddress,
@ -227,77 +228,9 @@ function usePricing(): UsePricing {
return tx return tx
} }
async function createPricing(
priceOptions: PriceOptions,
ddo: Asset
): Promise<TransactionReceipt | void> {
const dataToken = ddo?.services[0].datatokenAddress
const dtSymbol = await getDTSymbol(ddo)
if (!accountId || !dtSymbol) return
const { type, amountOcean, price, weightOnDataToken, swapFee } =
priceOptions
let { amountDataToken } = priceOptions
const isPool = type === 'dynamic'
if (!isPool && !oceanConfig.fixedRateExchangeAddress) {
LoggerInstance.error(`'fixedRateExchangeAddress' not set in oceanConfig.`)
return
}
setPricingIsLoading(true)
setPricingError(undefined)
setStep(99, 'pool', ddo)
try {
if (type === 'free') {
setStep(99, 'free', ddo)
// await ocean.OceanDispenser.activate(dataToken, '1', '1', accountId)
} else {
// if fixedPrice set dt to max amount
if (!isPool) amountDataToken = 1000
await mint(`${amountDataToken}`, ddo)
}
// amountDataToken for fixed price is set to max
// const tx = isPool
// ? await ocean.pool
// .create(
// accountId,
// dataToken,
// `${amountDataToken}`,
// weightOnDataToken,
// `${amountOcean}`,
// `${swapFee}`
// )
// .next((step: number) => setStep(step, 'pool', ddo))
// : type === 'fixed'
// ? await ocean.fixedRateExchange
// .create(dataToken, `${price}`, accountId, `${amountDataToken}`)
// .next((step: number) => setStep(step, 'exchange', ddo))
// : await ocean.OceanDispenser.makeMinter(dataToken, accountId).next(
// (step: number) => setStep(step, 'free', ddo)
// )
// we should remove this sleep , why do we have sleep for 20 seconds !?!?!?!?!?!?!!?
// await sleep(20000)
// return tx
} catch (error) {
setPricingError(error.message)
LoggerInstance.error(error)
} finally {
setPricingStep(0)
setPricingStepText(undefined)
setPricingIsLoading(false)
}
}
return { return {
getDTSymbol, getDTSymbol,
getDTName, getDTName,
createPricing,
buyDT, buyDT,
mint, mint,
pricingStep, pricingStep,

5
src/@types/AssetExtended.d.ts vendored Normal file
View File

@ -0,0 +1,5 @@
import { Asset } from '@oceanprotocol/lib'
interface AssetExtended extends Asset {
accessDetails?: AccessDetails
}

20
src/@types/Price.d.ts vendored
View File

@ -1,14 +1,14 @@
interface BestPrice { interface AccessDetails {
type: 'dynamic' | 'fixed' | 'free' | '' type: 'dynamic' | 'fixed' | 'free' | ''
address: string price: number
value: number // if type is dynamic this is the pool address, for fixed/free this is an id.
isConsumable?: 'true' | 'false' | '' addressOrId: string
ocean?: number baseToken: TokenInfo
oceanSymbol?: string datatoken: TokenInfo
datatoken?: number isConsumable?: boolean
datatokenSymbol?: string // if there are valid orders for this
exchangeId?: string owned: bool
pools: string[] validOrderTx: string
} }
interface PriceOptions { interface PriceOptions {

6
src/@types/TokenInfo.d.ts vendored Normal file
View File

@ -0,0 +1,6 @@
interface TokenInfo {
address: string
name: string
symbol: string
decimals?: number
}

View File

@ -2,5 +2,5 @@ interface DownloadedAsset {
dtSymbol: string dtSymbol: string
timestamp: number timestamp: number
networkId: number networkId: number
ddo: Asset asset: Asset
} }

View File

@ -1,7 +1,3 @@
declare module 'ethereum-blockies' { declare module 'ethereum-blockies' {
export function toDataUrl(address: string): string export function toDataUrl(address: string): string
} }
declare module 'ethereum-address' {
export function isAddress(address: string): boolean
}

View File

@ -0,0 +1,282 @@
import { gql, OperationResult } from 'urql'
import { fetchData, getQueryContext } from './subgraph'
import {
TokenPriceQuery,
TokenPriceQuery_token as TokenPrice
} from '../@types/subgraph/TokenPriceQuery'
import {
TokensPriceQuery,
TokensPriceQuery_tokens as TokensPrice
} from '../@types/subgraph/TokensPriceQuery'
import { Asset } from '@oceanprotocol/lib'
import { AssetExtended } from 'src/@types/AssetExtended'
const TokensPriceQuery = gql`
query TokensPriceQuery($datatokenIds: [ID!], $account: String) {
tokens(where: { id_in: $datatokenIds }) {
id
symbol
name
orders(
where: { consumer: $account }
orderBy: createdTimestamp
orderDirection: desc
) {
tx
serviceIndex
createdTimestamp
}
dispensers {
id
active
isMinter
maxBalance
token {
id
name
symbol
}
}
fixedRateExchanges {
id
price
baseToken {
symbol
name
address
}
datatoken {
symbol
name
address
}
active
}
pools {
id
spotPrice
isFinalized
datatokenLiquidity
baseToken {
symbol
name
address
}
datatoken {
symbol
name
address
}
}
}
}
`
const TokenPriceQuery = gql`
query TokenPriceQuery($datatokenId: ID!, $account: String) {
token(id: $datatokenId) {
id
symbol
name
orders(
where: { consumer: $account }
orderBy: createdTimestamp
orderDirection: desc
) {
tx
serviceIndex
createdTimestamp
}
dispensers {
id
active
isMinter
maxBalance
token {
id
name
symbol
}
}
fixedRateExchanges {
id
price
baseToken {
symbol
name
address
}
datatoken {
symbol
name
address
}
active
}
pools {
id
spotPrice
isFinalized
datatokenLiquidity
baseToken {
symbol
name
address
}
datatoken {
symbol
name
address
}
}
}
}
`
function getAccessDetailsFromTokenPrice(
tokenPrice: TokenPrice | TokensPrice,
timeout?: number
): AccessDetails {
const accessDetails = {} as AccessDetails
if (!timeout && !tokenPrice.orders && tokenPrice.orders.length > 0) {
const order = tokenPrice.orders[0]
accessDetails.owned = Date.now() / 1000 - order.createdTimestamp < timeout
accessDetails.validOrderTx = order.tx
}
// free is always the best price
if (tokenPrice.dispensers && tokenPrice.dispensers.length > 0) {
const dispenser = tokenPrice.dispensers[0]
accessDetails.type = 'free'
accessDetails.addressOrId = dispenser.id
accessDetails.price = 0
accessDetails.isConsumable = dispenser.active
accessDetails.datatoken = {
address: dispenser.token.id,
name: dispenser.token.name,
symbol: dispenser.token.symbol
}
return accessDetails
}
// checking for fixed price
if (
tokenPrice.fixedRateExchanges &&
tokenPrice.fixedRateExchanges.length > 0
) {
const fre = tokenPrice.fixedRateExchanges[0]
accessDetails.type = 'fixed'
accessDetails.addressOrId = fre.id
accessDetails.price = fre.price
// in theory we should check dt balance here, we can skip this because in the market we always create fre with minting capabilities.
accessDetails.isConsumable = fre.active
accessDetails.baseToken = {
address: fre.baseToken.address,
name: fre.baseToken.name,
symbol: fre.baseToken.symbol
}
accessDetails.datatoken = {
address: fre.datatoken.address,
name: fre.datatoken.name,
symbol: fre.datatoken.symbol
}
return accessDetails
}
// checking for pools
if (tokenPrice.pools && tokenPrice.pools.length > 0) {
const pool = tokenPrice.pools[0]
accessDetails.type = 'dynamic'
accessDetails.addressOrId = pool.id
// TODO: this needs to be consumePrice
accessDetails.price = pool.spotPrice
// TODO: pool.datatokenLiquidity > 3 is kinda random here, we shouldn't run into this anymore now , needs more thinking/testing
accessDetails.isConsumable = pool.isFinalized && pool.datatokenLiquidity > 3
accessDetails.baseToken = {
address: pool.baseToken.address,
name: pool.baseToken.name,
symbol: pool.baseToken.symbol
}
accessDetails.datatoken = {
address: pool.datatoken.address,
name: pool.datatoken.name,
symbol: pool.datatoken.symbol
}
return accessDetails
}
return accessDetails
}
/**
* returns various consume details for the desired datatoken
* @param chain chain on witch the dt is preset
* @param datatokenAddress address of the datatoken
* @param timeout timeout of the service , only needed if you want order details like owned and validOrderId
* @param account account that wants to consume, only needed if you want order details like owned and validOrderId
* @returns AccessDetails
*/
export async function getAccessDetails(
chain: number,
datatokenAddress: string,
timeout?: number,
account = ''
): Promise<AccessDetails> {
let accessDetails = {} as AccessDetails
const queryContext = getQueryContext(Number(chain))
const tokenQueryResult: OperationResult<TokenPriceQuery, any> =
await fetchData(
TokenPriceQuery,
{
datatokenId: datatokenAddress.toLowerCase(),
account: account.toLowerCase()
},
queryContext
)
const tokenPrice: TokenPrice = tokenQueryResult.data.token
accessDetails = getAccessDetailsFromTokenPrice(tokenPrice, timeout)
return accessDetails
}
export async function getAccessDetailsForAssets(
assets: Asset[],
account = ''
): Promise<AssetExtended[]> {
const assetsExtended: AssetExtended[] = assets
const chainAssetLists: any = {}
for (const asset of assets) {
// harcoded until we have chainId on assets
if (chainAssetLists[asset.chainId]) {
chainAssetLists[asset.chainId].push(
asset?.services[0].datatokenAddress.toLowerCase()
)
} else {
chainAssetLists[asset.chainId] = []
chainAssetLists[asset.chainId].push(
asset?.services[0].datatokenAddress.toLowerCase()
)
}
}
for (const chainKey in chainAssetLists) {
const queryContext = getQueryContext(Number(chainKey))
const tokenQueryResult: OperationResult<TokensPriceQuery, any> =
await fetchData(
TokensPriceQuery,
{
datatokenIds: chainAssetLists[chainKey],
account: account.toLowerCase()
},
queryContext
)
tokenQueryResult.data?.tokens.forEach((token) => {
const accessDetails = getAccessDetailsFromTokenPrice(token)
const currentAsset = assetsExtended.find(
(asset) => asset.services[0].datatokenAddress.toLowerCase() === token.id
)
currentAsset.accessDetails = accessDetails
})
}
return assetsExtended
}

View File

@ -4,7 +4,7 @@ import {
PublisherTrustedAlgorithm PublisherTrustedAlgorithm
} from '@oceanprotocol/lib' } from '@oceanprotocol/lib'
import { AssetSelectionAsset } from '@shared/FormFields/AssetSelection' import { AssetSelectionAsset } from '@shared/FormFields/AssetSelection'
import { PriceList, getAssetsPriceList } from './subgraph' import { PriceList } from './subgraph'
import axios, { CancelToken, AxiosResponse } from 'axios' import axios, { CancelToken, AxiosResponse } from 'axios'
import { OrdersData_orders as OrdersData } from '../@types/subgraph/OrdersData' import { OrdersData_orders as OrdersData } from '../@types/subgraph/OrdersData'
import { metadataCacheUri } from '../../app.config' import { metadataCacheUri } from '../../app.config'
@ -110,7 +110,7 @@ export async function queryMetadata(
} }
} }
export async function retrieveDDO( export async function retrieveAsset(
did: string, did: string,
cancelToken: CancelToken cancelToken: CancelToken
): Promise<Asset> { ): Promise<Asset> {
@ -207,7 +207,8 @@ export async function transformDDOToAssetSelection(
cancelToken?: CancelToken cancelToken?: CancelToken
): Promise<AssetSelectionAsset[]> { ): Promise<AssetSelectionAsset[]> {
const didList: string[] = [] const didList: string[] = []
const priceList: PriceList = await getAssetsPriceList(ddoList) // const priceList: PriceList = await getAssetsPriceList(ddoList)
const priceList: PriceList = null
const symbolList: any = {} const symbolList: any = {}
const didProviderEndpointMap: any = {} const didProviderEndpointMap: any = {}
for (const ddo of ddoList) { for (const ddo of ddoList) {
@ -346,16 +347,16 @@ export async function getDownloadAssets(
const result = await queryMetadata(query, cancelToken) const result = await queryMetadata(query, cancelToken)
const downloadedAssets: DownloadedAsset[] = result.results const downloadedAssets: DownloadedAsset[] = result.results
.map((ddo) => { .map((asset) => {
const order = tokenOrders.find( const order = tokenOrders.find(
({ datatoken }) => ({ datatoken }) =>
datatoken?.address.toLowerCase() === datatoken?.address.toLowerCase() ===
ddo.services[0].datatokenAddress.toLowerCase() asset.services[0].datatokenAddress.toLowerCase()
) )
return { return {
ddo, asset,
networkId: ddo.chainId, networkId: asset.chainId,
dtSymbol: order?.datatoken?.symbol, dtSymbol: order?.datatoken?.symbol,
timestamp: order?.createdTimestamp timestamp: order?.createdTimestamp
} }

View File

@ -1,41 +0,0 @@
import { LoggerInstance } from '@oceanprotocol/lib'
import { TransactionReceipt } from 'web3-core'
export async function setMinterToPublisher(
dataTokenAddress: string,
accountId: string,
setError: (msg: string) => void
): Promise<TransactionReceipt> {
// free pricing v3 workaround part1
// const status = await ocean.OceanDispenser.status(dataTokenAddress)
// if (!status?.minterApproved) return
// const response = await ocean.OceanDispenser.cancelMinter(
// dataTokenAddress,
// accountId
// )
// if (!response) {
// setError('Updating DDO failed.')
// LoggerInstance.error('Failed at cancelMinter')
// }
// return response
return null
}
export async function setMinterToDispenser(
dataTokenAddress: string,
accountId: string,
setError: (msg: string) => void
): Promise<TransactionReceipt> {
// free pricing v3 workaround part2
// const response = await ocean.OceanDispenser.makeMinter(
// dataTokenAddress,
// accountId
// )
// if (!response) {
// setError('Updating DDO failed.')
// LoggerInstance.error('Failed at makeMinter')
// }
// return response
return null
}

View File

@ -62,7 +62,7 @@ export function generateNftCreateData(nftMetadata: NftMetadata): any {
symbol: nftMetadata.symbol, symbol: nftMetadata.symbol,
templateIndex: 1, templateIndex: 1,
// Gas estimation fails if we add our huge tokenURI // Gas estimation fails if we add our huge tokenURI
tokenURI: '' tokenURI: '{url:"https://coolImage.com, name: "just for test"}'
// TODO: figure out if Buffer.from method is working in browser in final build // TODO: figure out if Buffer.from method is working in browser in final build
// as BTOA is deprecated. // as BTOA is deprecated.
// tokenURI: window?.btoa(JSON.stringify(nftMetadata)) // tokenURI: window?.btoa(JSON.stringify(nftMetadata))

View File

@ -16,7 +16,6 @@ export function getOceanConfig(network: string | number): Config {
? undefined ? undefined
: process.env.NEXT_PUBLIC_INFURA_PROJECT_ID : process.env.NEXT_PUBLIC_INFURA_PROJECT_ID
) as Config ) as Config
// TODO: remove hack once address is fixed // TODO: remove hack once address is fixed
if (network === 'rinkeby' || network === 4) if (network === 'rinkeby' || network === 4)
config.oceanTokenAddress = '0x8967bcf84170c91b0d24d4302c2376283b0b3a07' config.oceanTokenAddress = '0x8967bcf84170c91b0d24d4302c2376283b0b3a07'

View File

@ -36,11 +36,6 @@ export interface PriceList {
[key: string]: string [key: string]: string
} }
export interface AssetListPrices {
ddo: Asset
price: BestPrice
}
interface DidAndDatatokenMap { interface DidAndDatatokenMap {
[name: string]: string [name: string]: string
} }
@ -410,195 +405,6 @@ export async function getPreviousOrders(
} }
} }
function transformPriceToBestPrice(
frePrice: AssetsFrePriceFixedRateExchange[],
poolPrice: AssetsPoolPricePool[],
freePrice: AssetFreePriceDispenser[]
) {
if (poolPrice?.length > 0) {
const price: BestPrice = {
type: 'dynamic',
address: poolPrice[0]?.id,
value: poolPrice[0]?.spotPrice,
ocean: poolPrice[0]?.baseTokenLiquidity,
oceanSymbol: poolPrice[0]?.baseToken.symbol,
datatoken: poolPrice[0]?.datatokenLiquidity,
pools: [poolPrice[0]?.id],
isConsumable: poolPrice[0]?.spotPrice === '-1' ? 'false' : 'true'
}
return price
} else if (frePrice?.length > 0) {
// TODO Hacky hack, temporary™: set isConsumable to true for fre assets.
// isConsumable: 'true'
const price: BestPrice = {
type: 'fixed',
value: frePrice[0]?.price,
address: frePrice[0]?.id,
exchangeId: frePrice[0]?.id,
oceanSymbol: frePrice[0]?.baseToken.symbol,
ocean: 0,
datatoken: 0,
pools: [],
isConsumable: 'true'
}
return price
} else if (freePrice?.length > 0) {
const price: BestPrice = {
type: 'free',
value: 0,
address: freePrice[0]?.token.id,
exchangeId: '',
ocean: 0,
datatoken: 0,
pools: [],
isConsumable: 'true'
}
return price
} else {
const price: BestPrice = {
type: '',
value: 0,
address: '',
exchangeId: '',
ocean: 0,
datatoken: 0,
pools: [],
isConsumable: 'false'
}
return price
}
}
async function getAssetsPoolsExchangesAndDatatokenMap(
assets: Asset[]
): Promise<
[
AssetsPoolPricePool[],
AssetsFrePriceFixedRateExchange[],
AssetFreePriceDispenser[],
DidAndDatatokenMap
]
> {
const didDTMap: DidAndDatatokenMap = {}
const chainAssetLists: any = {}
for (const ddo of assets) {
didDTMap[ddo?.services[0].datatokenAddress.toLowerCase()] = ddo.id
// harcoded until we have chainId on assets
if (chainAssetLists[ddo.chainId]) {
chainAssetLists[ddo.chainId].push(
ddo?.services[0].datatokenAddress.toLowerCase()
)
} else {
chainAssetLists[ddo.chainId] = []
chainAssetLists[ddo.chainId].push(
ddo?.services[0].datatokenAddress.toLowerCase()
)
}
}
let poolPriceResponse: AssetsPoolPricePool[] = []
let frePriceResponse: AssetsFrePriceFixedRateExchange[] = []
let freePriceResponse: AssetFreePriceDispenser[] = []
for (const chainKey in chainAssetLists) {
const freVariables = {
datatoken_in: chainAssetLists[chainKey]
}
const poolVariables = {
datatokenAddress_in: chainAssetLists[chainKey]
}
const freeVariables = {
datatoken_in: chainAssetLists[chainKey]
}
const queryContext = getQueryContext(Number(chainKey))
const chainPoolPriceResponse: OperationResult<AssetsPoolPrice> =
await fetchData(PoolQuery, poolVariables, queryContext)
poolPriceResponse = poolPriceResponse.concat(
chainPoolPriceResponse.data.pools
)
const chainFrePriceResponse: OperationResult<AssetsFrePrice> =
await fetchData(FreQuery, freVariables, queryContext)
frePriceResponse = frePriceResponse.concat(
chainFrePriceResponse.data.fixedRateExchanges
)
const chainFreePriceResponse: OperationResult<AssetsFreePrice> =
await fetchData(FreeQuery, freeVariables, queryContext)
freePriceResponse = freePriceResponse.concat(
chainFreePriceResponse.data.dispensers
)
}
return [poolPriceResponse, frePriceResponse, freePriceResponse, didDTMap]
}
export async function getAssetsPriceList(assets: Asset[]): Promise<PriceList> {
const priceList: PriceList = {}
const values: [
AssetsPoolPricePool[],
AssetsFrePriceFixedRateExchange[],
AssetFreePriceDispenser[],
DidAndDatatokenMap
] = await getAssetsPoolsExchangesAndDatatokenMap(assets)
const poolPriceResponse = values[0]
const frePriceResponse = values[1]
const freePriceResponse = values[2]
const didDTMap: DidAndDatatokenMap = values[3]
for (const poolPrice of poolPriceResponse) {
priceList[didDTMap[poolPrice.datatoken.address]] = poolPrice.spotPrice
}
for (const frePrice of frePriceResponse) {
priceList[didDTMap[frePrice.datatoken?.address]] = frePrice.price
}
for (const freePrice of freePriceResponse) {
priceList[didDTMap[freePrice.token?.address]] = '0'
}
return priceList
}
export async function getPrice(asset: Asset): Promise<BestPrice> {
const freVariables = {
datatoken: asset?.services[0].datatokenAddress.toLowerCase()
}
const freeVariables = {
datatoken: asset?.services[0].datatokenAddress.toLowerCase()
}
const poolVariables = {
datatokenAddress: asset?.services[0].datatokenAddress.toLowerCase()
}
const queryContext = getQueryContext(Number(asset.chainId))
const poolPriceResponse: OperationResult<AssetsPoolPrice> = await fetchData(
AssetPoolPriceQuery,
poolVariables,
queryContext
)
const frePriceResponse: OperationResult<AssetsFrePrice> = await fetchData(
AssetFreQuery,
freVariables,
queryContext
)
const freePriceResponse: OperationResult<AssetsFreePrice> = await fetchData(
AssetFreeQuery,
freeVariables,
queryContext
)
const bestPrice: BestPrice = transformPriceToBestPrice(
frePriceResponse.data.fixedRateExchanges,
poolPriceResponse.data.pools,
freePriceResponse.data.dispensers
)
return bestPrice
}
export async function getSpotPrice(asset: Asset): Promise<number> { export async function getSpotPrice(asset: Asset): Promise<number> {
const poolVariables = { const poolVariables = {
datatokenAddress: asset?.services[0].datatokenAddress.toLowerCase() datatokenAddress: asset?.services[0].datatokenAddress.toLowerCase()
@ -614,49 +420,6 @@ export async function getSpotPrice(asset: Asset): Promise<number> {
return poolPriceResponse.data.pools[0].spotPrice return poolPriceResponse.data.pools[0].spotPrice
} }
export async function getAssetsBestPrices(
assets: Asset[]
): Promise<AssetListPrices[]> {
const assetsWithPrice: AssetListPrices[] = []
const values: [
AssetsPoolPricePool[],
AssetsFrePriceFixedRateExchange[],
AssetFreePriceDispenser[],
DidAndDatatokenMap
] = await getAssetsPoolsExchangesAndDatatokenMap(assets)
const poolPriceResponse = values[0]
const frePriceResponse = values[1]
const freePriceResponse = values[2]
for (const ddo of assets) {
const dataToken = ddo.services[0].datatokenAddress.toLowerCase()
const poolPrice: AssetsPoolPricePool[] = []
const frePrice: AssetsFrePriceFixedRateExchange[] = []
const freePrice: AssetFreePriceDispenser[] = []
const pool = poolPriceResponse.find(
(pool: AssetsPoolPricePool) => pool.datatoken.address === dataToken
)
pool && poolPrice.push(pool)
const fre = frePriceResponse.find(
(fre: AssetsFrePriceFixedRateExchange) =>
fre.datatoken.address === dataToken
)
fre && frePrice.push(fre)
const free = freePriceResponse.find(
(free: AssetFreePriceDispenser) => free.token.address === dataToken
)
free && freePrice.push(free)
const bestPrice = transformPriceToBestPrice(frePrice, poolPrice, freePrice)
assetsWithPrice.push({
ddo: ddo,
price: bestPrice
})
}
return assetsWithPrice
}
export async function getHighestLiquidityDatatokens( export async function getHighestLiquidityDatatokens(
chainIds: number[] chainIds: number[]
): Promise<string[]> { ): Promise<string[]> {

View File

@ -7,11 +7,11 @@ import { useSiteMetadata } from '@hooks/useSiteMetadata'
import { Asset } from '@oceanprotocol/lib' import { Asset } from '@oceanprotocol/lib'
export default function AssetListTitle({ export default function AssetListTitle({
ddo, asset,
did, did,
title title
}: { }: {
ddo?: Asset asset?: Asset
did?: string did?: string
title?: string title?: string
}): ReactElement { }): ReactElement {
@ -20,8 +20,8 @@ export default function AssetListTitle({
useEffect(() => { useEffect(() => {
if (title || !appConfig.metadataCacheUri) return if (title || !appConfig.metadataCacheUri) return
if (ddo) { if (asset) {
setAssetTitle(ddo.metadata.name) setAssetTitle(asset.metadata.name)
return return
} }
@ -32,16 +32,16 @@ export default function AssetListTitle({
setAssetTitle(title[did]) setAssetTitle(title[did])
} }
!ddo && did && getAssetName() !asset && did && getAssetName()
return () => { return () => {
source.cancel() source.cancel()
} }
}, [assetTitle, appConfig.metadataCacheUri, ddo, did, title]) }, [assetTitle, appConfig.metadataCacheUri, asset, did, title])
return ( return (
<h3 className={styles.title}> <h3 className={styles.title}>
<Link href={`/asset/${did || ddo?.id}`}> <Link href={`/asset/${did || asset?.id}`}>
<a>{assetTitle}</a> <a>{assetTitle}</a>
</Link> </Link>
</h3> </h3>

View File

@ -3,11 +3,13 @@ import React, { ReactElement, useEffect, useState } from 'react'
import Pagination from '@shared/Pagination' import Pagination from '@shared/Pagination'
import styles from './index.module.css' import styles from './index.module.css'
import classNames from 'classnames/bind' import classNames from 'classnames/bind'
import { getAssetsBestPrices, AssetListPrices } from '@utils/subgraph'
import Loader from '@shared/atoms/Loader' import Loader from '@shared/atoms/Loader'
import { useUserPreferences } from '@context/UserPreferences' import { useUserPreferences } from '@context/UserPreferences'
import { useIsMounted } from '@hooks/useIsMounted' import { useIsMounted } from '@hooks/useIsMounted'
// not sure why this import is required
import { AssetExtended } from 'src/@types/AssetExtended'
import { Asset } from '@oceanprotocol/lib' import { Asset } from '@oceanprotocol/lib'
import { getAccessDetailsForAssets } from '@utils/accessDetailsAndPricing'
const cx = classNames.bind(styles) const cx = classNames.bind(styles)
@ -41,24 +43,19 @@ export default function AssetList({
noPublisher noPublisher
}: AssetListProps): ReactElement { }: AssetListProps): ReactElement {
const { chainIds } = useUserPreferences() const { chainIds } = useUserPreferences()
const [assetsWithPrices, setAssetsWithPrices] = useState<AssetListPrices[]>() const [assetsWithPrices, setAssetsWithPrices] = useState<AssetExtended[]>()
const [loading, setLoading] = useState<boolean>(isLoading) const [loading, setLoading] = useState<boolean>(isLoading)
const isMounted = useIsMounted() const isMounted = useIsMounted()
useEffect(() => { useEffect(() => {
if (!assets) return if (!assets) return
setAssetsWithPrices(assets as AssetExtended[])
const initialAssets: AssetListPrices[] = assets.map((asset) => ({
ddo: asset,
price: null
}))
setAssetsWithPrices(initialAssets)
setLoading(false) setLoading(false)
async function fetchPrices() { async function fetchPrices() {
const assetsWithPrices = await getAssetsBestPrices(assets) const assetsWithPrices = await getAccessDetailsForAssets(assets)
if (!isMounted()) return if (!isMounted()) return
setAssetsWithPrices(assetsWithPrices) setAssetsWithPrices([...assetsWithPrices])
} }
fetchPrices() fetchPrices()
}, [assets, isMounted]) }, [assets, isMounted])
@ -83,9 +80,8 @@ export default function AssetList({
{assetsWithPrices.length > 0 ? ( {assetsWithPrices.length > 0 ? (
assetsWithPrices.map((assetWithPrice) => ( assetsWithPrices.map((assetWithPrice) => (
<AssetTeaser <AssetTeaser
ddo={assetWithPrice.ddo} assetExtended={assetWithPrice}
price={assetWithPrice.price} key={assetWithPrice.id}
key={assetWithPrice.ddo.id}
noPublisher={noPublisher} noPublisher={noPublisher}
/> />
)) ))

View File

@ -8,28 +8,25 @@ import AssetType from '@shared/AssetType'
import NetworkName from '@shared/NetworkName' import NetworkName from '@shared/NetworkName'
import styles from './AssetTeaser.module.css' import styles from './AssetTeaser.module.css'
import { getServiceByName } from '@utils/ddo' import { getServiceByName } from '@utils/ddo'
import { Asset } from '@oceanprotocol/lib' import { AssetExtended } from 'src/@types/AssetExtended'
declare type AssetTeaserProps = { declare type AssetTeaserProps = {
ddo: Asset assetExtended: AssetExtended
price: BestPrice
noPublisher?: boolean noPublisher?: boolean
} }
export default function AssetTeaser({ export default function AssetTeaser({
ddo, assetExtended,
price,
noPublisher noPublisher
}: AssetTeaserProps): ReactElement { }: AssetTeaserProps): ReactElement {
const { name, type, description } = ddo.metadata const { name, type, description } = assetExtended.metadata
const { datatokens } = ddo const { datatokens } = assetExtended
const isCompute = Boolean(getServiceByName(ddo, 'compute')) const isCompute = Boolean(getServiceByName(assetExtended, 'compute'))
const accessType = isCompute ? 'compute' : 'access' const accessType = isCompute ? 'compute' : 'access'
const { owner } = ddo.nft const { owner } = assetExtended.nft
return ( return (
<article className={`${styles.teaser} ${styles[type]}`}> <article className={`${styles.teaser} ${styles[type]}`}>
<Link href={`/asset/${ddo.id}`}> <Link href={`/asset/${assetExtended.id}`}>
<a className={styles.link}> <a className={styles.link}>
<header className={styles.header}> <header className={styles.header}>
<div className={styles.symbol}>{datatokens[0]?.symbol}</div> <div className={styles.symbol}>{datatokens[0]?.symbol}</div>
@ -54,8 +51,11 @@ export default function AssetTeaser({
</div> </div>
<footer className={styles.foot}> <footer className={styles.foot}>
<Price price={price} small /> <Price accessDetails={assetExtended.accessDetails} small />
<NetworkName networkId={ddo.chainId} className={styles.network} /> <NetworkName
networkId={assetExtended.chainId}
className={styles.network}
/>
</footer> </footer>
</a> </a>
</Link> </Link>

View File

@ -75,7 +75,7 @@ const txHistoryQuery = gql`
export interface PoolTransaction extends TransactionHistoryPoolTransactions { export interface PoolTransaction extends TransactionHistoryPoolTransactions {
networkId: number networkId: number
ddo: Asset asset: Asset
} }
const columns = [ const columns = [
@ -88,7 +88,7 @@ const columns = [
{ {
name: 'Data Set', name: 'Data Set',
selector: function getAssetRow(row: PoolTransaction) { selector: function getAssetRow(row: PoolTransaction) {
return <AssetTitle ddo={row.ddo} /> return <AssetTitle asset={row.asset} />
} }
}, },
{ {
@ -187,7 +187,7 @@ export default function PoolTransactions({
poolTransactions.push({ poolTransactions.push({
...data[i], ...data[i],
networkId: ddoList[i]?.chainId, networkId: ddoList[i]?.chainId,
ddo: ddoList[i] asset: ddoList[i]
}) })
} }
const sortedTransactions = poolTransactions.sort( const sortedTransactions = poolTransactions.sort(

View File

@ -49,7 +49,7 @@ export default function PriceUnit({
<div> <div>
{Number.isNaN(Number(price)) ? '-' : formatPrice(price, locale)}{' '} {Number.isNaN(Number(price)) ? '-' : formatPrice(price, locale)}{' '}
<span className={styles.symbol}>{symbol}</span> <span className={styles.symbol}>{symbol}</span>
{type && type === 'pool' && ( {type && type === 'dynamic' && (
<Badge label="pool" className={styles.badge} /> <Badge label="pool" className={styles.badge} />
)} )}
</div> </div>

View File

@ -5,26 +5,26 @@ import Tooltip from '../atoms/Tooltip'
import PriceUnit from './PriceUnit' import PriceUnit from './PriceUnit'
export default function Price({ export default function Price({
price, accessDetails,
className, className,
small, small,
conversion conversion
}: { }: {
price: BestPrice accessDetails: AccessDetails
className?: string className?: string
small?: boolean small?: boolean
conversion?: boolean conversion?: boolean
}): ReactElement { }): ReactElement {
return price?.value || price?.type === 'free' ? ( return accessDetails?.price || accessDetails?.type === 'free' ? (
<PriceUnit <PriceUnit
price={`${price.value}`} price={`${accessDetails.price}`}
symbol={price.oceanSymbol} symbol={accessDetails.baseToken?.symbol}
className={className} className={className}
small={small} small={small}
conversion={conversion} conversion={conversion}
type={price.type} type={accessDetails.type}
/> />
) : !price || price?.type === '' ? ( ) : !accessDetails || accessDetails?.type === '' ? (
<div className={styles.empty}> <div className={styles.empty}>
No price set{' '} No price set{' '}
<Tooltip content="No pricing mechanism has been set on this asset yet." /> <Tooltip content="No pricing mechanism has been set on this asset yet." />

View File

@ -18,12 +18,12 @@ export default function TokenApproval({
tokenAddress: string tokenAddress: string
tokenSymbol: string tokenSymbol: string
}): ReactElement { }): ReactElement {
const { price, isAssetNetwork } = useAsset() const { accessDetails, isAssetNetwork } = useAsset()
const [tokenApproved, setTokenApproved] = useState(false) const [tokenApproved, setTokenApproved] = useState(false)
const [loading, setLoading] = useState(false) const [loading, setLoading] = useState(false)
const { web3, accountId } = useWeb3() const { web3, accountId } = useWeb3()
const spender = price?.address const spender = accessDetails?.addressOrId
const checkTokenApproval = useCallback(async () => { const checkTokenApproval = useCallback(async () => {
if (!web3 || !tokenAddress || !spender || !isAssetNetwork || !amount) return if (!web3 || !tokenAddress || !spender || !isAssetNetwork || !amount) return

View File

@ -11,13 +11,15 @@ import { useAsset } from '@context/Asset'
export default function WalletNetworkSwitcher(): ReactElement { export default function WalletNetworkSwitcher(): ReactElement {
const { networkId, web3Provider } = useWeb3() const { networkId, web3Provider } = useWeb3()
const { ddo } = useAsset() const { assetExtended } = useAsset()
const { networksList } = useNetworkMetadata() const { networksList } = useNetworkMetadata()
const ddoNetworkData = getNetworkDataById(networksList, ddo.chainId) const ddoNetworkData = getNetworkDataById(networksList, assetExtended.chainId)
const walletNetworkData = getNetworkDataById(networksList, networkId) const walletNetworkData = getNetworkDataById(networksList, networkId)
const ddoNetworkName = ( const ddoNetworkName = (
<strong>{getNetworkDisplayName(ddoNetworkData, ddo.chainId)}</strong> <strong>
{getNetworkDisplayName(ddoNetworkData, assetExtended.chainId)}
</strong>
) )
const walletNetworkName = ( const walletNetworkName = (
<strong>{getNetworkDisplayName(walletNetworkData, networkId)}</strong> <strong>{getNetworkDisplayName(walletNetworkData, networkId)}</strong>
@ -25,7 +27,7 @@ export default function WalletNetworkSwitcher(): ReactElement {
async function switchWalletNetwork() { async function switchWalletNetwork() {
const networkNode = await networksList.find( const networkNode = await networksList.find(
(data) => data.chainId === ddo.chainId (data) => data.chainId === assetExtended.chainId
) )
addCustomNetwork(web3Provider, networkNode) addCustomNetwork(web3Provider, networkNode)
} }

View File

@ -32,7 +32,7 @@ export default function FormStartCompute({
selectedComputeAssetType, selectedComputeAssetType,
selectedComputeAssetTimeout, selectedComputeAssetTimeout,
stepText, stepText,
algorithmPrice, algorithmConsumeDetails,
isConsumable, isConsumable,
consumableFeedback consumableFeedback
}: { }: {
@ -56,14 +56,14 @@ export default function FormStartCompute({
selectedComputeAssetType?: string selectedComputeAssetType?: string
selectedComputeAssetTimeout?: string selectedComputeAssetTimeout?: string
stepText: string stepText: string
algorithmPrice: BestPrice algorithmConsumeDetails: AccessDetails
isConsumable: boolean isConsumable: boolean
consumableFeedback: string consumableFeedback: string
}): ReactElement { }): ReactElement {
const { isValid, values }: FormikContextType<{ algorithm: string }> = const { isValid, values }: FormikContextType<{ algorithm: string }> =
useFormikContext() useFormikContext()
const { price, ddo, isAssetNetwork } = useAsset() const { accessDetails, assetExtended, isAssetNetwork } = useAsset()
const [totalPrice, setTotalPrice] = useState(price?.value) const [totalPrice, setTotalPrice] = useState(accessDetails?.price)
const [isBalanceSufficient, setIsBalanceSufficient] = useState<boolean>(false) const [isBalanceSufficient, setIsBalanceSufficient] = useState<boolean>(false)
const { accountId, balance } = useWeb3() const { accountId, balance } = useWeb3()
const [algorithmConsumableStatus, setAlgorithmConsumableStatus] = const [algorithmConsumableStatus, setAlgorithmConsumableStatus] =
@ -97,19 +97,19 @@ export default function FormStartCompute({
// Set price for calculation output // Set price for calculation output
// //
useEffect(() => { useEffect(() => {
if (!price || !algorithmPrice) return if (!accessDetails || !algorithmConsumeDetails) return
const priceDataset = const priceDataset =
hasPreviousOrder || hasDatatoken ? 0 : Number(price.value) hasPreviousOrder || hasDatatoken ? 0 : Number(accessDetails.price)
const priceAlgo = const priceAlgo =
hasPreviousOrderSelectedComputeAsset || hasDatatokenSelectedComputeAsset hasPreviousOrderSelectedComputeAsset || hasDatatokenSelectedComputeAsset
? 0 ? 0
: Number(algorithmPrice.value) : Number(algorithmConsumeDetails.price)
setTotalPrice(priceDataset + priceAlgo) setTotalPrice(priceDataset + priceAlgo)
}, [ }, [
price, accessDetails,
algorithmPrice, algorithmConsumeDetails,
hasPreviousOrder, hasPreviousOrder,
hasDatatoken, hasDatatoken,
hasPreviousOrderSelectedComputeAsset, hasPreviousOrderSelectedComputeAsset,
@ -143,7 +143,7 @@ export default function FormStartCompute({
hasDatatoken={hasDatatoken} hasDatatoken={hasDatatoken}
selectedComputeAssetTimeout={selectedComputeAssetTimeout} selectedComputeAssetTimeout={selectedComputeAssetTimeout}
hasDatatokenSelectedComputeAsset={hasDatatokenSelectedComputeAsset} hasDatatokenSelectedComputeAsset={hasDatatokenSelectedComputeAsset}
algorithmPrice={algorithmPrice} algorithmConsumeDetails={algorithmConsumeDetails}
symbol={oceanSymbol} symbol={oceanSymbol}
totalPrice={totalPrice} totalPrice={totalPrice}
/> />
@ -159,7 +159,7 @@ export default function FormStartCompute({
} }
hasPreviousOrder={hasPreviousOrder} hasPreviousOrder={hasPreviousOrder}
hasDatatoken={hasDatatoken} hasDatatoken={hasDatatoken}
dtSymbol={ddo?.datatokens[0]?.symbol} dtSymbol={assetExtended?.datatokens[0]?.symbol}
dtBalance={dtBalance} dtBalance={dtBalance}
datasetLowPoolLiquidity={datasetLowPoolLiquidity} datasetLowPoolLiquidity={datasetLowPoolLiquidity}
assetTimeout={assetTimeout} assetTimeout={assetTimeout}
@ -177,8 +177,8 @@ export default function FormStartCompute({
stepText={stepText} stepText={stepText}
isLoading={isLoading} isLoading={isLoading}
type="submit" type="submit"
priceType={price?.type} priceType={accessDetails?.type}
algorithmPriceType={algorithmPrice?.type} algorithmPriceType={algorithmConsumeDetails?.type}
isBalanceSufficient={isBalanceSufficient} isBalanceSufficient={isBalanceSufficient}
isConsumable={isConsumable} isConsumable={isConsumable}
consumableFeedback={consumableFeedback} consumableFeedback={consumableFeedback}

View File

@ -12,7 +12,7 @@ interface PriceOutputProps {
assetTimeout: string assetTimeout: string
hasPreviousOrderSelectedComputeAsset: boolean hasPreviousOrderSelectedComputeAsset: boolean
hasDatatokenSelectedComputeAsset: boolean hasDatatokenSelectedComputeAsset: boolean
algorithmPrice: BestPrice algorithmConsumeDetails: AccessDetails
selectedComputeAssetTimeout: string selectedComputeAssetTimeout: string
} }
@ -60,10 +60,10 @@ export default function PriceOutput({
symbol, symbol,
hasPreviousOrderSelectedComputeAsset, hasPreviousOrderSelectedComputeAsset,
hasDatatokenSelectedComputeAsset, hasDatatokenSelectedComputeAsset,
algorithmPrice, algorithmConsumeDetails,
selectedComputeAssetTimeout selectedComputeAssetTimeout
}: PriceOutputProps): ReactElement { }: PriceOutputProps): ReactElement {
const { price } = useAsset() const { accessDetails } = useAsset()
return ( return (
<div className={styles.priceComponent}> <div className={styles.priceComponent}>
@ -74,14 +74,14 @@ export default function PriceOutput({
<Row <Row
hasPreviousOrder={hasPreviousOrder} hasPreviousOrder={hasPreviousOrder}
hasDatatoken={hasDatatoken} hasDatatoken={hasDatatoken}
price={price?.value} price={accessDetails?.price}
timeout={assetTimeout} timeout={assetTimeout}
symbol={symbol} symbol={symbol}
/> />
<Row <Row
hasPreviousOrder={hasPreviousOrderSelectedComputeAsset} hasPreviousOrder={hasPreviousOrderSelectedComputeAsset}
hasDatatoken={hasDatatokenSelectedComputeAsset} hasDatatoken={hasDatatokenSelectedComputeAsset}
price={algorithmPrice?.value} price={algorithmConsumeDetails?.price}
timeout={selectedComputeAssetTimeout} timeout={selectedComputeAssetTimeout}
symbol={symbol} symbol={symbol}
sign="+" sign="+"

View File

@ -30,16 +30,17 @@ import SuccessConfetti from '@shared/SuccessConfetti'
import { getServiceByName, secondsToString } from '@utils/ddo' import { getServiceByName, secondsToString } from '@utils/ddo'
import { AssetSelectionAsset } from '@shared/FormFields/AssetSelection' import { AssetSelectionAsset } from '@shared/FormFields/AssetSelection'
import AlgorithmDatasetsListForCompute from './AlgorithmDatasetsListForCompute' import AlgorithmDatasetsListForCompute from './AlgorithmDatasetsListForCompute'
import { getPreviousOrders, getPrice } from '@utils/subgraph' import { getPreviousOrders } from '@utils/subgraph'
import AssetActionHistoryTable from '../AssetActionHistoryTable' import AssetActionHistoryTable from '../AssetActionHistoryTable'
import ComputeJobs from '../../../Profile/History/ComputeJobs' import ComputeJobs from '../../../Profile/History/ComputeJobs'
import { useCancelToken } from '@hooks/useCancelToken' import { useCancelToken } from '@hooks/useCancelToken'
import { useIsMounted } from '@hooks/useIsMounted' import { useIsMounted } from '@hooks/useIsMounted'
import { SortTermOptions } from '../../../../@types/aquarius/SearchQuery' import { SortTermOptions } from '../../../../@types/aquarius/SearchQuery'
import { getAccessDetails } from '@utils/accessDetailsAndPricing'
export default function Compute({ export default function Compute({
ddo, ddo,
price, accessDetails,
dtBalance, dtBalance,
file, file,
fileIsLoading, fileIsLoading,
@ -47,7 +48,7 @@ export default function Compute({
consumableFeedback consumableFeedback
}: { }: {
ddo: Asset ddo: Asset
price: BestPrice accessDetails: AccessDetails
dtBalance: string dtBalance: string
file: FileMetadata file: FileMetadata
fileIsLoading?: boolean fileIsLoading?: boolean
@ -70,7 +71,8 @@ export default function Compute({
const [hasPreviousAlgorithmOrder, setHasPreviousAlgorithmOrder] = const [hasPreviousAlgorithmOrder, setHasPreviousAlgorithmOrder] =
useState(false) useState(false)
const [algorithmDTBalance, setalgorithmDTBalance] = useState<string>() const [algorithmDTBalance, setalgorithmDTBalance] = useState<string>()
const [algorithmPrice, setAlgorithmPrice] = useState<BestPrice>() const [algorithmConsumeDetails, setAlgorithmConsumeDetails] =
useState<AccessDetails>()
const [previousAlgorithmOrderId, setPreviousAlgorithmOrderId] = const [previousAlgorithmOrderId, setPreviousAlgorithmOrderId] =
useState<string>() useState<string>()
const [datasetTimeout, setDatasetTimeout] = useState<string>() const [datasetTimeout, setDatasetTimeout] = useState<string>()
@ -169,27 +171,24 @@ export default function Compute({
const initMetadata = useCallback(async (ddo: Asset): Promise<void> => { const initMetadata = useCallback(async (ddo: Asset): Promise<void> => {
if (!ddo) return if (!ddo) return
const price = await getPrice(ddo) const accessDetails = await getAccessDetails(
setAlgorithmPrice(price) ddo.chainId,
ddo.services[0].datatokenAddress
)
setAlgorithmConsumeDetails(accessDetails)
}, []) }, [])
useEffect(() => { useEffect(() => {
if (!algorithmPrice) return if (!algorithmConsumeDetails) return
setIsAlgoConsumablePrice( setIsAlgoConsumablePrice(algorithmConsumeDetails.isConsumable)
algorithmPrice.isConsumable !== undefined }, [algorithmConsumeDetails])
? algorithmPrice.isConsumable === 'true'
: true
)
}, [algorithmPrice])
useEffect(() => { useEffect(() => {
if (!price) return if (!accessDetails) return
setIsConsumablePrice( setIsConsumablePrice(accessDetails.isConsumable)
price.isConsumable !== undefined ? price.isConsumable === 'true' : true }, [accessDetails])
)
}, [price])
// useEffect(() => { // useEffect(() => {
// setDatasetTimeout(secondsToString(timeout)) // setDatasetTimeout(secondsToString(timeout))
@ -392,7 +391,7 @@ export default function Compute({
<> <>
<div className={styles.info}> <div className={styles.info}>
<FileIcon file={file} isLoading={fileIsLoading} small /> <FileIcon file={file} isLoading={fileIsLoading} small />
<Price price={price} conversion /> <Price accessDetails={accessDetails} conversion />
</div> </div>
{ddo.metadata.type === 'algorithm' ? ( {ddo.metadata.type === 'algorithm' ? (
@ -426,7 +425,7 @@ export default function Compute({
assetTimeout={datasetTimeout} assetTimeout={datasetTimeout}
hasPreviousOrderSelectedComputeAsset={hasPreviousAlgorithmOrder} hasPreviousOrderSelectedComputeAsset={hasPreviousAlgorithmOrder}
hasDatatokenSelectedComputeAsset={hasAlgoAssetDatatoken} hasDatatokenSelectedComputeAsset={hasAlgoAssetDatatoken}
oceanSymbol={price ? price.oceanSymbol : ''} oceanSymbol={accessDetails ? accessDetails.baseToken.symbol : ''}
dtSymbolSelectedComputeAsset={ dtSymbolSelectedComputeAsset={
selectedAlgorithmAsset?.datatokens[0]?.symbol selectedAlgorithmAsset?.datatokens[0]?.symbol
} }
@ -435,7 +434,7 @@ export default function Compute({
selectedComputeAssetType="algorithm" selectedComputeAssetType="algorithm"
selectedComputeAssetTimeout={algorithmTimeout} selectedComputeAssetTimeout={algorithmTimeout}
stepText={pricingStepText || 'Starting Compute Job...'} stepText={pricingStepText || 'Starting Compute Job...'}
algorithmPrice={algorithmPrice} algorithmConsumeDetails={algorithmConsumeDetails}
isConsumable={isConsumable} isConsumable={isConsumable}
consumableFeedback={consumableFeedback} consumableFeedback={consumableFeedback}
/> />
@ -447,7 +446,7 @@ export default function Compute({
<SuccessConfetti success="Your job started successfully! Watch the progress below or on your profile." /> <SuccessConfetti success="Your job started successfully! Watch the progress below or on your profile." />
)} )}
</footer> </footer>
{accountId && price?.datatoken && ( {accountId && accessDetails?.datatoken && (
<AssetActionHistoryTable title="Your Compute Jobs"> <AssetActionHistoryTable title="Your Compute Jobs">
<ComputeJobs minimal /> <ComputeJobs minimal />
</AssetActionHistoryTable> </AssetActionHistoryTable>

View File

@ -4,10 +4,6 @@ import FileIcon from '@shared/FileIcon'
import Price from '@shared/Price' import Price from '@shared/Price'
import { useSiteMetadata } from '@hooks/useSiteMetadata' import { useSiteMetadata } from '@hooks/useSiteMetadata'
import { useAsset } from '@context/Asset' import { useAsset } from '@context/Asset'
import { gql } from 'urql'
import { fetchData, getQueryContext } from '@utils/subgraph'
import { OrdersData } from '../../../@types/subgraph/OrdersData'
import BigNumber from 'bignumber.js'
import { useWeb3 } from '@context/Web3' import { useWeb3 } from '@context/Web3'
import { usePricing } from '@hooks/usePricing' import { usePricing } from '@hooks/usePricing'
import { useConsume } from '@hooks/useConsume' import { useConsume } from '@hooks/useConsume'
@ -18,23 +14,9 @@ import styles from './Consume.module.css'
import { useIsMounted } from '@hooks/useIsMounted' import { useIsMounted } from '@hooks/useIsMounted'
import { Asset, FileMetadata } from '@oceanprotocol/lib' import { Asset, FileMetadata } from '@oceanprotocol/lib'
const previousOrderQuery = gql`
query PreviousOrder($id: String!, $account: String!) {
orders(
first: 1
where: { datatoken: $id, payer: $account }
orderBy: createdTimestamp
orderDirection: desc
) {
createdTimestamp
tx
}
}
`
export default function Consume({ export default function Consume({
ddo, ddo,
price, accessDetails,
file, file,
isBalanceSufficient, isBalanceSufficient,
dtBalance, dtBalance,
@ -43,7 +25,7 @@ export default function Consume({
consumableFeedback consumableFeedback
}: { }: {
ddo: Asset ddo: Asset
price: BestPrice accessDetails: AccessDetails
file: FileMetadata file: FileMetadata
isBalanceSufficient: boolean isBalanceSufficient: boolean
dtBalance: string dtBalance: string
@ -63,50 +45,8 @@ export default function Consume({
const [hasDatatoken, setHasDatatoken] = useState(false) const [hasDatatoken, setHasDatatoken] = useState(false)
const [isConsumablePrice, setIsConsumablePrice] = useState(true) const [isConsumablePrice, setIsConsumablePrice] = useState(true)
const [assetTimeout, setAssetTimeout] = useState('') const [assetTimeout, setAssetTimeout] = useState('')
const [data, setData] = useState<OrdersData>()
const isMounted = useIsMounted() const isMounted = useIsMounted()
useEffect(() => {
if (!ddo || !accountId) return
const context = getQueryContext(ddo.chainId)
const variables = {
id: ddo.services[0].datatokenAddress?.toLowerCase(),
account: accountId?.toLowerCase()
}
fetchData(previousOrderQuery, variables, context).then((result: any) => {
isMounted() && setData(result.data)
})
}, [ddo, accountId, hasPreviousOrder, isMounted])
useEffect(() => {
if (
!data ||
!assetTimeout ||
data.orders.length === 0 ||
!accountId ||
!isAssetNetwork
)
return
const lastOrder = data.orders[0]
if (assetTimeout === '0') {
setPreviousOrderId(lastOrder.tx)
setHasPreviousOrder(true)
} else {
const expiry = new BigNumber(lastOrder.createdTimestamp).plus(
assetTimeout
)
const unixTime = new BigNumber(Math.floor(Date.now() / 1000))
if (unixTime.isLessThan(expiry)) {
setPreviousOrderId(lastOrder.tx)
setHasPreviousOrder(true)
} else {
setHasPreviousOrder(false)
}
}
}, [data, assetTimeout, accountId, isAssetNetwork])
useEffect(() => { useEffect(() => {
if (!ddo) return if (!ddo) return
@ -115,12 +55,12 @@ export default function Consume({
}, [ddo]) }, [ddo])
useEffect(() => { useEffect(() => {
if (!price) return if (!accessDetails) return
setIsConsumablePrice( setIsConsumablePrice(accessDetails.isConsumable)
price.isConsumable !== undefined ? price.isConsumable === 'true' : true setHasPreviousOrder(accessDetails.owned)
) setPreviousOrderId(accessDetails.validOrderTx)
}, [price]) }, [accessDetails])
useEffect(() => { useEffect(() => {
setHasDatatoken(Number(dtBalance) >= 1) setHasDatatoken(Number(dtBalance) >= 1)
@ -151,10 +91,10 @@ export default function Consume({
]) ])
async function handleConsume() { async function handleConsume() {
if (!hasPreviousOrder && !hasDatatoken) { // if (!hasPreviousOrder && !hasDatatoken) {
const tx = await buyDT('1', price, ddo) // const tx = await buyDT('1', price, ddo)
if (tx === undefined) return // if (tx === undefined) return
} // }
const error = await consume( const error = await consume(
ddo.id, ddo.id,
ddo.services[0].datatokenAddress, ddo.services[0].datatokenAddress,
@ -188,7 +128,7 @@ export default function Consume({
assetType={ddo?.metadata?.type} assetType={ddo?.metadata?.type}
stepText={consumeStepText || pricingStepText} stepText={consumeStepText || pricingStepText}
isLoading={pricingIsLoading || isLoading} isLoading={pricingIsLoading || isLoading}
priceType={price?.type} priceType={accessDetails?.type}
isConsumable={isConsumable} isConsumable={isConsumable}
isBalanceSufficient={isBalanceSufficient} isBalanceSufficient={isBalanceSufficient}
consumableFeedback={consumableFeedback} consumableFeedback={consumableFeedback}
@ -202,7 +142,7 @@ export default function Consume({
<FileIcon file={file} isLoading={fileIsLoading} /> <FileIcon file={file} isLoading={fileIsLoading} />
</div> </div>
<div className={styles.pricewrapper}> <div className={styles.pricewrapper}>
<Price price={price} conversion /> <Price accessDetails={accessDetails} conversion />
{!isInPurgatory && <PurchaseButton />} {!isInPurgatory && <PurchaseButton />}
</div> </div>
</div> </div>

View File

@ -60,8 +60,14 @@ const initialPoolInfoCreator: Partial<PoolInfoUser> = initialPoolInfoUser
export default function Pool(): ReactElement { export default function Pool(): ReactElement {
const { accountId } = useWeb3() const { accountId } = useWeb3()
const { isInPurgatory, ddo, owner, price, refreshInterval, isAssetNetwork } = const {
useAsset() isInPurgatory,
assetExtended,
owner,
accessDetails,
refreshInterval,
isAssetNetwork
} = useAsset()
const [poolData, setPoolData] = useState<PoolDataPoolData>() const [poolData, setPoolData] = useState<PoolDataPoolData>()
const [poolInfo, setPoolInfo] = useState<PoolInfo>( const [poolInfo, setPoolInfo] = useState<PoolInfo>(
@ -82,11 +88,11 @@ export default function Pool(): ReactElement {
const [fetchInterval, setFetchInterval] = useState<NodeJS.Timeout>() const [fetchInterval, setFetchInterval] = useState<NodeJS.Timeout>()
const fetchAllData = useCallback(async () => { const fetchAllData = useCallback(async () => {
if (!ddo?.chainId || !price?.address || !owner) return if (!assetExtended?.chainId || !accessDetails?.addressOrId || !owner) return
const response = await getPoolData( const response = await getPoolData(
ddo.chainId, assetExtended.chainId,
price.address, accessDetails.addressOrId,
owner, owner,
accountId || '' accountId || ''
) )
@ -101,7 +107,7 @@ export default function Pool(): ReactElement {
LoggerInstance.log('[pool] Fetched pool data:', response.poolData) LoggerInstance.log('[pool] Fetched pool data:', response.poolData)
LoggerInstance.log('[pool] Fetched user data:', response.poolDataUser) LoggerInstance.log('[pool] Fetched user data:', response.poolDataUser)
LoggerInstance.log('[pool] Fetched pool snapshots:', response.poolSnapshots) LoggerInstance.log('[pool] Fetched pool snapshots:', response.poolSnapshots)
}, [ddo?.chainId, price?.address, owner, accountId]) }, [assetExtended?.chainId, accessDetails?.addressOrId, owner, accountId])
// Helper: start interval fetching // Helper: start interval fetching
const initFetchInterval = useCallback(() => { const initFetchInterval = useCallback(() => {
@ -233,7 +239,12 @@ export default function Pool(): ReactElement {
// 3 User Pool Info // 3 User Pool Info
// //
useEffect(() => { useEffect(() => {
if (!poolData || !poolInfo?.totalPoolTokens || !ddo?.chainId || !accountId) if (
!poolData ||
!poolInfo?.totalPoolTokens ||
!assetExtended?.chainId ||
!accountId
)
return return
const poolShare = const poolShare =
@ -299,7 +310,7 @@ export default function Pool(): ReactElement {
poolData, poolData,
poolInfoUser?.poolShares, poolInfoUser?.poolShares,
accountId, accountId,
ddo?.chainId, assetExtended?.chainId,
owner, owner,
poolInfo?.totalPoolTokens poolInfo?.totalPoolTokens
]) ])
@ -317,7 +328,7 @@ export default function Pool(): ReactElement {
{showAdd ? ( {showAdd ? (
<Add <Add
setShowAdd={setShowAdd} setShowAdd={setShowAdd}
poolAddress={price?.address} poolAddress={accessDetails?.addressOrId}
totalPoolTokens={poolInfo?.totalPoolTokens} totalPoolTokens={poolInfo?.totalPoolTokens}
totalBalance={{ totalBalance={{
baseToken: new Decimal(poolData?.baseTokenLiquidity).toString(), baseToken: new Decimal(poolData?.baseTokenLiquidity).toString(),
@ -332,7 +343,7 @@ export default function Pool(): ReactElement {
) : showRemove ? ( ) : showRemove ? (
<Remove <Remove
setShowRemove={setShowRemove} setShowRemove={setShowRemove}
poolAddress={price?.address} poolAddress={accessDetails?.addressOrId}
poolTokens={poolInfoUser?.poolShares} poolTokens={poolInfoUser?.poolShares}
totalPoolTokens={poolInfo?.totalPoolTokens} totalPoolTokens={poolInfo?.totalPoolTokens}
tokenOutAddress={poolInfo?.baseTokenAddress} tokenOutAddress={poolInfo?.baseTokenAddress}
@ -350,17 +361,18 @@ export default function Pool(): ReactElement {
<Tooltip content={content.pool.tooltips.price} /> <Tooltip content={content.pool.tooltips.price} />
<div className={styles.dataTokenLinks}> <div className={styles.dataTokenLinks}>
<ExplorerLink <ExplorerLink
networkId={ddo?.chainId} networkId={assetExtended?.chainId}
path={`address/${price?.address}`} path={`address/${accessDetails?.addressOrId}`}
> >
Pool Pool
</ExplorerLink> </ExplorerLink>
<ExplorerLink <ExplorerLink
networkId={ddo?.chainId} networkId={assetExtended?.chainId}
path={ path={
ddo?.chainId === 2021000 || ddo?.chainId === 1287 assetExtended?.chainId === 2021000 ||
? `tokens/${ddo.services[0].datatokenAddress}` assetExtended?.chainId === 1287
: `token/${ddo.services[0].datatokenAddress}` ? `tokens/${assetExtended.services[0].datatokenAddress}`
: `token/${assetExtended.services[0].datatokenAddress}`
} }
> >
Datatoken Datatoken
@ -466,8 +478,8 @@ export default function Pool(): ReactElement {
<AssetActionHistoryTable title="Your Pool Transactions"> <AssetActionHistoryTable title="Your Pool Transactions">
<PoolTransactions <PoolTransactions
accountId={accountId} accountId={accountId}
poolAddress={price?.address} poolAddress={accessDetails?.addressOrId}
poolChainId={[ddo?.chainId]} poolChainId={[assetExtended?.chainId]}
minimal minimal
/> />
</AssetActionHistoryTable> </AssetActionHistoryTable>

View File

@ -14,19 +14,18 @@ import { useAsset } from '@context/Asset'
import { FormTradeData } from './_types' import { FormTradeData } from './_types'
import { initialValues } from './_constants' import { initialValues } from './_constants'
import content from '../../../../../content/price.json' import content from '../../../../../content/price.json'
import { AssetExtended } from 'src/@types/AssetExtended'
export default function FormTrade({ export default function FormTrade({
ddo, assetExtended,
balance, balance,
maxDt, maxDt,
maxOcean, maxOcean
price
}: { }: {
ddo: Asset assetExtended: AssetExtended
balance: PoolBalance balance: PoolBalance
maxDt: string maxDt: string
maxOcean: string maxOcean: string
price: BestPrice
}): ReactElement { }): ReactElement {
const { accountId } = useWeb3() const { accountId } = useWeb3()
const { isAssetNetwork } = useAsset() const { isAssetNetwork } = useAsset()
@ -111,11 +110,10 @@ export default function FormTrade({
<> <>
{isWarningAccepted ? ( {isWarningAccepted ? (
<Swap <Swap
ddo={ddo} assetExtended={assetExtended}
balance={balance} balance={balance}
maxDt={maxDt} maxDt={maxDt}
maxOcean={maxOcean} maxOcean={maxOcean}
price={price}
setCoin={setCoinFrom} setCoin={setCoinFrom}
setMaximumOcean={setMaximumOcean} setMaximumOcean={setMaximumOcean}
setMaximumDt={setMaximumDt} setMaximumDt={setMaximumDt}

View File

@ -12,24 +12,23 @@ import Decimal from 'decimal.js'
import { useAsset } from '@context/Asset' import { useAsset } from '@context/Asset'
import { FormTradeData, TradeItem } from './_types' import { FormTradeData, TradeItem } from './_types'
import { Asset } from '@oceanprotocol/lib' import { Asset } from '@oceanprotocol/lib'
import { AssetExtended } from 'src/@types/AssetExtended'
Decimal.set({ toExpNeg: -18, precision: 18, rounding: 1 }) Decimal.set({ toExpNeg: -18, precision: 18, rounding: 1 })
export default function Swap({ export default function Swap({
ddo, assetExtended,
maxDt, maxDt,
maxOcean, maxOcean,
balance, balance,
price,
setMaximumDt, setMaximumDt,
setMaximumOcean, setMaximumOcean,
setCoin setCoin
}: { }: {
ddo: Asset assetExtended: AssetExtended
maxDt: string maxDt: string
maxOcean: string maxOcean: string
balance: PoolBalance balance: PoolBalance
price: BestPrice
setMaximumDt: (value: string) => void setMaximumDt: (value: string) => void
setMaximumOcean: (value: string) => void setMaximumOcean: (value: string) => void
setCoin: (value: string) => void setCoin: (value: string) => void
@ -37,12 +36,12 @@ export default function Swap({
const { isAssetNetwork } = useAsset() const { isAssetNetwork } = useAsset()
const [oceanItem, setOceanItem] = useState<TradeItem>({ const [oceanItem, setOceanItem] = useState<TradeItem>({
amount: '0', amount: '0',
token: price.oceanSymbol, token: assetExtended.accessDetails.baseToken?.symbol,
maxAmount: '0' maxAmount: '0'
}) })
const [dtItem, setDtItem] = useState<TradeItem>({ const [dtItem, setDtItem] = useState<TradeItem>({
amount: '0', amount: '0',
token: ddo.datatokens[0].symbol, token: assetExtended.accessDetails.datatoken.symbol,
maxAmount: '0' maxAmount: '0'
}) })
@ -59,7 +58,7 @@ export default function Swap({
const [tokenAmount, setTokenAmount] = useState<string>() const [tokenAmount, setTokenAmount] = useState<string>()
useEffect(() => { useEffect(() => {
if (!ddo || !balance || !values?.type || !price) return if (!assetExtended || !balance || !values?.type) return
async function calculateMaximum() { async function calculateMaximum() {
const amountDataToken = const amountDataToken =
@ -115,11 +114,10 @@ export default function Swap({
} }
calculateMaximum() calculateMaximum()
}, [ }, [
ddo, assetExtended,
maxOcean, maxOcean,
maxDt, maxDt,
balance, balance,
price,
values?.type, values?.type,
setMaximumDt, setMaximumDt,
setMaximumOcean setMaximumOcean
@ -127,7 +125,9 @@ export default function Swap({
const switchTokens = () => { const switchTokens = () => {
setFieldValue('type', values.type === 'buy' ? 'sell' : 'buy') setFieldValue('type', values.type === 'buy' ? 'sell' : 'buy')
setCoin(values.type === 'sell' ? 'OCEAN' : ddo.datatokens[0].symbol) setCoin(
values.type === 'sell' ? 'OCEAN' : assetExtended.datatokens[0].symbol
)
// don't reset form because we don't want to reset type // don't reset form because we don't want to reset type
setFieldValue('datatoken', 0) setFieldValue('datatoken', 0)
setFieldValue('ocean', 0) setFieldValue('ocean', 0)
@ -223,7 +223,7 @@ export default function Swap({
<Output <Output
dtSymbol={dtItem.token} dtSymbol={dtItem.token}
oceanSymbol={oceanItem.token} oceanSymbol={oceanItem.token}
poolAddress={price?.address} poolAddress={assetExtended.accessDetails?.addressOrId}
/> />
<PriceImpact <PriceImpact

View File

@ -2,8 +2,6 @@ import React, { ReactElement, useEffect, useState } from 'react'
import FormTrade from './FormTrade' import FormTrade from './FormTrade'
import { useAsset } from '@context/Asset' import { useAsset } from '@context/Asset'
import { useWeb3 } from '@context/Web3' import { useWeb3 } from '@context/Web3'
import { isValidNumber } from '@utils/numbers'
import Decimal from 'decimal.js' import Decimal from 'decimal.js'
import { Datatoken } from '@oceanprotocol/lib' import { Datatoken } from '@oceanprotocol/lib'
@ -13,7 +11,7 @@ export default function Trade(): ReactElement {
const { accountId, balance, web3 } = useWeb3() const { accountId, balance, web3 } = useWeb3()
const { isAssetNetwork } = useAsset() const { isAssetNetwork } = useAsset()
const [tokenBalance, setTokenBalance] = useState<PoolBalance>() const [tokenBalance, setTokenBalance] = useState<PoolBalance>()
const { price, ddo } = useAsset() const { assetExtended } = useAsset()
const [maxDt, setMaxDt] = useState('0') const [maxDt, setMaxDt] = useState('0')
const [maxOcean, setMaxOcean] = useState('0') const [maxOcean, setMaxOcean] = useState('0')
@ -25,14 +23,14 @@ export default function Trade(): ReactElement {
!isAssetNetwork || !isAssetNetwork ||
!balance?.ocean || !balance?.ocean ||
!accountId || !accountId ||
!ddo?.services[0].datatokenAddress !assetExtended?.services[0].datatokenAddress
) )
return return
async function getTokenBalance() { async function getTokenBalance() {
const datatokenInstance = new Datatoken(web3) const datatokenInstance = new Datatoken(web3)
const dtBalance = await datatokenInstance.balance( const dtBalance = await datatokenInstance.balance(
ddo.services[0].datatokenAddress, assetExtended.services[0].datatokenAddress,
accountId accountId
) )
setTokenBalance({ setTokenBalance({
@ -41,11 +39,16 @@ export default function Trade(): ReactElement {
}) })
} }
getTokenBalance() getTokenBalance()
}, [web3, balance.ocean, accountId, ddo, isAssetNetwork]) }, [web3, balance.ocean, accountId, assetExtended, isAssetNetwork])
// Get maximum amount for either OCEAN or datatoken // Get maximum amount for either OCEAN or datatoken
useEffect(() => { useEffect(() => {
if (!isAssetNetwork || !price || price.value === 0) return if (
!isAssetNetwork ||
!assetExtended.accessDetails ||
assetExtended.accessDetails.price === 0
)
return
async function getMaximum() { async function getMaximum() {
// const maxTokensInPool = await ocean.pool.getDTMaxBuyQuantity( // const maxTokensInPool = await ocean.pool.getDTMaxBuyQuantity(
@ -66,12 +69,11 @@ export default function Trade(): ReactElement {
// ) // )
} }
getMaximum() getMaximum()
}, [isAssetNetwork, balance.ocean, price]) }, [isAssetNetwork, balance.ocean, assetExtended])
return ( return (
<FormTrade <FormTrade
ddo={ddo} assetExtended={assetExtended}
price={price}
balance={tokenBalance} balance={tokenBalance}
maxDt={maxDt} maxDt={maxDt}
maxOcean={maxOcean} maxOcean={maxOcean}

View File

@ -24,10 +24,10 @@ import { FormPublishData } from 'src/components/Publish/_types'
export default function AssetActions({ export default function AssetActions({
ddo, ddo,
price accessDetails
}: { }: {
ddo: Asset ddo: Asset
price: BestPrice accessDetails: AccessDetails
}): ReactElement { }): ReactElement {
const { accountId, balance, web3 } = useWeb3() const { accountId, balance, web3 } = useWeb3()
const { isAssetNetwork } = useAsset() const { isAssetNetwork } = useAsset()
@ -112,22 +112,24 @@ export default function AssetActions({
// Check user balance against price // Check user balance against price
useEffect(() => { useEffect(() => {
if (price?.type === 'free') setIsBalanceSufficient(true) if (accessDetails?.type === 'free') setIsBalanceSufficient(true)
if (!price?.value || !accountId || !balance?.ocean || !dtBalance) return if (!accessDetails?.price || !accountId || !balance?.ocean || !dtBalance)
return
setIsBalanceSufficient( setIsBalanceSufficient(
compareAsBN(balance.ocean, `${price.value}`) || Number(dtBalance) >= 1 compareAsBN(balance.ocean, `${accessDetails.price}`) ||
Number(dtBalance) >= 1
) )
return () => { return () => {
setIsBalanceSufficient(false) setIsBalanceSufficient(false)
} }
}, [balance, accountId, price, dtBalance]) }, [balance, accountId, accessDetails, dtBalance])
const UseContent = isCompute ? ( const UseContent = isCompute ? (
<Compute <Compute
ddo={ddo} ddo={ddo}
price={price} accessDetails={accessDetails}
dtBalance={dtBalance} dtBalance={dtBalance}
file={fileMetadata} file={fileMetadata}
fileIsLoading={fileIsLoading} fileIsLoading={fileIsLoading}
@ -137,7 +139,7 @@ export default function AssetActions({
) : ( ) : (
<Consume <Consume
ddo={ddo} ddo={ddo}
price={price} accessDetails={accessDetails}
dtBalance={dtBalance} dtBalance={dtBalance}
isBalanceSufficient={isBalanceSufficient} isBalanceSufficient={isBalanceSufficient}
file={fileMetadata} file={fileMetadata}
@ -154,17 +156,17 @@ export default function AssetActions({
} }
] ]
price?.type === 'dynamic' && accessDetails?.type === 'dynamic' &&
tabs.push( tabs.push(
{ {
title: 'Pool', title: 'Pool',
content: <Pool />, content: <Pool />,
disabled: !price.datatoken disabled: !accessDetails.datatoken
}, },
{ {
title: 'Trade', title: 'Trade',
content: <Trade />, content: <Trade />,
disabled: !price.datatoken disabled: !accessDetails.datatoken
} }
) )

View File

@ -26,7 +26,7 @@ const getReceipts = gql`
` `
export default function EditHistory(): ReactElement { export default function EditHistory(): ReactElement {
const { ddo } = useAsset() const { assetExtended } = useAsset()
function getUpdateType(type: string): string { function getUpdateType(type: string): string {
switch (type) { switch (type) {
@ -49,17 +49,17 @@ export default function EditHistory(): ReactElement {
const [queryContext, setQueryContext] = useState<OperationContext>() const [queryContext, setQueryContext] = useState<OperationContext>()
useEffect(() => { useEffect(() => {
if (!ddo) return if (!assetExtended) return
const queryContext = getQueryContext(ddo.chainId) const queryContext = getQueryContext(assetExtended.chainId)
setQueryContext(queryContext) setQueryContext(queryContext)
}, [ddo]) }, [assetExtended])
const [result] = useQuery({ const [result] = useQuery({
query: getReceipts, query: getReceipts,
variables: { address: ddo?.nft.address.toLowerCase() }, variables: { address: assetExtended?.nft.address.toLowerCase() },
context: queryContext, context: queryContext,
pause: !ddo || !queryContext pause: !assetExtended || !queryContext
}) })
const { data } = result const { data } = result
@ -80,7 +80,10 @@ export default function EditHistory(): ReactElement {
<ul className={styles.history}> <ul className={styles.history}>
{receipts?.map((receipt) => ( {receipts?.map((receipt) => (
<li key={receipt.id} className={styles.item}> <li key={receipt.id} className={styles.item}>
<ExplorerLink networkId={ddo?.chainId} path={`/tx/${receipt.tx}`}> <ExplorerLink
networkId={assetExtended?.chainId}
path={`/tx/${receipt.tx}`}
>
{getUpdateType(receipt.type)}{' '} {getUpdateType(receipt.type)}{' '}
<Time date={`${receipt.timestamp}`} relative isUnix /> <Time date={`${receipt.timestamp}`} relative isUnix />
</ExplorerLink> </ExplorerLink>

View File

@ -16,11 +16,11 @@ import content from '../../../../content/purgatory.json'
import { Asset } from '@oceanprotocol/lib' import { Asset } from '@oceanprotocol/lib'
export default function AssetContent({ export default function AssetContent({
ddo, asset,
price accessDetails
}: { }: {
ddo: Asset asset: Asset
price: BestPrice accessDetails: AccessDetails
}): ReactElement { }): ReactElement {
const { debug } = useUserPreferences() const { debug } = useUserPreferences()
const { isInPurgatory, purgatoryData } = useAsset() const { isInPurgatory, purgatoryData } = useAsset()
@ -28,14 +28,14 @@ export default function AssetContent({
return ( return (
<> <>
<div className={styles.networkWrap}> <div className={styles.networkWrap}>
<NetworkName networkId={ddo?.chainId} className={styles.network} /> <NetworkName networkId={asset?.chainId} className={styles.network} />
</div> </div>
<article className={styles.grid}> <article className={styles.grid}>
<div> <div>
<div className={styles.content}> <div className={styles.content}>
<MetaMain ddo={ddo} /> <MetaMain ddo={asset} />
{price?.datatoken !== null && <Bookmark did={ddo?.id} />} {accessDetails?.datatoken !== null && <Bookmark did={asset?.id} />}
{isInPurgatory === true ? ( {isInPurgatory === true ? (
<Alert <Alert
@ -48,20 +48,20 @@ export default function AssetContent({
<> <>
<Markdown <Markdown
className={styles.description} className={styles.description}
text={ddo?.metadata.description || ''} text={asset?.metadata.description || ''}
/> />
<MetaSecondary ddo={ddo} /> <MetaSecondary ddo={asset} />
</> </>
)} )}
<MetaFull ddo={ddo} /> <MetaFull ddo={asset} />
<EditHistory /> <EditHistory />
{debug === true && <DebugOutput title="DDO" output={ddo} />} {debug === true && <DebugOutput title="DDO" output={asset} />}
</div> </div>
</div> </div>
<div className={styles.actions}> <div className={styles.actions}>
<AssetActions ddo={ddo} price={price} /> <AssetActions ddo={asset} accessDetails={accessDetails} />
{/* {/*
TODO: restore edit actions, ideally put edit screens on new page TODO: restore edit actions, ideally put edit screens on new page

View File

@ -8,7 +8,6 @@ import { useUserPreferences } from '@context/UserPreferences'
import DebugEditCompute from './DebugEditCompute' import DebugEditCompute from './DebugEditCompute'
import styles from './index.module.css' import styles from './index.module.css'
// import { transformComputeFormToServiceComputePrivacy } from '@utils/compute' // import { transformComputeFormToServiceComputePrivacy } from '@utils/compute'
import { setMinterToDispenser, setMinterToPublisher } from '@utils/freePrice'
import Web3Feedback from '@shared/Web3Feedback' import Web3Feedback from '@shared/Web3Feedback'
import { getInitialValues, validationSchema } from './_constants' import { getInitialValues, validationSchema } from './_constants'
import content from '../../../../content/pages/editComputeDataset.json' import content from '../../../../content/pages/editComputeDataset.json'
@ -20,7 +19,7 @@ export default function EditComputeDataset({
}): ReactElement { }): ReactElement {
const { debug } = useUserPreferences() const { debug } = useUserPreferences()
const { accountId } = useWeb3() const { accountId } = useWeb3()
const { ddo, price, isAssetNetwork, refreshDdo } = useAsset() const { assetExtended, isAssetNetwork, refreshAsset } = useAsset()
const [success, setSuccess] = useState<string>() const [success, setSuccess] = useState<string>()
const [error, setError] = useState<string>() const [error, setError] = useState<string>()
@ -112,7 +111,7 @@ export default function EditComputeDataset({
/> />
</article> </article>
<Web3Feedback <Web3Feedback
networkId={ddo?.chainId} networkId={assetExtended?.chainId}
isAssetNetwork={isAssetNetwork} isAssetNetwork={isAssetNetwork}
/> />
{debug === true && ( {debug === true && (

View File

@ -28,12 +28,12 @@ export default function FormEditComputeDataset({
setShowEdit: (show: boolean) => void setShowEdit: (show: boolean) => void
}): ReactElement { }): ReactElement {
const { appConfig } = useSiteMetadata() const { appConfig } = useSiteMetadata()
const { ddo } = useAsset() const { assetExtended } = useAsset()
const { values }: FormikContextType<ComputePrivacyForm> = useFormikContext() const { values }: FormikContextType<ComputePrivacyForm> = useFormikContext()
const [allAlgorithms, setAllAlgorithms] = useState<AssetSelectionAsset[]>() const [allAlgorithms, setAllAlgorithms] = useState<AssetSelectionAsset[]>()
const newCancelToken = useCancelToken() const newCancelToken = useCancelToken()
const { publisherTrustedAlgorithms } = getServiceByName( const { publisherTrustedAlgorithms } = getServiceByName(
ddo, assetExtended,
'compute' 'compute'
).compute ).compute
@ -41,14 +41,14 @@ export default function FormEditComputeDataset({
publisherTrustedAlgorithms: PublisherTrustedAlgorithm[] publisherTrustedAlgorithms: PublisherTrustedAlgorithm[]
): Promise<AssetSelectionAsset[]> { ): Promise<AssetSelectionAsset[]> {
const baseParams = { const baseParams = {
chainIds: [ddo.chainId], chainIds: [assetExtended.chainId],
sort: { sortBy: SortTermOptions.Created }, sort: { sortBy: SortTermOptions.Created },
filters: [getFilterTerm('service.attributes.main.type', 'algorithm')] filters: [getFilterTerm('service.attributes.main.type', 'algorithm')]
} as BaseQueryParams } as BaseQueryParams
const query = generateBaseQuery(baseParams) const query = generateBaseQuery(baseParams)
const querryResult = await queryMetadata(query, newCancelToken()) const querryResult = await queryMetadata(query, newCancelToken())
const datasetComputeService = getServiceByName(ddo, 'compute') const datasetComputeService = getServiceByName(assetExtended, 'compute')
const algorithmSelectionList = await transformDDOToAssetSelection( const algorithmSelectionList = await transformDDOToAssetSelection(
datasetComputeService?.serviceEndpoint, datasetComputeService?.serviceEndpoint,
querryResult.results, querryResult.results,

View File

@ -10,7 +10,6 @@ import { getServiceByName, mapTimeoutStringToSeconds } from '@utils/ddo'
import styles from './index.module.css' import styles from './index.module.css'
import { LoggerInstance } from '@oceanprotocol/lib' import { LoggerInstance } from '@oceanprotocol/lib'
import { useWeb3 } from '@context/Web3' import { useWeb3 } from '@context/Web3'
import { setMinterToDispenser, setMinterToPublisher } from '@utils/freePrice'
import content from '../../../../content/pages/edit.json' import content from '../../../../content/pages/edit.json'
import { MetadataEditForm } from './_types' import { MetadataEditForm } from './_types'
@ -23,11 +22,11 @@ export default function Edit({
}): ReactElement { }): ReactElement {
const { debug } = useUserPreferences() const { debug } = useUserPreferences()
const { accountId } = useWeb3() const { accountId } = useWeb3()
const { ddo, refreshDdo, price } = useAsset() const { assetExtended, refreshAsset, accessDetails } = useAsset()
const [success, setSuccess] = useState<string>() const [success, setSuccess] = useState<string>()
const [error, setError] = useState<string>() const [error, setError] = useState<string>()
const [timeoutStringValue, setTimeoutStringValue] = useState<string>() const [timeoutStringValue, setTimeoutStringValue] = useState<string>()
const { timeout } = ddo.services[0] const { timeout } = assetExtended.services[0]
const hasFeedback = error || success const hasFeedback = error || success
@ -119,7 +118,11 @@ export default function Edit({
return ( return (
<Formik <Formik
initialValues={getInitialValues(ddo.metadata, timeout, price.value)} initialValues={getInitialValues(
assetExtended.metadata,
timeout,
accessDetails.price
)}
validationSchema={validationSchema} validationSchema={validationSchema}
onSubmit={async (values, { resetForm }) => { onSubmit={async (values, { resetForm }) => {
// move user's focus to top of screen // move user's focus to top of screen
@ -145,7 +148,7 @@ export default function Edit({
/> */} /> */}
<aside> <aside>
<Web3Feedback networkId={ddo?.chainId} /> <Web3Feedback networkId={assetExtended?.chainId} />
</aside> </aside>
{/* {debug === true && <Debug values={values} ddo={ddo} />} */} {/* {debug === true && <Debug values={values} ddo={ddo} />} */}

View File

@ -6,20 +6,21 @@ import { useAsset } from '@context/Asset'
import AssetContent from './AssetContent' import AssetContent from './AssetContent'
export default function AssetDetails({ uri }: { uri: string }): ReactElement { export default function AssetDetails({ uri }: { uri: string }): ReactElement {
const { ddo, title, error, isInPurgatory, loading, price } = useAsset() const { assetExtended, title, error, isInPurgatory, loading, accessDetails } =
useAsset()
const [pageTitle, setPageTitle] = useState<string>() const [pageTitle, setPageTitle] = useState<string>()
useEffect(() => { useEffect(() => {
if (!ddo || error) { if (!assetExtended || error) {
setPageTitle('Could not retrieve asset') setPageTitle('Could not retrieve asset')
return return
} }
setPageTitle(isInPurgatory ? '' : title) setPageTitle(isInPurgatory ? '' : title)
}, [ddo, error, isInPurgatory, title]) }, [assetExtended, error, isInPurgatory, title])
return ddo && pageTitle !== undefined && !loading ? ( return assetExtended && pageTitle !== undefined && !loading ? (
<Page title={pageTitle} uri={uri}> <Page title={pageTitle} uri={uri}>
<AssetContent ddo={ddo} price={price} /> <AssetContent asset={assetExtended} accessDetails={accessDetails} />
</Page> </Page>
) : error ? ( ) : error ? (
<Page title={pageTitle} noPageHeader uri={uri}> <Page title={pageTitle} noPageHeader uri={uri}>

View File

@ -6,27 +6,29 @@ import Price from '@shared/Price'
import Tooltip from '@shared/atoms/Tooltip' import Tooltip from '@shared/atoms/Tooltip'
import AssetTitle from '@shared/AssetList/AssetListTitle' import AssetTitle from '@shared/AssetList/AssetListTitle'
import { retrieveDDOListByDIDs } from '@utils/aquarius' import { retrieveDDOListByDIDs } from '@utils/aquarius'
import { getAssetsBestPrices, AssetListPrices } from '@utils/subgraph'
import { CancelToken } from 'axios' import { CancelToken } from 'axios'
import { useSiteMetadata } from '@hooks/useSiteMetadata' import { useSiteMetadata } from '@hooks/useSiteMetadata'
import { useCancelToken } from '@hooks/useCancelToken' import { useCancelToken } from '@hooks/useCancelToken'
import { AssetExtended } from 'src/@types/AssetExtended'
import { getAccessDetailsForAssets } from '@utils/accessDetailsAndPricing'
import { useWeb3 } from '@context/Web3'
const columns = [ const columns = [
{ {
name: 'Data Set', name: 'Data Set',
selector: function getAssetRow(row: AssetListPrices) { selector: function getAssetRow(row: AssetExtended) {
const { metadata } = row.ddo const { metadata } = row
return <AssetTitle title={metadata.name} ddo={row.ddo} /> return <AssetTitle title={metadata.name} asset={row} />
}, },
maxWidth: '45rem', maxWidth: '45rem',
grow: 1 grow: 1
}, },
{ {
name: 'Datatoken Symbol', name: 'Datatoken Symbol',
selector: function getAssetRow(row: AssetListPrices) { selector: function getAssetRow(row: AssetExtended) {
return ( return (
<Tooltip content={row.ddo.datatokens[0].name}> <Tooltip content={row.datatokens[0].name}>
{row.ddo.datatokens[0].symbol} {row.datatokens[0].symbol}
</Tooltip> </Tooltip>
) )
}, },
@ -34,8 +36,8 @@ const columns = [
}, },
{ {
name: 'Price', name: 'Price',
selector: function getAssetRow(row: AssetListPrices) { selector: function getAssetRow(row: AssetExtended) {
return <Price price={row.price} small /> return <Price accessDetails={row.accessDetails} small />
}, },
right: true right: true
} }
@ -43,9 +45,10 @@ const columns = [
export default function Bookmarks(): ReactElement { export default function Bookmarks(): ReactElement {
const { appConfig } = useSiteMetadata() const { appConfig } = useSiteMetadata()
const { accountId } = useWeb3()
const { bookmarks } = useUserPreferences() const { bookmarks } = useUserPreferences()
const [pinned, setPinned] = useState<AssetListPrices[]>() const [pinned, setPinned] = useState<AssetExtended[]>()
const [isLoading, setIsLoading] = useState<boolean>() const [isLoading, setIsLoading] = useState<boolean>()
const { chainIds } = useUserPreferences() const { chainIds } = useUserPreferences()
const newCancelToken = useCancelToken() const newCancelToken = useCancelToken()
@ -87,8 +90,9 @@ export default function Bookmarks(): ReactElement {
chainIds, chainIds,
newCancelToken() newCancelToken()
) )
const pinnedAssets: AssetListPrices[] = await getAssetsBestPrices( const pinnedAssets: AssetExtended[] = await getAccessDetailsForAssets(
resultPinned resultPinned,
accountId
) )
setPinned(pinnedAssets) setPinned(pinnedAssets)
} catch (error) { } catch (error) {
@ -102,6 +106,7 @@ export default function Bookmarks(): ReactElement {
appConfig?.metadataCacheUri, appConfig?.metadataCacheUri,
bookmarks, bookmarks,
chainIds, chainIds,
accountId,
getAssetsBookmarked, getAssetsBookmarked,
newCancelToken newCancelToken
]) ])

View File

@ -53,7 +53,7 @@ function SectionQueryResult({
queryData?: string[] queryData?: string[]
}) { }) {
const { chainIds } = useUserPreferences() const { chainIds } = useUserPreferences()
const [result, setResult] = useState<any>() const [result, setResult] = useState<PagedAssets>()
const [loading, setLoading] = useState<boolean>() const [loading, setLoading] = useState<boolean>()
const isMounted = useIsMounted() const isMounted = useIsMounted()
const newCancelToken = useCancelToken() const newCancelToken = useCancelToken()

View File

@ -3,7 +3,6 @@ import React, { useEffect, useState, ReactElement } from 'react'
import { useUserPreferences } from '@context/UserPreferences' import { useUserPreferences } from '@context/UserPreferences'
import { import {
getAccountLiquidityInOwnAssets, getAccountLiquidityInOwnAssets,
getAssetsBestPrices,
UserLiquidity, UserLiquidity,
calculateUserLiquidity calculateUserLiquidity
} from '@utils/subgraph' } from '@utils/subgraph'
@ -12,6 +11,7 @@ import NumberUnit from './NumberUnit'
import styles from './Stats.module.css' import styles from './Stats.module.css'
import { useProfile } from '@context/Profile' import { useProfile } from '@context/Profile'
import { PoolShares_poolShares as PoolShare } from '../../../@types/subgraph/PoolShares' import { PoolShares_poolShares as PoolShare } from '../../../@types/subgraph/PoolShares'
import { getAccessDetailsForAssets } from '@utils/accessDetailsAndPricing'
async function getPoolSharesLiquidity( async function getPoolSharesLiquidity(
poolShares: PoolShare[] poolShares: PoolShare[]
@ -50,10 +50,12 @@ export default function Stats({
async function getPublisherLiquidity() { async function getPublisherLiquidity() {
try { try {
const accountPoolAdresses: string[] = [] const accountPoolAdresses: string[] = []
const assetsPrices = await getAssetsBestPrices(assets) const assetsPrices = await getAccessDetailsForAssets(assets)
for (const priceInfo of assetsPrices) { for (const priceInfo of assetsPrices) {
if (priceInfo.price.type === 'dynamic') { if (priceInfo.accessDetails.type === 'dynamic') {
accountPoolAdresses.push(priceInfo.price.address.toLowerCase()) accountPoolAdresses.push(
priceInfo.accessDetails.addressOrId.toLowerCase()
)
} }
} }
const userLiquidity = await getAccountLiquidityInOwnAssets( const userLiquidity = await getAccountLiquidityInOwnAssets(

View File

@ -3,7 +3,7 @@ import Time from '@shared/atoms/Time'
import Button from '@shared/atoms/Button' import Button from '@shared/atoms/Button'
import Modal from '@shared/atoms/Modal' import Modal from '@shared/atoms/Modal'
import External from '@images/external.svg' import External from '@images/external.svg'
import { retrieveDDO } from '@utils/aquarius' import { retrieveAsset } from '@utils/aquarius'
import Results from './Results' import Results from './Results'
import styles from './Details.module.css' import styles from './Details.module.css'
import { useCancelToken } from '@hooks/useCancelToken' import { useCancelToken } from '@hooks/useCancelToken'
@ -46,7 +46,7 @@ function DetailsAssets({ job }: { job: ComputeJobMetaData }) {
const newCancelToken = useCancelToken() const newCancelToken = useCancelToken()
useEffect(() => { useEffect(() => {
async function getAlgoMetadata() { async function getAlgoMetadata() {
const ddo = await retrieveDDO(job.algoDID, newCancelToken()) const ddo = await retrieveAsset(job.algoDID, newCancelToken())
setAlgoDtSymbol(ddo.datatokens[0].symbol) setAlgoDtSymbol(ddo.datatokens[0].symbol)
setAlgoName(ddo?.metadata.name) setAlgoName(ddo?.metadata.name)
} }

View File

@ -74,7 +74,7 @@ export default function ComputeJobs({
minimal?: boolean minimal?: boolean
}): ReactElement { }): ReactElement {
const { accountId, networkId } = useWeb3() const { accountId, networkId } = useWeb3()
const { ddo } = useAsset() const { assetExtended } = useAsset()
const { chainIds } = useUserPreferences() const { chainIds } = useUserPreferences()
const [isLoading, setIsLoading] = useState(false) const [isLoading, setIsLoading] = useState(false)
const [jobs, setJobs] = useState<ComputeJobMetaData[]>([]) const [jobs, setJobs] = useState<ComputeJobMetaData[]>([])
@ -96,7 +96,7 @@ export default function ComputeJobs({
} catch (error) { } catch (error) {
LoggerInstance.error(error.message) LoggerInstance.error(error.message)
} }
}, [chainIds, accountId, ddo, isMounted]) }, [chainIds, accountId, assetExtended, isMounted])
useEffect(() => { useEffect(() => {
fetchJobs() fetchJobs()

View File

@ -9,7 +9,7 @@ const columns = [
{ {
name: 'Data Set', name: 'Data Set',
selector: function getAssetRow(row: DownloadedAsset) { selector: function getAssetRow(row: DownloadedAsset) {
return <AssetTitle ddo={row.ddo} /> return <AssetTitle asset={row.asset} />
} }
}, },
{ {

View File

@ -27,7 +27,7 @@ interface AssetPoolShare {
poolShare: PoolShare poolShare: PoolShare
networkId: number networkId: number
createTime: number createTime: number
ddo: Asset asset: Asset
} }
function Liquidity({ row, type }: { row: AssetPoolShare; type: string }) { function Liquidity({ row, type }: { row: AssetPoolShare; type: string }) {
@ -83,7 +83,7 @@ const columns = [
{ {
name: 'Data Set', name: 'Data Set',
selector: function getAssetRow(row: AssetPoolShare) { selector: function getAssetRow(row: AssetPoolShare) {
return <AssetTitle ddo={row.ddo} /> return <AssetTitle asset={row.asset} />
}, },
grow: 2 grow: 2
}, },
@ -140,7 +140,7 @@ async function getPoolSharesAssets(
userLiquidity: userLiquidity, userLiquidity: userLiquidity,
networkId: ddoList[i].chainId, networkId: ddoList[i].chainId,
createTime: data[i].pool.createdTimestamp, createTime: data[i].pool.createdTimestamp,
ddo: ddoList[i] asset: ddoList[i]
}) })
} }
const assets = assetList.sort((a, b) => b.createTime - a.createTime) const assets = assetList.sort((a, b) => b.createTime - a.createTime)

View File

@ -7,24 +7,34 @@ import { transformPublishFormToDdo } from '../_utils'
import { Asset } from '@oceanprotocol/lib' import { Asset } from '@oceanprotocol/lib'
export default function Preview(): ReactElement { export default function Preview(): ReactElement {
const [ddo, setDdo] = useState<Asset>() const [asset, setAsset] = useState<Asset>()
const [price, setPrice] = useState<BestPrice>() const [accessDetails, setAccessDetails] = useState<AccessDetails>()
const { values } = useFormikContext<FormPublishData>() const { values } = useFormikContext<FormPublishData>()
useEffect(() => { useEffect(() => {
async function makeDdo() { async function makeDdo() {
const ddo = await transformPublishFormToDdo(values) const asset = await transformPublishFormToDdo(values)
setDdo(ddo as Asset) setAsset(asset as Asset)
// dummy BestPrice to trigger certain AssetActions // dummy BestPrice to trigger certain AssetActions
const price: BestPrice = { const accessDetails: AccessDetails = {
type: values.pricing.type, type: values.pricing.type,
address: '0x...', addressOrId: '0x...',
value: values.pricing.price, price: values.pricing.price,
pools: [], baseToken: {
oceanSymbol: 'OCEAN' address: '0x..',
name: '',
symbol: ''
},
datatoken: {
address: '0x..',
name: '',
symbol: ''
},
owned: false,
validOrderTx: ''
} }
setPrice(price) setAccessDetails(accessDetails)
} }
makeDdo() makeDdo()
}, [values]) }, [values])
@ -34,7 +44,7 @@ export default function Preview(): ReactElement {
<h2 className={styles.previewTitle}>Preview</h2> <h2 className={styles.previewTitle}>Preview</h2>
<h3 className={styles.assetTitle}>{values.metadata.name}</h3> <h3 className={styles.assetTitle}>{values.metadata.name}</h3>
<AssetContent ddo={ddo} price={price} /> <AssetContent asset={asset} accessDetails={accessDetails} />
</div> </div>
) )
} }

View File

@ -86,7 +86,7 @@ export async function transformPublishFormToDdo(
const did = nftAddress ? generateDid(nftAddress, chainId) : '0x...' const did = nftAddress ? generateDid(nftAddress, chainId) : '0x...'
const currentTime = dateToStringNoMS(new Date()) const currentTime = dateToStringNoMS(new Date())
const isPreview = !datatokenAddress && !nftAddress const isPreview = !datatokenAddress && !nftAddress
console.log('did', did, isPreview)
// Transform from files[0].url to string[] assuming only 1 file // Transform from files[0].url to string[] assuming only 1 file
const filesTransformed = files?.length && const filesTransformed = files?.length &&
files[0].valid && [files[0].url.replace('javascript:', '')] files[0].valid && [files[0].url.replace('javascript:', '')]

View File

@ -6,7 +6,6 @@ import AssetProvider from '@context/Asset'
export default function PageAssetDetails(): ReactElement { export default function PageAssetDetails(): ReactElement {
const router = useRouter() const router = useRouter()
const { did } = router.query const { did } = router.query
return ( return (
<AssetProvider did={did as string}> <AssetProvider did={did as string}>
<PageTemplateAssetDetails uri={router.pathname} /> <PageTemplateAssetDetails uri={router.pathname} />

View File

@ -5,8 +5,8 @@ import { accountTruncate } from '@utils/web3'
import { useWeb3 } from '@context/Web3' import { useWeb3 } from '@context/Web3'
import ProfileProvider from '@context/Profile' import ProfileProvider from '@context/Profile'
import { getEnsAddress, getEnsName } from '@utils/ens' import { getEnsAddress, getEnsName } from '@utils/ens'
import ethereumAddress from 'ethereum-address'
import { useRouter } from 'next/router' import { useRouter } from 'next/router'
import web3 from 'web3'
export default function PageProfile(): ReactElement { export default function PageProfile(): ReactElement {
const router = useRouter() const router = useRouter()
@ -29,7 +29,7 @@ export default function PageProfile(): ReactElement {
const pathAccount = router.query.account as string const pathAccount = router.query.account as string
// Path has ETH addreess // Path has ETH addreess
if (ethereumAddress.isAddress(pathAccount)) { if (web3.utils.isAddress(pathAccount)) {
const finalAccountId = pathAccount || accountId const finalAccountId = pathAccount || accountId
setFinalAccountId(finalAccountId) setFinalAccountId(finalAccountId)

View File

@ -2,9 +2,9 @@ import React, { ReactElement, useState } from 'react'
import Search from '../components/Search' import Search from '../components/Search'
import Page from '@shared/Page' import Page from '@shared/Page'
import { accountTruncate } from '@utils/web3' import { accountTruncate } from '@utils/web3'
import ethereumAddress from 'ethereum-address'
import { MAXIMUM_NUMBER_OF_PAGES_WITH_RESULTS } from '@utils/aquarius' import { MAXIMUM_NUMBER_OF_PAGES_WITH_RESULTS } from '@utils/aquarius'
import { useRouter } from 'next/router' import { useRouter } from 'next/router'
import web3 from 'web3'
export default function PageSearch(): ReactElement { export default function PageSearch(): ReactElement {
const router = useRouter() const router = useRouter()
@ -13,7 +13,7 @@ export default function PageSearch(): ReactElement {
const [totalResults, setTotalResults] = useState<number>() const [totalResults, setTotalResults] = useState<number>()
const [totalPagesNumber, setTotalPagesNumber] = useState<number>() const [totalPagesNumber, setTotalPagesNumber] = useState<number>()
const isETHAddress = ethereumAddress.isAddress(text as string) const isETHAddress = web3.utils.isAddress(text as string)
const searchValue = const searchValue =
(isETHAddress ? accountTruncate(text as string) : text) || (isETHAddress ? accountTruncate(text as string) : text) ||
tags || tags ||