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

Merge pull request #540 from oceanprotocol/issue497-fetch-price-subgraph

Fetch asset price without relying on ddo's price
This commit is contained in:
Bogdan Fazakas 2021-05-13 11:36:06 +03:00 committed by GitHub
commit 48cb9b1840
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 101 additions and 175 deletions

2
package-lock.json generated
View File

@ -18101,7 +18101,7 @@
} }
}, },
"ethereumjs-abi": { "ethereumjs-abi": {
"version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#1a27c59c15ab1e95ee8e5c4ed6ad814c49cc439e", "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#1ce6a1d64235fabe2aaf827fd606def55693508f",
"from": "git+https://github.com/ethereumjs/ethereumjs-abi.git", "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git",
"requires": { "requires": {
"bn.js": "^4.11.8", "bn.js": "^4.11.8",

View File

@ -3,7 +3,6 @@ import {
DDO, DDO,
File as FileMetadata, File as FileMetadata,
Logger, Logger,
ServiceType,
publisherTrustedAlgorithm, publisherTrustedAlgorithm,
BestPrice BestPrice
} from '@oceanprotocol/lib' } from '@oceanprotocol/lib'
@ -37,11 +36,8 @@ import FormStartComputeDataset from './FormComputeDataset'
import styles from './index.module.css' import styles from './index.module.css'
import SuccessConfetti from '../../../atoms/SuccessConfetti' import SuccessConfetti from '../../../atoms/SuccessConfetti'
import Button from '../../../atoms/Button' import Button from '../../../atoms/Button'
import { gql, useQuery } from '@apollo/client'
import { FrePrice } from '../../../../@types/apollo/FrePrice'
import { PoolPrice } from '../../../../@types/apollo/PoolPrice'
import { secondsToString } from '../../../../utils/metadata' import { secondsToString } from '../../../../utils/metadata'
import { getPreviousOrders } from '../../../../utils/subgraph' import { getPreviousOrders, getPrice } from '../../../../utils/subgraph'
const SuccessAction = () => ( const SuccessAction = () => (
<Button style="text" to="/history" size="small"> <Button style="text" to="/history" size="small">
@ -49,23 +45,6 @@ const SuccessAction = () => (
</Button> </Button>
) )
const freQuery = gql`
query AlgorithmFrePrice($datatoken: String) {
fixedRateExchanges(orderBy: id, where: { datatoken: $datatoken }) {
rate
id
}
}
`
const poolQuery = gql`
query AlgorithmPoolPrice($datatoken: String) {
pools(where: { datatokenAddress: $datatoken }) {
spotPrice
consumePrice
}
}
`
export default function Compute({ export default function Compute({
isBalanceSufficient, isBalanceSufficient,
dtBalance, dtBalance,
@ -95,7 +74,6 @@ export default function Compute({
) )
const [algorithmDTBalance, setalgorithmDTBalance] = useState<string>() const [algorithmDTBalance, setalgorithmDTBalance] = useState<string>()
const [algorithmPrice, setAlgorithmPrice] = useState<BestPrice>() const [algorithmPrice, setAlgorithmPrice] = useState<BestPrice>()
const [variables, setVariables] = useState({})
const [ const [
previousAlgorithmOrderId, previousAlgorithmOrderId,
setPreviousAlgorithmOrderId setPreviousAlgorithmOrderId
@ -103,25 +81,6 @@ export default function Compute({
const [datasetTimeout, setDatasetTimeout] = useState<string>() const [datasetTimeout, setDatasetTimeout] = useState<string>()
const [algorithmTimeout, setAlgorithmTimeout] = useState<string>() const [algorithmTimeout, setAlgorithmTimeout] = useState<string>()
/* eslint-disable @typescript-eslint/no-unused-vars */
const {
refetch: refetchFre,
startPolling: startPollingFre,
data: frePrice
} = useQuery<FrePrice>(freQuery, {
variables,
skip: false
})
const {
refetch: refetchPool,
startPolling: startPollingPool,
data: poolPrice
} = useQuery<PoolPrice>(poolQuery, {
variables,
skip: false
})
/* eslint-enable @typescript-eslint/no-unused-vars */
const isComputeButtonDisabled = const isComputeButtonDisabled =
isJobStarting === true || file === null || !ocean || !isBalanceSufficient isJobStarting === true || file === null || !ocean || !isBalanceSufficient
const hasDatatoken = Number(dtBalance) >= 1 const hasDatatoken = Number(dtBalance) >= 1
@ -215,40 +174,10 @@ export default function Compute({
setDatasetTimeout(secondsToString(timeout)) setDatasetTimeout(secondsToString(timeout))
}, [ddo]) }, [ddo])
useEffect(() => {
if (
!frePrice ||
frePrice.fixedRateExchanges.length === 0 ||
algorithmPrice.type !== 'exchange'
)
return
setAlgorithmPrice((prevState) => ({
...prevState,
value: frePrice.fixedRateExchanges[0].rate,
address: frePrice.fixedRateExchanges[0].id
}))
}, [frePrice])
useEffect(() => {
if (
!poolPrice ||
poolPrice.pools.length === 0 ||
algorithmPrice.type !== 'pool'
)
return
setAlgorithmPrice((prevState) => ({
...prevState,
value:
poolPrice.pools[0].consumePrice === '-1'
? poolPrice.pools[0].spotPrice
: poolPrice.pools[0].consumePrice
}))
}, [poolPrice])
const initMetadata = useCallback(async (ddo: DDO): Promise<void> => { const initMetadata = useCallback(async (ddo: DDO): Promise<void> => {
if (!ddo) return if (!ddo) return
setAlgorithmPrice(ddo.price) const price = await getPrice(ddo)
setVariables({ datatoken: ddo?.dataToken.toLowerCase() }) setAlgorithmPrice(price)
}, []) }, [])
useEffect(() => { useEffect(() => {

View File

@ -12,11 +12,9 @@ import { PurgatoryData } from '@oceanprotocol/lib/dist/node/ddo/interfaces/Purga
import getAssetPurgatoryData from '../utils/purgatory' import getAssetPurgatoryData from '../utils/purgatory'
import axios, { CancelToken } from 'axios' import axios, { CancelToken } from 'axios'
import { retrieveDDO } from '../utils/aquarius' import { retrieveDDO } from '../utils/aquarius'
import { getPrice } from '../utils/subgraph'
import { MetadataMarket } from '../@types/MetaData' import { MetadataMarket } from '../@types/MetaData'
import { useOcean } from './Ocean' import { useOcean } from './Ocean'
import { gql, useQuery } from '@apollo/client'
import { PoolPrice } from '../@types/apollo/PoolPrice'
import { FrePrice } from '../@types/apollo/FrePrice'
interface AssetProviderValue { interface AssetProviderValue {
isInPurgatory: boolean isInPurgatory: boolean
@ -33,26 +31,6 @@ interface AssetProviderValue {
refreshDdo: (token?: CancelToken) => Promise<void> refreshDdo: (token?: CancelToken) => Promise<void>
} }
const poolQuery = gql`
query PoolPrice($datatoken: String) {
pools(where: { datatokenAddress: $datatoken }) {
spotPrice
consumePrice
datatokenReserve
oceanReserve
}
}
`
const freQuery = gql`
query FrePrice($datatoken: String) {
fixedRateExchanges(orderBy: id, where: { datatoken: $datatoken }) {
rate
id
}
}
`
const AssetContext = createContext({} as AssetProviderValue) const AssetContext = createContext({} as AssetProviderValue)
const refreshInterval = 10000 // 10 sec. const refreshInterval = 10000 // 10 sec.
@ -75,68 +53,6 @@ function AssetProvider({
const [owner, setOwner] = useState<string>() const [owner, setOwner] = useState<string>()
const [error, setError] = useState<string>() const [error, setError] = useState<string>()
const [type, setType] = useState<MetadataMain['type']>() const [type, setType] = useState<MetadataMain['type']>()
const [variables, setVariables] = useState({})
/* eslint-disable @typescript-eslint/no-unused-vars */
const {
refetch: refetchFre,
startPolling: startPollingFre,
data: frePrice
} = useQuery<FrePrice>(freQuery, {
variables,
skip: false
})
const {
refetch: refetchPool,
startPolling: startPollingPool,
data: poolPrice
} = useQuery<PoolPrice>(poolQuery, {
variables,
skip: false
})
/* eslint-enable @typescript-eslint/no-unused-vars */
// this is not working as expected, thus we need to fetch both pool and fre
// useEffect(() => {
// if (!ddo || !variables || variables === '') return
// if (ddo.price.type === 'exchange') {
// refetchFre(variables)
// startPollingFre(refreshInterval)
// } else {
// refetchPool(variables)
// startPollingPool(refreshInterval)
// }
// }, [ddo, variables])
useEffect(() => {
if (
!frePrice ||
frePrice.fixedRateExchanges.length === 0 ||
price.type !== 'exchange'
)
return
setPrice((prevState) => ({
...prevState,
value: frePrice.fixedRateExchanges[0].rate,
address: frePrice.fixedRateExchanges[0].id
}))
}, [frePrice])
useEffect(() => {
if (!poolPrice || poolPrice.pools.length === 0 || price.type !== 'pool')
return
setPrice((prevState) => ({
...prevState,
value:
poolPrice.pools[0].consumePrice === '-1'
? poolPrice.pools[0].spotPrice
: poolPrice.pools[0].consumePrice,
ocean: poolPrice.pools[0].oceanReserve,
datatoken: poolPrice.pools[0].datatokenReserve,
isConsumable: poolPrice.pools[0].consumePrice === '-1' ? 'false' : 'true'
}))
}, [poolPrice])
const fetchDdo = async (token?: CancelToken) => { const fetchDdo = async (token?: CancelToken) => {
Logger.log('[asset] Init asset, get DDO') Logger.log('[asset] Init asset, get DDO')
@ -201,10 +117,8 @@ function AssetProvider({
const initMetadata = useCallback(async (ddo: DDO): Promise<void> => { const initMetadata = useCallback(async (ddo: DDO): Promise<void> => {
if (!ddo) return if (!ddo) return
// Set price & metadata from DDO first const returnedPrice = await getPrice(ddo)
// TODO Hacky hack, temporary™: set isConsumable to true by default since Aquarius can't be trusted. setPrice({ ...returnedPrice })
setPrice({ ...ddo.price, isConsumable: 'true' })
setVariables({ datatoken: ddo?.dataToken.toLowerCase() })
// Get metadata from DDO // Get metadata from DDO
const { attributes } = ddo.findServiceByType('metadata') const { attributes } = ddo.findServiceByType('metadata')

View File

@ -1,5 +1,5 @@
import { gql, DocumentNode, ApolloQueryResult } from '@apollo/client' import { gql, DocumentNode, ApolloQueryResult } from '@apollo/client'
import { DDO } from '@oceanprotocol/lib' import { DDO, BestPrice } from '@oceanprotocol/lib'
import { getApolloClientInstance } from '../providers/ApolloClientProvider' import { getApolloClientInstance } from '../providers/ApolloClientProvider'
import BigNumber from 'bignumber.js' import BigNumber from 'bignumber.js'
@ -7,8 +7,8 @@ export interface PriceList {
[key: string]: string [key: string]: string
} }
const freQuery = gql` const FreQuery = gql`
query AssetFrePrice($datatoken_in: [String!]) { query AssetsFrePrice($datatoken_in: [String!]) {
fixedRateExchanges(orderBy: id, where: { datatoken_in: $datatoken_in }) { fixedRateExchanges(orderBy: id, where: { datatoken_in: $datatoken_in }) {
rate rate
id id
@ -20,18 +20,40 @@ const freQuery = gql`
} }
` `
const poolQuery = gql` const AssetFreQuery = gql`
query AssetPoolPrice($datatokenAddress_in: [String!]) { query AssetFrePrice($datatoken: String) {
fixedRateExchanges(orderBy: id, where: { datatoken: $datatoken }) {
rate
id
}
}
`
const PoolQuery = gql`
query AssetsPoolPrice($datatokenAddress_in: [String!]) {
pools(where: { datatokenAddress_in: $datatokenAddress_in }) { pools(where: { datatokenAddress_in: $datatokenAddress_in }) {
id
spotPrice spotPrice
consumePrice consumePrice
id
datatokenAddress datatokenAddress
} }
} }
` `
const previousOrderQuery = gql` const AssetPoolPriceQuerry = gql`
query AssetPoolPrice($datatokenAddress: String) {
pools(where: { datatokenAddress: $datatokenAddress }) {
id
spotPrice
consumePrice
datatokenAddress
datatokenReserve
oceanReserve
}
}
`
const PreviousOrderQuery = gql`
query AssetPreviousOrder($id: String!, $account: String!) { query AssetPreviousOrder($id: String!, $account: String!) {
tokenOrders( tokenOrders(
first: 1 first: 1
@ -53,7 +75,8 @@ async function fetchData(
const client = getApolloClientInstance() const client = getApolloClientInstance()
const response = await client.query({ const response = await client.query({
query: query, query: query,
variables: variables variables: variables,
fetchPolicy: 'no-cache'
}) })
return response return response
} catch (error) { } catch (error) {
@ -71,7 +94,7 @@ export async function getPreviousOrders(
account: account account: account
} }
const fetchedPreviousOrders: any = await fetchData( const fetchedPreviousOrders: any = await fetchData(
previousOrderQuery, PreviousOrderQuery,
variables variables
) )
if (fetchedPreviousOrders.data?.tokenOrders?.length === 0) return null if (fetchedPreviousOrders.data?.tokenOrders?.length === 0) return null
@ -105,16 +128,76 @@ export async function getAssetPrices(assets: DDO[]): Promise<PriceList> {
const poolVariables = { const poolVariables = {
datatokenAddress_in: dataTokenList datatokenAddress_in: dataTokenList
} }
const poolPriceResponse: any = await fetchData(poolQuery, poolVariables) const poolPriceResponse: any = await fetchData(PoolQuery, poolVariables)
for (const poolPrice of poolPriceResponse.data?.pools) { for (const poolPrice of poolPriceResponse.data?.pools) {
priceList[didDTMap[poolPrice.datatokenAddress]] = priceList[didDTMap[poolPrice.datatokenAddress]] =
poolPrice.consumePrice === '-1' poolPrice.consumePrice === '-1'
? poolPrice.spotPrice ? poolPrice.spotPrice
: poolPrice.consumePrice : poolPrice.consumePrice
} }
const frePriceResponse: any = await fetchData(freQuery, freVariables) const frePriceResponse: any = await fetchData(FreQuery, freVariables)
for (const frePrice of frePriceResponse.data?.fixedRateExchanges) { for (const frePrice of frePriceResponse.data?.fixedRateExchanges) {
priceList[didDTMap[frePrice.datatoken?.address]] = frePrice.rate priceList[didDTMap[frePrice.datatoken?.address]] = frePrice.rate
} }
return priceList return priceList
} }
export async function getPrice(asset: DDO): Promise<BestPrice> {
const freVariables = {
datatoken: asset?.dataToken.toLowerCase()
}
const poolVariables = {
datatokenAddress: asset?.dataToken.toLowerCase()
}
const poolPriceResponse: any = await fetchData(
AssetPoolPriceQuerry,
poolVariables
)
const frePriceResponse: any = await fetchData(AssetFreQuery, freVariables)
if (poolPriceResponse.data?.pools.length > 0) {
const price: BestPrice = {
type: 'pool',
address: poolPriceResponse.data?.pools[0]?.id,
value:
poolPriceResponse.data?.pools[0]?.consumePrice === '-1'
? poolPriceResponse.data?.pools[0]?.spotPrice
: poolPriceResponse.data?.pools[0]?.consumePrice,
ocean: poolPriceResponse.data?.pools[0]?.oceanReserve,
datatoken: poolPriceResponse.data?.pools[0]?.datatokenReserve,
pools: [poolPriceResponse.data?.pools[0]?.id],
isConsumable:
poolPriceResponse.data?.pools[0]?.consumePrice === '-1'
? 'false'
: 'true'
}
return price
} else if (frePriceResponse.data?.fixedRateExchanges.length > 0) {
// TODO Hacky hack, temporary™: set isConsumable to true for fre assets.
// isConsumable: 'true'
const price: BestPrice = {
type: 'exchange',
value: frePriceResponse.data?.fixedRateExchanges[0]?.rate,
address: frePriceResponse.data?.fixedRateExchanges[0]?.id,
exchange_id: frePriceResponse.data?.fixedRateExchanges[0]?.id,
ocean: 0,
datatoken: 0,
pools: [],
isConsumable: 'true'
}
return price
} else {
const price: BestPrice = {
type: '',
value: 0,
address: '',
exchange_id: '',
ocean: 0,
datatoken: 0,
pools: [],
isConsumable: 'false'
}
return price
}
}