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

Merge pull request #693 from oceanprotocol/poc-urql

Adapt price fetching for multi network using asset chainId and replace apollo with urql
This commit is contained in:
Bogdan Fazakas 2021-07-12 13:04:39 +03:00 committed by GitHub
commit 0acb18dec1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 4669 additions and 2264 deletions

4
.gitignore vendored
View File

@ -13,4 +13,6 @@ public/storybook
.vercel .vercel
repo-metadata.json repo-metadata.json
content/networks-metadata.json content/networks-metadata.json
src/@types/apollo src/@types/apollo
graphql.schema.json
src/@types/graph.types.ts

View File

@ -171,10 +171,10 @@ function Component() {
Most financial data in the market is retrieved with GraphQL from [our own subgraph](https://github.com/oceanprotocol/ocean-subgraph), rendered on top of the initial data coming from Aquarius. Most financial data in the market is retrieved with GraphQL from [our own subgraph](https://github.com/oceanprotocol/ocean-subgraph), rendered on top of the initial data coming from Aquarius.
The app has [Apollo Client](https://www.apollographql.com/docs/react/) setup to query the respective subgraph based on network. In any component this client can be used like so: The app has [Urql Client](https://formidable.com/open-source/urql/docs/basics/react-preact/) setup to query the respective subgraph based on network. In any component this client can be used like so:
```tsx ```tsx
import { gql, useQuery } from '@apollo/client' import { gql, useQuery } from 'urql'
const query = gql` const query = gql`
query PoolLiquidity($id: ID!, $shareId: ID) { query PoolLiquidity($id: ID!, $shareId: ID) {

22
codegen.yml Normal file
View File

@ -0,0 +1,22 @@
overwrite: true
schema: 'https://subgraph.rinkeby.oceanprotocol.com/subgraphs/name/oceanprotocol/ocean-subgraph'
documents:
- './src/utils/subgraph.ts'
- './src/components/pages/History/PoolShares.tsx'
- './src/components/pages/History/Downloads.tsx'
- './src/components/pages/History/ComputeJobs/index.tsx'
- './src/ //Users/bogdanfazakas/Sites/ocean-market/src/components/organisms/AssetContent/EditHistory.tsx'
# - './src/components/organisms/AssetActions/Pool/index.tsx'
- './src/components/organisms/AssetActions/Pool/Graph.tsx'
- './src/components/organisms/AssetActions/Consume.tsx'
- './src/components/molecules/PoolTransactions.tsx'
- './src/components/molecules/MarketStats.tsx'
generates:
./src/@types/graph.types.ts:
plugins:
- 'typescript'
- 'typescript-operations'
- 'typescript-react-apollo'
./graphql.schema.json:
plugins:
- 'introspection'

View File

@ -7,6 +7,9 @@ execSync(`node ./scripts/write-repo-metadata > repo-metadata.json`, {
stdio: 'inherit' stdio: 'inherit'
}) })
// Generate GraphQl typings for urql
// execSync(`npm run graphql:graphTypes`, { stdio: 'inherit' })
// Generate Apollo typings // Generate Apollo typings
execSync(`npm run apollo:codegen`, { stdio: 'inherit' }) execSync(`npm run apollo:codegen`, { stdio: 'inherit' })

6430
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -9,6 +9,7 @@
"build": "gatsby build && cp _redirects public/_redirects", "build": "gatsby build && cp _redirects public/_redirects",
"serve": "serve -s public/", "serve": "serve -s public/",
"jest": "NODE_ENV=test jest -c tests/unit/jest.config.js", "jest": "NODE_ENV=test jest -c tests/unit/jest.config.js",
"test-graphql": "npm run graphql:graphTypes && npm run lint && npm run jest",
"test": "npm run apollo:codegen && npm run lint && npm run jest", "test": "npm run apollo:codegen && npm run lint && npm run jest",
"test:watch": "npm run lint && npm run jest -- --watch", "test:watch": "npm run lint && npm run jest -- --watch",
"lint": "npm run write:repoMetadata && eslint --ignore-path .gitignore --ext .js --ext .ts --ext .tsx . && npm run type-check", "lint": "npm run write:repoMetadata && eslint --ignore-path .gitignore --ext .js --ext .ts --ext .tsx . && npm run type-check",
@ -19,19 +20,20 @@
"storybook:build": "build-storybook -c .storybook -o public/storybook", "storybook:build": "build-storybook -c .storybook -o public/storybook",
"write:repoMetadata": "node ./scripts/write-repo-metadata > repo-metadata.json", "write:repoMetadata": "node ./scripts/write-repo-metadata > repo-metadata.json",
"deploy:s3": "./scripts/deploy-s3.sh", "deploy:s3": "./scripts/deploy-s3.sh",
"postinstall": "husky install",
"apollo:codegen": "apollo client:codegen --target typescript --tsFileExtension=d.ts --outputFlat src/@types/apollo/", "apollo:codegen": "apollo client:codegen --target typescript --tsFileExtension=d.ts --outputFlat src/@types/apollo/",
"postinstall": "husky install" "graphql:graphTypes": "graphql-codegen --config codegen.yml"
}, },
"dependencies": { "dependencies": {
"@apollo/client": "^3.3.19",
"@coingecko/cryptoformat": "^0.4.2", "@coingecko/cryptoformat": "^0.4.2",
"@loadable/component": "^5.15.0", "@loadable/component": "^5.15.0",
"@oceanprotocol/art": "^3.0.0", "@oceanprotocol/art": "^3.0.0",
"@oceanprotocol/lib": "^0.16.2", "@oceanprotocol/lib": "^0.16.4",
"@oceanprotocol/typographies": "^0.1.0", "@oceanprotocol/typographies": "^0.1.0",
"@portis/web3": "^4.0.4", "@portis/web3": "^4.0.4",
"@sindresorhus/slugify": "^2.1.0", "@sindresorhus/slugify": "^2.1.0",
"@tippyjs/react": "^4.2.5", "@tippyjs/react": "^4.2.5",
"@urql/introspection": "^0.3.0",
"@walletconnect/web3-provider": "^1.4.1", "@walletconnect/web3-provider": "^1.4.1",
"axios": "^0.21.1", "axios": "^0.21.1",
"chart.js": "^2.9.4", "chart.js": "^2.9.4",
@ -60,6 +62,7 @@
"gatsby-transformer-remark": "^2.16.1", "gatsby-transformer-remark": "^2.16.1",
"gatsby-transformer-sharp": "^2.12.1", "gatsby-transformer-sharp": "^2.12.1",
"graphql": "14.7.0", "graphql": "14.7.0",
"graphql-schema-typescript": "^1.5.2",
"is-url-superb": "^6.0.0", "is-url-superb": "^6.0.0",
"jwt-decode": "^3.1.2", "jwt-decode": "^3.1.2",
"lodash.debounce": "^4.0.8", "lodash.debounce": "^4.0.8",
@ -81,12 +84,18 @@
"shortid": "^2.2.16", "shortid": "^2.2.16",
"slugify": "^1.5.3", "slugify": "^1.5.3",
"swr": "^0.5.6", "swr": "^0.5.6",
"urql": "^2.0.3",
"use-dark-mode": "^2.3.1", "use-dark-mode": "^2.3.1",
"web3": "^1.3.6", "web3": "^1.3.6",
"web3modal": "^1.9.3", "web3modal": "^1.9.3",
"yup": "^0.32.9" "yup": "^0.32.9"
}, },
"devDependencies": { "devDependencies": {
"@graphql-codegen/cli": "1.21.6",
"@graphql-codegen/introspection": "1.18.2",
"@graphql-codegen/typescript": "1.22.4",
"@graphql-codegen/typescript-operations": "^1.18.3",
"@graphql-codegen/typescript-react-apollo": "2.3.0",
"@svgr/webpack": "^5.5.0", "@svgr/webpack": "^5.5.0",
"@testing-library/jest-dom": "^5.12.0", "@testing-library/jest-dom": "^5.12.0",
"@testing-library/react": "^11.2.7", "@testing-library/react": "^11.2.7",

View File

@ -11,7 +11,7 @@ import { useOcean } from '../../providers/Ocean'
import styles from './AssetTeaser.module.css' import styles from './AssetTeaser.module.css'
declare type AssetTeaserProps = { declare type AssetTeaserProps = {
ddo: any ddo: DDO
price: BestPrice price: BestPrice
} }

View File

@ -1,8 +1,7 @@
import { useUserPreferences } from '../../providers/UserPreferences' import { useUserPreferences } from '../../providers/UserPreferences'
import React, { ReactElement, useEffect, useState } from 'react' import React, { ReactElement, useEffect, useState } from 'react'
import Table from '../atoms/Table' import Table from '../atoms/Table'
import { DDO, Logger, ConfigHelperConfig } from '@oceanprotocol/lib' import { DDO, Logger, BestPrice } from '@oceanprotocol/lib'
import { useOcean } from '../../providers/Ocean'
import Price from '../atoms/Price' import Price from '../atoms/Price'
import Tooltip from '../atoms/Tooltip' import Tooltip from '../atoms/Tooltip'
import AssetTitle from './AssetListTitle' import AssetTitle from './AssetListTitle'
@ -10,6 +9,7 @@ import {
queryMetadata, queryMetadata,
transformChainIdsListToQuery transformChainIdsListToQuery
} from '../../utils/aquarius' } from '../../utils/aquarius'
import { getAssetsBestPrices, AssetListPrices } from '../../utils/subgraph'
import axios, { CancelToken } from 'axios' import axios, { CancelToken } from 'axios'
import { useSiteMetadata } from '../../hooks/useSiteMetadata' import { useSiteMetadata } from '../../hooks/useSiteMetadata'
@ -52,19 +52,19 @@ async function getAssetsBookmarked(
const columns = [ const columns = [
{ {
name: 'Data Set', name: 'Data Set',
selector: function getAssetRow(row: DDO) { selector: function getAssetRow(row: AssetListPrices) {
const { attributes } = row.findServiceByType('metadata') const { attributes } = row.ddo.findServiceByType('metadata')
return <AssetTitle title={attributes.main.name} ddo={row} /> return <AssetTitle title={attributes.main.name} ddo={row.ddo} />
}, },
maxWidth: '45rem', maxWidth: '45rem',
grow: 1 grow: 1
}, },
{ {
name: 'Datatoken Symbol', name: 'Datatoken Symbol',
selector: function getAssetRow(row: DDO) { selector: function getAssetRow(row: AssetListPrices) {
return ( return (
<Tooltip content={row.dataTokenInfo.name}> <Tooltip content={row.ddo.dataTokenInfo.name}>
{row.dataTokenInfo.symbol} {row.ddo.dataTokenInfo.symbol}
</Tooltip> </Tooltip>
) )
}, },
@ -72,7 +72,7 @@ const columns = [
}, },
{ {
name: 'Price', name: 'Price',
selector: function getAssetRow(row: DDO) { selector: function getAssetRow(row: AssetListPrices) {
return <Price price={row.price} small /> return <Price price={row.price} small />
}, },
right: true right: true
@ -83,7 +83,7 @@ export default function Bookmarks(): ReactElement {
const { appConfig } = useSiteMetadata() const { appConfig } = useSiteMetadata()
const { bookmarks } = useUserPreferences() const { bookmarks } = useUserPreferences()
const [pinned, setPinned] = useState<DDO[]>() const [pinned, setPinned] = useState<AssetListPrices[]>()
const [isLoading, setIsLoading] = useState<boolean>() const [isLoading, setIsLoading] = useState<boolean>()
const { chainIds } = useUserPreferences() const { chainIds } = useUserPreferences()
@ -106,7 +106,10 @@ export default function Bookmarks(): ReactElement {
chainIds, chainIds,
source.token source.token
) )
setPinned(resultPinned?.results) const pinnedAssets: AssetListPrices[] = await getAssetsBestPrices(
resultPinned?.results
)
setPinned(pinnedAssets)
} catch (error) { } catch (error) {
Logger.error(error.message) Logger.error(error.message)
} }

View File

@ -1,6 +1,6 @@
import React, { ReactElement, useEffect, useState } from 'react' import React, { ReactElement, useEffect, useState } from 'react'
import styles from './MarketStats.module.css' import styles from './MarketStats.module.css'
import { gql, useQuery } from '@apollo/client' import { gql, useQuery } from 'urql'
import Conversion from '../atoms/Price/Conversion' import Conversion from '../atoms/Price/Conversion'
import PriceUnit from '../atoms/Price/PriceUnit' import PriceUnit from '../atoms/Price/PriceUnit'
import Tooltip from '../atoms/Tooltip' import Tooltip from '../atoms/Tooltip'
@ -19,7 +19,11 @@ export default function MarketStats(): ReactElement {
const [totalValueLocked, setTotalValueLocked] = useState<string>() const [totalValueLocked, setTotalValueLocked] = useState<string>()
const [totalOceanLiquidity, setTotalOceanLiquidity] = useState<string>() const [totalOceanLiquidity, setTotalOceanLiquidity] = useState<string>()
const [poolCount, setPoolCount] = useState<number>() const [poolCount, setPoolCount] = useState<number>()
const { data } = useQuery(getTotalPoolsValues, { pollInterval: 20000 }) const [result] = useQuery({
query: getTotalPoolsValues
// pollInterval: 20000
})
const { data } = result
useEffect(() => { useEffect(() => {
if (!data || !data.poolFactories || data.poolFactories.length === 0) return if (!data || !data.poolFactories || data.poolFactories.length === 0) return

View File

@ -8,7 +8,7 @@ import styles from './PoolTransactions.module.css'
import { useUserPreferences } from '../../providers/UserPreferences' import { useUserPreferences } from '../../providers/UserPreferences'
import { Ocean } from '@oceanprotocol/lib' import { Ocean } from '@oceanprotocol/lib'
import { formatPrice } from '../atoms/Price/PriceUnit' import { formatPrice } from '../atoms/Price/PriceUnit'
import { gql, useQuery } from '@apollo/client' import { gql, useQuery } from 'urql'
import { import {
TransactionHistory, TransactionHistory,
TransactionHistory_poolTransactions as TransactionHistoryPoolTransactions TransactionHistory_poolTransactions as TransactionHistoryPoolTransactions
@ -16,7 +16,6 @@ import {
import web3 from 'web3' import web3 from 'web3'
import { useWeb3 } from '../../providers/Web3' import { useWeb3 } from '../../providers/Web3'
import { getOceanConfig } from '../../utils/ocean'
const txHistoryQueryByPool = gql` const txHistoryQueryByPool = gql`
query TransactionHistoryByPool($user: String, $pool: String) { query TransactionHistoryByPool($user: String, $pool: String) {
@ -199,27 +198,26 @@ export default function PoolTransactions({
const { accountId } = useWeb3() const { accountId } = useWeb3()
const [logs, setLogs] = useState<TransactionHistoryPoolTransactions[]>() const [logs, setLogs] = useState<TransactionHistoryPoolTransactions[]>()
const { data, loading } = useQuery<TransactionHistory>( const [result] = useQuery<TransactionHistory>({
poolAddress ? txHistoryQueryByPool : txHistoryQuery, query: poolAddress ? txHistoryQueryByPool : txHistoryQuery,
{ variables: {
variables: { user: accountId?.toLowerCase(),
user: accountId?.toLowerCase(), pool: poolAddress?.toLowerCase()
pool: poolAddress?.toLowerCase()
},
pollInterval: 20000
} }
) // pollInterval: 20000
})
const { data, fetching } = result
useEffect(() => { useEffect(() => {
if (!data) return if (!data) return
setLogs(data.poolTransactions) setLogs(data.poolTransactions)
}, [data, loading]) }, [data, fetching])
return ( return (
<Table <Table
columns={minimal ? columnsMinimal : columns} columns={minimal ? columnsMinimal : columns}
data={logs} data={logs}
isLoading={loading} isLoading={fetching}
noTableHead={minimal} noTableHead={minimal}
dense={minimal} dense={minimal}
pagination={minimal ? logs?.length >= 4 : logs?.length >= 9} pagination={minimal ? logs?.length >= 4 : logs?.length >= 9}

View File

@ -5,7 +5,7 @@ import File from '../../atoms/File'
import Price from '../../atoms/Price' import Price from '../../atoms/Price'
import { useSiteMetadata } from '../../../hooks/useSiteMetadata' import { useSiteMetadata } from '../../../hooks/useSiteMetadata'
import { useAsset } from '../../../providers/Asset' import { useAsset } from '../../../providers/Asset'
import { gql, useQuery } from '@apollo/client' import { gql, useQuery } from 'urql'
import { OrdersData } from '../../../@types/apollo/OrdersData' import { OrdersData } from '../../../@types/apollo/OrdersData'
import BigNumber from 'bignumber.js' import BigNumber from 'bignumber.js'
import { useOcean } from '../../../providers/Ocean' import { useOcean } from '../../../providers/Ocean'
@ -61,13 +61,15 @@ 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 } = useQuery<OrdersData>(previousOrderQuery, { const [result] = useQuery<OrdersData>({
query: previousOrderQuery,
variables: { variables: {
id: ddo.dataToken?.toLowerCase(), id: ddo.dataToken?.toLowerCase(),
account: accountId?.toLowerCase() account: accountId?.toLowerCase()
}, }
pollInterval: 5000 // pollInterval: 5000
}) })
const { data } = result
useEffect(() => { useEffect(() => {
if (!data || !assetTimeout || data.tokenOrders.length === 0) return if (!data || !assetTimeout || data.tokenOrders.length === 0) return

View File

@ -17,7 +17,7 @@ import { darkModeConfig } from '../../../../../app.config'
import Button from '../../../atoms/Button' import Button from '../../../atoms/Button'
import { Logger } from '@oceanprotocol/lib' import { Logger } from '@oceanprotocol/lib'
import { useAsset } from '../../../../providers/Asset' import { useAsset } from '../../../../providers/Asset'
import { gql, useQuery } from '@apollo/client' import { gql, useQuery } from 'urql'
import { PoolHistory } from '../../../../@types/apollo/PoolHistory' import { PoolHistory } from '../../../../@types/apollo/PoolHistory'
declare type GraphType = 'liquidity' | 'price' declare type GraphType = 'liquidity' | 'price'
@ -130,13 +130,15 @@ export default function Graph(): ReactElement {
const [isLoading, setIsLoading] = useState(true) const [isLoading, setIsLoading] = useState(true)
const [graphData, setGraphData] = useState<ChartData>() const [graphData, setGraphData] = useState<ChartData>()
const { data, refetch, error } = useQuery<PoolHistory>(poolHistory, { const [result, refetch] = useQuery<PoolHistory>({
query: poolHistory,
variables: { variables: {
id: price.address.toLowerCase(), id: price.address.toLowerCase(),
block: lastBlock block: lastBlock
}, }
pollInterval: 20000 // pollInterval: 20000
}) })
const { data, error } = result
useEffect(() => { useEffect(() => {
Logger.log('Fired GraphOptions!') Logger.log('Fired GraphOptions!')

View File

@ -15,7 +15,7 @@ import { PoolBalance } from '../../../../@types/TokenBalance'
import Transactions from './Transactions' import Transactions from './Transactions'
import Graph from './Graph' import Graph from './Graph'
import { useAsset } from '../../../../providers/Asset' import { useAsset } from '../../../../providers/Asset'
import { gql, useQuery } from '@apollo/client' import { gql, useQuery } from 'urql'
import { PoolLiquidity } from '../../../../@types/apollo/PoolLiquidity' import { PoolLiquidity } from '../../../../@types/apollo/PoolLiquidity'
import { useOcean } from '../../../../providers/Ocean' import { useOcean } from '../../../../providers/Ocean'
import { useWeb3 } from '../../../../providers/Web3' import { useWeb3 } from '../../../../providers/Web3'
@ -91,14 +91,17 @@ export default function Pool(): ReactElement {
// the purpose of the value is just to trigger the effect // the purpose of the value is just to trigger the effect
const [refreshPool, setRefreshPool] = useState(false) const [refreshPool, setRefreshPool] = useState(false)
const { data: dataLiquidity } = useQuery<PoolLiquidity>(poolLiquidityQuery, { const [result] = useQuery<PoolLiquidity>({
query: poolLiquidityQuery,
variables: { variables: {
id: price.address.toLowerCase(), id: price.address.toLowerCase(),
shareId: `${price.address.toLowerCase()}-${ddo.publicKey[0].owner.toLowerCase()}` shareId: `${price.address.toLowerCase()}-${ddo.publicKey[0].owner.toLowerCase()}`
}, }
pollInterval: 5000 // pollInterval: 5000
}) })
const { data: dataLiquidity } = result
useEffect(() => { useEffect(() => {
async function init() { async function init() {
if (!dataLiquidity || !dataLiquidity.pool) return if (!dataLiquidity || !dataLiquidity.pool) return

View File

@ -3,7 +3,7 @@ import { useAsset } from '../../../providers/Asset'
import ExplorerLink from '../../atoms/ExplorerLink' import ExplorerLink from '../../atoms/ExplorerLink'
import Time from '../../atoms/Time' import Time from '../../atoms/Time'
import styles from './EditHistory.module.css' import styles from './EditHistory.module.css'
import { gql, useQuery } from '@apollo/client' import { gql, useQuery } from 'urql'
import { ReceiptData_datatokens_updates as ReceiptData } from '../../../@types/apollo/ReceiptData' import { ReceiptData_datatokens_updates as ReceiptData } from '../../../@types/apollo/ReceiptData'
import { useWeb3 } from '../../../providers/Web3' import { useWeb3 } from '../../../providers/Web3'
@ -22,9 +22,11 @@ const getReceipts = gql`
export default function EditHistory(): ReactElement { export default function EditHistory(): ReactElement {
const { networkId } = useWeb3() const { networkId } = useWeb3()
const { ddo } = useAsset() const { ddo } = useAsset()
const { data } = useQuery(getReceipts, { const [result] = useQuery({
query: getReceipts,
variables: { address: ddo?.dataToken.toLowerCase() } variables: { address: ddo?.dataToken.toLowerCase() }
}) })
const { data } = result
const [receipts, setReceipts] = useState<ReceiptData[]>() const [receipts, setReceipts] = useState<ReceiptData[]>()
const [creationTx, setCreationTx] = useState<string>() const [creationTx, setCreationTx] = useState<string>()

View File

@ -14,8 +14,9 @@ export default function Footer(): ReactElement {
return ( return (
<footer className={styles.footer}> <footer className={styles.footer}>
<div className={styles.content}> <div className={styles.content}>
{/* <SyncStatus /> | <BuildId /> {/* <SyncStatus /> | */}
<MarketStats /> */} <BuildId />
<MarketStats />
<div className={styles.copyright}> <div className={styles.copyright}>
© {year} <Markdown text={copyright} /> {' '} © {year} <Markdown text={copyright} /> {' '}
<Link to="/terms">Terms</Link> <Link to="/terms">Terms</Link>

View File

@ -8,14 +8,14 @@ import Dotdotdot from 'react-dotdotdot'
import Table from '../../../atoms/Table' import Table from '../../../atoms/Table'
import Button from '../../../atoms/Button' import Button from '../../../atoms/Button'
import { useOcean } from '../../../../providers/Ocean' import { useOcean } from '../../../../providers/Ocean'
import { gql, useQuery } from '@apollo/client' import { gql, useQuery } from 'urql'
import { ComputeOrders } from '../../../../@types/apollo/ComputeOrders'
import { useWeb3 } from '../../../../providers/Web3' import { useWeb3 } from '../../../../providers/Web3'
import { import {
queryMetadata, queryMetadata,
transformChainIdsListToQuery transformChainIdsListToQuery
} from '../../../../utils/aquarius' } from '../../../../utils/aquarius'
import axios, { CancelToken } from 'axios' import axios, { CancelToken } from 'axios'
import { ComputeOrders } from '../../../../@types/apollo/ComputeOrders'
import Details from './Details' import Details from './Details'
import { ComputeJob } from '@oceanprotocol/lib/dist/node/ocean/interfaces/Compute' import { ComputeJob } from '@oceanprotocol/lib/dist/node/ocean/interfaces/Compute'
import { ReactComponent as Refresh } from '../../../../images/refresh.svg' import { ReactComponent as Refresh } from '../../../../images/refresh.svg'
@ -117,17 +117,19 @@ export default function ComputeJobs(): ReactElement {
const [isLoading, setIsLoading] = useState(true) const [isLoading, setIsLoading] = useState(true)
const [jobs, setJobs] = useState<ComputeJobMetaData[]>([]) const [jobs, setJobs] = useState<ComputeJobMetaData[]>([])
const { chainIds } = useUserPreferences() const { chainIds } = useUserPreferences()
const { data, refetch } = useQuery<ComputeOrders>(getComputeOrders, { const [result] = useQuery<ComputeOrders>({
query: getComputeOrders,
variables: { variables: {
user: accountId?.toLowerCase() user: accountId?.toLowerCase()
} }
}) })
const { data } = result
async function getJobs() { async function getJobs() {
if (!accountId) return if (!accountId) return
setIsLoading(true) setIsLoading(true)
await refetch() // await refetch()
const dtList = [] const dtList = []
const computeJobs: ComputeJobMetaData[] = [] const computeJobs: ComputeJobMetaData[] = []
for (let i = 0; i < data.tokenOrders.length; i++) { for (let i = 0; i < data.tokenOrders.length; i++) {

View File

@ -1,6 +1,6 @@
import React, { ReactElement, useEffect, useState } from 'react' import React, { ReactElement, useEffect, useState } from 'react'
import Table from '../../atoms/Table' import Table from '../../atoms/Table'
import { gql, useQuery } from '@apollo/client' import { gql, useQuery } from 'urql'
import Time from '../../atoms/Time' import Time from '../../atoms/Time'
import web3 from 'web3' import web3 from 'web3'
import AssetTitle from '../../molecules/AssetListTitle' import AssetTitle from '../../molecules/AssetListTitle'
@ -58,9 +58,11 @@ export default function ComputeDownloads(): ReactElement {
const { accountId } = useWeb3() const { accountId } = useWeb3()
const [isLoading, setIsLoading] = useState(false) const [isLoading, setIsLoading] = useState(false)
const [orders, setOrders] = useState<DownloadedAssets[]>() const [orders, setOrders] = useState<DownloadedAssets[]>()
const { data } = useQuery(getTokenOrders, { const [result] = useQuery({
query: getTokenOrders,
variables: { user: accountId?.toLowerCase() } variables: { user: accountId?.toLowerCase() }
}) })
const { data } = result
const { appConfig } = useSiteMetadata() const { appConfig } = useSiteMetadata()
useEffect(() => { useEffect(() => {

View File

@ -3,7 +3,7 @@ import Table from '../../atoms/Table'
import Conversion from '../../atoms/Price/Conversion' import Conversion from '../../atoms/Price/Conversion'
import styles from './PoolShares.module.css' import styles from './PoolShares.module.css'
import AssetTitle from '../../molecules/AssetListTitle' import AssetTitle from '../../molecules/AssetListTitle'
import { gql, useQuery } from '@apollo/client' import { gql, useQuery } from 'urql'
import { import {
PoolShares as PoolSharesList, PoolShares as PoolSharesList,
PoolShares_poolShares as PoolShare, PoolShares_poolShares as PoolShare,
@ -141,13 +141,15 @@ const columns = [
export default function PoolShares(): ReactElement { export default function PoolShares(): ReactElement {
const { accountId } = useWeb3() const { accountId } = useWeb3()
const [assets, setAssets] = useState<Asset[]>() const [assets, setAssets] = useState<Asset[]>()
const { data, loading } = useQuery<PoolSharesList>(poolSharesQuery, {
const [result] = useQuery<PoolSharesList>({
query: poolSharesQuery,
variables: { variables: {
user: accountId?.toLowerCase() user: accountId?.toLowerCase()
}, }
pollInterval: 20000 // pollInterval: 20000
}) })
const { data, fetching } = result
useEffect(() => { useEffect(() => {
if (!data) return if (!data) return
const assetList: Asset[] = [] const assetList: Asset[] = []
@ -159,7 +161,7 @@ export default function PoolShares(): ReactElement {
}) })
}) })
setAssets(assetList) setAssets(assetList)
}, [data, loading]) }, [data, fetching])
return ( return (
<Table <Table
@ -168,7 +170,7 @@ export default function PoolShares(): ReactElement {
data={assets} data={assets}
pagination pagination
paginationPerPage={5} paginationPerPage={5}
isLoading={loading} isLoading={fetching}
sortField="userLiquidity" sortField="userLiquidity"
sortAsc={false} sortAsc={false}
/> />

View File

@ -23,12 +23,12 @@ import { useUserPreferences } from '../../providers/UserPreferences'
async function getQueryHighest( async function getQueryHighest(
chainIds: number[] chainIds: number[]
): Promise<[SearchQuery, string]> { ): Promise<[SearchQuery, string]> {
const dids = await getHighestLiquidityDIDs() const dids = await getHighestLiquidityDIDs(chainIds)
// TODO: this query needs to adapt to chainIds // TODO: this query needs to adapt to chainIds
const queryHighest = { const queryHighest = {
page: 1, page: 1,
offset: 15, offset: 9,
query: { query: {
query_string: { query_string: {
query: `(${dids}) AND (${transformChainIdsListToQuery( query: `(${dids}) AND (${transformChainIdsListToQuery(

View File

@ -2,7 +2,7 @@ import React, { ReactElement } from 'react'
import Web3Provider from '../providers/Web3' import Web3Provider from '../providers/Web3'
import { UserPreferencesProvider } from '../providers/UserPreferences' import { UserPreferencesProvider } from '../providers/UserPreferences'
import PricesProvider from '../providers/Prices' import PricesProvider from '../providers/Prices'
import ApolloClientProvider from '../providers/ApolloClientProvider' import UrqlProvider from '../providers/UrqlProvider'
export default function wrapRootElement({ export default function wrapRootElement({
element element
@ -11,11 +11,11 @@ export default function wrapRootElement({
}): ReactElement { }): ReactElement {
return ( return (
<Web3Provider> <Web3Provider>
<ApolloClientProvider> <UrqlProvider>
<UserPreferencesProvider> <UserPreferencesProvider>
<PricesProvider>{element}</PricesProvider> <PricesProvider>{element}</PricesProvider>
</UserPreferencesProvider> </UserPreferencesProvider>
</ApolloClientProvider> </UrqlProvider>
</Web3Provider> </Web3Provider>
) )
} }

View File

@ -1,63 +0,0 @@
import {
ApolloClient,
ApolloProvider,
HttpLink,
InMemoryCache,
NormalizedCacheObject
} from '@apollo/client'
import { Logger } from '@oceanprotocol/lib'
import fetch from 'cross-fetch'
import React, { useState, useEffect, ReactNode, ReactElement } from 'react'
import { useWeb3 } from './Web3'
import { getOceanConfig } from '../utils/ocean'
let apolloClient: ApolloClient<NormalizedCacheObject>
function createClient(subgraphUri: string) {
const client = new ApolloClient({
link: new HttpLink({
uri: `${subgraphUri}/subgraphs/name/oceanprotocol/ocean-subgraph`,
fetch
}),
cache: new InMemoryCache()
})
return client
}
export function getApolloClientInstance(): ApolloClient<NormalizedCacheObject> {
return apolloClient
}
export default function ApolloClientProvider({
children
}: {
children: ReactNode
}): ReactElement {
const { networkId } = useWeb3()
const [client, setClient] = useState<ApolloClient<NormalizedCacheObject>>()
useEffect(() => {
const oceanConfig = getOceanConfig(networkId || 1)
if (!oceanConfig?.subgraphUri) {
Logger.error(
'No subgraphUri defined, preventing ApolloProvider from initialization.'
)
return
}
const newClient = createClient(oceanConfig.subgraphUri)
apolloClient = newClient
setClient(newClient)
Logger.log(`[apollo] Client connected to ${oceanConfig.subgraphUri}`)
}, [networkId])
return client ? (
<ApolloProvider client={client}>{children}</ApolloProvider>
) : (
<></>
)
}
export { ApolloClientProvider }

View File

@ -20,7 +20,7 @@ import { useSiteMetadata } from '../hooks/useSiteMetadata'
interface AssetProviderValue { interface AssetProviderValue {
isInPurgatory: boolean isInPurgatory: boolean
purgatoryData: PurgatoryData purgatoryData: PurgatoryData
ddo: any ddo: DDO
did: string did: string
metadata: MetadataMarket metadata: MetadataMarket
title: string title: string
@ -121,7 +121,7 @@ function AssetProvider({
} }
}, []) }, [])
const initMetadata = useCallback(async (ddo: any): Promise<void> => { const initMetadata = useCallback(async (ddo: DDO): Promise<void> => {
if (!ddo) return if (!ddo) return
setLoading(true) setLoading(true)
const returnedPrice = await getPrice(ddo) const returnedPrice = await getPrice(ddo)

View File

@ -0,0 +1,46 @@
import { createClient, Provider, Client } from 'urql'
import React, { useState, useEffect, ReactNode, ReactElement } from 'react'
import { useWeb3 } from './Web3'
import { Logger } from '@oceanprotocol/lib'
import { getOceanConfig } from '../utils/ocean'
let urqlClient: Client
function createUrqlClient(subgraphUri: string) {
const client = createClient({
url: `${subgraphUri}/subgraphs/name/oceanprotocol/ocean-subgraph`
})
return client
}
export function getUrqlClientInstance(): Client {
return urqlClient
}
export default function UrqlClientProvider({
children
}: {
children: ReactNode
}): ReactElement {
const { networkId } = useWeb3()
const [client, setClient] = useState<Client>()
useEffect(() => {
const oceanConfig = getOceanConfig(networkId || 1)
if (!oceanConfig?.subgraphUri) {
Logger.error(
'No subgraphUri defined, preventing UrqlProvider from initialization.'
)
return
}
const newClient = createUrqlClient(oceanConfig.subgraphUri)
urqlClient = newClient
setClient(newClient)
Logger.log(`[URQL] Client connected to ${oceanConfig.subgraphUri}`)
}, [networkId])
return client ? <Provider value={client}>{children}</Provider> : <></>
}
export { UrqlClientProvider }

View File

@ -1,6 +1,8 @@
import { gql, DocumentNode, ApolloQueryResult } from '@apollo/client' import { gql, OperationResult, TypedDocumentNode, OperationContext } from 'urql'
import { DDO, BestPrice } from '@oceanprotocol/lib' import { DDO, BestPrice } from '@oceanprotocol/lib'
import { getApolloClientInstance } from '../providers/ApolloClientProvider' import { getUrqlClientInstance } from '../providers/UrqlProvider'
import { getOceanConfig } from './ocean'
import web3 from 'web3'
import { import {
AssetsPoolPrice, AssetsPoolPrice,
AssetsPoolPrice_pools as AssetsPoolPricePools AssetsPoolPrice_pools as AssetsPoolPricePools
@ -9,12 +11,11 @@ import {
AssetsFrePrice, AssetsFrePrice,
AssetsFrePrice_fixedRateExchanges as AssetsFrePriceFixedRateExchanges AssetsFrePrice_fixedRateExchanges as AssetsFrePriceFixedRateExchanges
} from '../@types/apollo/AssetsFrePrice' } from '../@types/apollo/AssetsFrePrice'
import { AssetPreviousOrder } from '../@types/apollo/AssetPreviousOrder'
import { import {
AssetsFreePrice, AssetsFreePrice,
AssetsFreePrice_dispensers as AssetFreePriceDispenser AssetsFreePrice_dispensers as AssetFreePriceDispenser
} from '../@types/apollo/AssetsFreePrice' } from '../@types/apollo/AssetsFreePrice'
import web3 from 'web3' import { AssetPreviousOrder } from '../@types/apollo/AssetPreviousOrder'
export interface PriceList { export interface PriceList {
[key: string]: string [key: string]: string
@ -135,17 +136,19 @@ const HighestLiquidityAssets = gql`
} }
` `
function getSubgrahUri(chainId: number): string {
const config = getOceanConfig(chainId)
return config.subgraphUri
}
async function fetchData( async function fetchData(
query: DocumentNode, query: TypedDocumentNode,
variables: any variables: any,
): Promise<ApolloQueryResult<any>> { context: OperationContext
): Promise<OperationResult> {
try { try {
const client = getApolloClientInstance() const client = getUrqlClientInstance()
const response = await client.query({ const response = await client.query(query, variables, context).toPromise()
query: query,
variables: variables,
fetchPolicy: 'no-cache'
})
return response return response
} catch (error) { } catch (error) {
console.error('Error fetchData: ', error.message) console.error('Error fetchData: ', error.message)
@ -161,8 +164,8 @@ export async function getPreviousOrders(
id: id, id: id,
account: account account: account
} }
const fetchedPreviousOrders: ApolloQueryResult<AssetPreviousOrder> = const fetchedPreviousOrders: OperationResult<AssetPreviousOrder> =
await fetchData(PreviousOrderQuery, variables) await fetchData(PreviousOrderQuery, variables, null)
if (fetchedPreviousOrders.data?.tokenOrders?.length === 0) return null if (fetchedPreviousOrders.data?.tokenOrders?.length === 0) return null
if (assetTimeout === '0') { if (assetTimeout === '0') {
return fetchedPreviousOrders?.data?.tokenOrders[0]?.tx return fetchedPreviousOrders?.data?.tokenOrders[0]?.tx
@ -242,44 +245,67 @@ async function getAssetsPoolsExchangesAndDatatokenMap(
assets: DDO[] assets: DDO[]
): Promise< ): Promise<
[ [
ApolloQueryResult<AssetsPoolPrice>, AssetsPoolPricePools[],
ApolloQueryResult<AssetsFrePrice>, AssetsFrePriceFixedRateExchanges[],
ApolloQueryResult<AssetsFreePrice>, AssetFreePriceDispenser[],
DidAndDatatokenMap DidAndDatatokenMap
] ]
> { > {
const didDTMap: DidAndDatatokenMap = {} const didDTMap: DidAndDatatokenMap = {}
const dataTokenList: string[] = [] const chainAssetLists: any = {}
for (const ddo of assets) { for (const ddo of assets) {
didDTMap[ddo?.dataToken.toLowerCase()] = ddo.id didDTMap[ddo?.dataToken.toLowerCase()] = ddo.id
dataTokenList.push(ddo?.dataToken.toLowerCase()) // harcoded until we have chainId on assets
if (chainAssetLists[ddo.chainId]) {
chainAssetLists[ddo.chainId].push(ddo?.dataToken.toLowerCase())
} else {
chainAssetLists[ddo.chainId] = []
chainAssetLists[ddo.chainId].push(ddo?.dataToken.toLowerCase())
}
} }
const freVariables = { let poolPriceResponse: AssetsPoolPricePools[] = []
datatoken_in: dataTokenList let frePriceResponse: AssetsFrePriceFixedRateExchanges[] = []
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: OperationContext = {
url: `${getSubgrahUri(
Number(chainKey)
)}/subgraphs/name/oceanprotocol/ocean-subgraph`,
requestPolicy: 'network-only'
}
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
)
} }
const poolVariables = {
datatokenAddress_in: dataTokenList
}
const freeVariables = {
datatoken_in: dataTokenList
}
const poolPriceResponse: ApolloQueryResult<AssetsPoolPrice> = await fetchData(
PoolQuery,
poolVariables
)
const frePriceResponse: ApolloQueryResult<AssetsFrePrice> = await fetchData(
FreQuery,
freVariables
)
const freePriceResponse: ApolloQueryResult<AssetsFreePrice> = await fetchData(
FreeQuery,
freeVariables
)
return [poolPriceResponse, frePriceResponse, freePriceResponse, didDTMap] return [poolPriceResponse, frePriceResponse, freePriceResponse, didDTMap]
} }
@ -287,9 +313,9 @@ export async function getAssetsPriceList(assets: DDO[]): Promise<PriceList> {
const priceList: PriceList = {} const priceList: PriceList = {}
const values: [ const values: [
ApolloQueryResult<AssetsPoolPrice>, AssetsPoolPricePools[],
ApolloQueryResult<AssetsFrePrice>, AssetsFrePriceFixedRateExchanges[],
ApolloQueryResult<AssetsFreePrice>, AssetFreePriceDispenser[],
DidAndDatatokenMap DidAndDatatokenMap
] = await getAssetsPoolsExchangesAndDatatokenMap(assets) ] = await getAssetsPoolsExchangesAndDatatokenMap(assets)
const poolPriceResponse = values[0] const poolPriceResponse = values[0]
@ -297,16 +323,16 @@ export async function getAssetsPriceList(assets: DDO[]): Promise<PriceList> {
const freePriceResponse = values[2] const freePriceResponse = values[2]
const didDTMap: DidAndDatatokenMap = values[3] const didDTMap: DidAndDatatokenMap = values[3]
for (const poolPrice of poolPriceResponse.data?.pools) { for (const poolPrice of poolPriceResponse) {
priceList[didDTMap[poolPrice.datatokenAddress]] = priceList[didDTMap[poolPrice.datatokenAddress]] =
poolPrice.consumePrice === '-1' poolPrice.consumePrice === '-1'
? poolPrice.spotPrice ? poolPrice.spotPrice
: poolPrice.consumePrice : poolPrice.consumePrice
} }
for (const frePrice of frePriceResponse.data?.fixedRateExchanges) { for (const frePrice of frePriceResponse) {
priceList[didDTMap[frePrice.datatoken?.address]] = frePrice.rate priceList[didDTMap[frePrice.datatoken?.address]] = frePrice.rate
} }
for (const freePrice of freePriceResponse.data?.dispensers) { for (const freePrice of freePriceResponse) {
priceList[didDTMap[freePrice.datatoken?.address]] = '0' priceList[didDTMap[freePrice.datatoken?.address]] = '0'
} }
return priceList return priceList
@ -316,26 +342,33 @@ export async function getPrice(asset: DDO): Promise<BestPrice> {
const freVariables = { const freVariables = {
datatoken: asset?.dataToken.toLowerCase() datatoken: asset?.dataToken.toLowerCase()
} }
const freeVariables = {
datatoken: asset?.dataToken.toLowerCase()
}
const poolVariables = { const poolVariables = {
datatokenAddress: asset?.dataToken.toLowerCase() datatokenAddress: asset?.dataToken.toLowerCase()
} }
const freeVariables = { const queryContext: OperationContext = {
datatoken: asset?.dataToken.toLowerCase() url: `${getSubgrahUri(
asset.chainId
)}/subgraphs/name/oceanprotocol/ocean-subgraph`,
requestPolicy: 'network-only'
} }
const poolPriceResponse: OperationResult<AssetsPoolPrice> = await fetchData(
const poolPriceResponse: ApolloQueryResult<AssetsPoolPrice> = await fetchData(
AssetPoolPriceQuerry, AssetPoolPriceQuerry,
poolVariables poolVariables,
queryContext
) )
const frePriceResponse: ApolloQueryResult<AssetsFrePrice> = await fetchData( const frePriceResponse: OperationResult<AssetsFrePrice> = await fetchData(
AssetFreQuery, AssetFreQuery,
freVariables freVariables,
queryContext
) )
const freePriceResponse: ApolloQueryResult<AssetsFreePrice> = await fetchData( const freePriceResponse: OperationResult<AssetsFreePrice> = await fetchData(
AssetFreeQuery, AssetFreeQuery,
freeVariables freeVariables,
queryContext
) )
const bestPrice: BestPrice = transformPriceToBestPrice( const bestPrice: BestPrice = transformPriceToBestPrice(
@ -353,29 +386,29 @@ export async function getAssetsBestPrices(
const assetsWithPrice: AssetListPrices[] = [] const assetsWithPrice: AssetListPrices[] = []
const values: [ const values: [
ApolloQueryResult<AssetsPoolPrice>, AssetsPoolPricePools[],
ApolloQueryResult<AssetsFrePrice>, AssetsFrePriceFixedRateExchanges[],
ApolloQueryResult<AssetsFreePrice>, AssetFreePriceDispenser[],
DidAndDatatokenMap DidAndDatatokenMap
] = await getAssetsPoolsExchangesAndDatatokenMap(assets) ] = await getAssetsPoolsExchangesAndDatatokenMap(assets)
const poolPriceResponse = values[0] const poolPriceResponse = values[0]
const frePriceResponse = values[1] const frePriceResponse = values[1]
const freePriceResponse = values[2] const freePriceResponse = values[2]
for (const ddo of assets) { for (const ddo of assets) {
const dataToken = ddo.dataToken.toLowerCase() const dataToken = ddo.dataToken.toLowerCase()
const poolPrice: AssetsPoolPricePools[] = [] const poolPrice: AssetsPoolPricePools[] = []
const frePrice: AssetsFrePriceFixedRateExchanges[] = [] const frePrice: AssetsFrePriceFixedRateExchanges[] = []
const freePrice: AssetFreePriceDispenser[] = [] const freePrice: AssetFreePriceDispenser[] = []
const pool = poolPriceResponse.data?.pools.find( const pool = poolPriceResponse.find(
(pool: any) => pool.datatokenAddress === dataToken (pool: any) => pool.datatokenAddress === dataToken
) )
pool && poolPrice.push(pool) pool && poolPrice.push(pool)
const fre = frePriceResponse.data?.fixedRateExchanges.find( const fre = frePriceResponse.find(
(fre: any) => fre.datatoken.address === dataToken (fre: any) => fre.datatoken.address === dataToken
) )
fre && frePrice.push(fre) fre && frePrice.push(fre)
const free = freePriceResponse.data?.dispensers.find( const free = freePriceResponse.find(
(free: any) => free.datatoken.address === dataToken (free: any) => free.datatoken.address === dataToken
) )
free && freePrice.push(free) free && freePrice.push(free)
@ -389,16 +422,30 @@ export async function getAssetsBestPrices(
return assetsWithPrice return assetsWithPrice
} }
export async function getHighestLiquidityDIDs(): Promise<string> { export async function getHighestLiquidityDIDs(
chainIds: number[]
): Promise<string> {
const didList: string[] = [] const didList: string[] = []
const fetchedPools = await fetchData(HighestLiquidityAssets, null) for (const chain of chainIds) {
if (fetchedPools.data?.pools?.length === 0) return null const queryContext: OperationContext = {
for (let i = 0; i < fetchedPools.data.pools.length; i++) { url: `${getSubgrahUri(
if (!fetchedPools.data.pools[i].datatokenAddress) continue Number(chain)
const did = web3.utils )}/subgraphs/name/oceanprotocol/ocean-subgraph`,
.toChecksumAddress(fetchedPools.data.pools[i].datatokenAddress) requestPolicy: 'network-only'
.replace('0x', 'did:op:') }
didList.push(did) const fetchedPools = await fetchData(
HighestLiquidityAssets,
null,
queryContext
)
if (fetchedPools.data?.pools?.length === 0) return null
for (let i = 0; i < fetchedPools.data.pools.length; i++) {
if (!fetchedPools.data.pools[i].datatokenAddress) continue
const did = web3.utils
.toChecksumAddress(fetchedPools.data.pools[i].datatokenAddress)
.replace('0x', 'did:op:')
didList.push(did)
}
} }
const searchDids = JSON.stringify(didList) const searchDids = JSON.stringify(didList)
.replace(/,/g, ' ') .replace(/,/g, ' ')