Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Display TVL #353

Merged
merged 25 commits into from
Feb 11, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 4 additions & 33 deletions src/components/App.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { ReactElement, useEffect, useState } from 'react'
import React, { ReactElement } from 'react'
import Footer from './organisms/Footer'
import Header from './organisms/Header'
import Styles from '../global/Styles'
Expand All @@ -7,15 +7,7 @@ import { useSiteMetadata } from '../hooks/useSiteMetadata'
import { useOcean } from '@oceanprotocol/react'
import Alert from './atoms/Alert'
import { graphql, PageProps, useStaticQuery } from 'gatsby'
import {
ApolloClient,
ApolloProvider,
HttpLink,
InMemoryCache,
NormalizedCacheObject
} from '@apollo/client'
import fetch from 'cross-fetch'
import { ConfigHelperConfig } from '@oceanprotocol/lib/dist/node/utils/ConfigHelper'

const contentQuery = graphql`
query AppQuery {
purgatory: allFile(filter: { relativePath: { eq: "purgatory.json" } }) {
Expand Down Expand Up @@ -45,24 +37,9 @@ export default function App({
const { warning } = useSiteMetadata()
const {
isInPurgatory: isAccountInPurgatory,
purgatoryData: accountPurgatory,
config
purgatoryData: accountPurgatory
} = useOcean()

const [client, setClient] = useState<ApolloClient<NormalizedCacheObject>>()

useEffect(() => {
const newClient = new ApolloClient({
link: new HttpLink({
uri: `${
(config as ConfigHelperConfig).subgraphUri
}/subgraphs/name/oceanprotocol/ocean-subgraph`,
fetch
}),
cache: new InMemoryCache()
})
setClient(newClient)
}, [config])
return (
<Styles>
<div className={styles.app}>
Expand All @@ -78,13 +55,7 @@ export default function App({
state="error"
/>
)}
{client ? (
<ApolloProvider client={client}>
<main className={styles.main}>{children}</main>
</ApolloProvider>
) : (
<></>
)}
<main className={styles.main}>{children}</main>
<Footer />
</div>
</Styles>
Expand Down
7 changes: 6 additions & 1 deletion src/components/atoms/Tooltip.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,18 @@ export default function Tooltip({
trigger,
disabled,
className,
placement
placement,
link,
reference
}: {
content: ReactNode
children?: ReactNode
trigger?: string
disabled?: boolean
className?: string
placement?: Placement
link?: string
reference?: string
}): ReactElement {
const [props, setSpring] = useSpring(() => animation.from)

Expand Down Expand Up @@ -72,6 +76,7 @@ export default function Tooltip({
<animated.div style={props}>
<div className={styles.content} {...attrs}>
{content}
{link && <a href={link}>{reference}</a>}
<div className={styles.arrow} data-popper-arrow />
</div>
</animated.div>
Expand Down
4 changes: 4 additions & 0 deletions src/components/molecules/MarketStats.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,7 @@
color: var(--color-secondary) !important;
font-size: var(--font-size-small) !important;
}

.info {
width: .85rem
}
104 changes: 34 additions & 70 deletions src/components/molecules/MarketStats.tsx
Original file line number Diff line number Diff line change
@@ -1,83 +1,47 @@
import { Logger } from '@oceanprotocol/lib'
import React, { ReactElement, useEffect, useState } from 'react'
import PriceUnit from '../atoms/Price/PriceUnit'
import axios from 'axios'
import styles from './MarketStats.module.css'
import { useInView } from 'react-intersection-observer'

interface MarketStatsResponse {
datasets: {
pools: number
exchanges: number
none: number
total: number
import { gql, useQuery } from '@apollo/client'
import Conversion from '../atoms/Price/Conversion'
import PriceUnit from '../atoms/Price/PriceUnit'
import Tooltip from '../atoms/Tooltip'

const getTotalPoolsValues = gql`
query PoolsData {
poolFactories {
totalValueLocked
totalOceanLiquidity
finalizedPoolCount
}
}
owners: number
ocean: number
datatoken: number
}

const refreshInterval = 60000 // 60 sec.
`

export default function MarketStats(): ReactElement {
const [ref, inView] = useInView()
const [stats, setStats] = useState<MarketStatsResponse>()
const [totalValueLocked, setTotalValueLocked] = useState<string>()
const [totalOceanLiquidity, setTotalOceanLiquidity] = useState<string>()
const [poolCount, setPoolCount] = useState<number>()
const { data } = useQuery(getTotalPoolsValues)

useEffect(() => {
const source = axios.CancelToken.source()
if (!data) return

async function getStats() {
try {
const response = await axios('https://market-stats.oceanprotocol.com', {
cancelToken: source.token
})
if (!response || response.status !== 200) return
setStats(response.data)
} catch (error) {
if (axios.isCancel(error)) {
Logger.log(error.message)
} else {
Logger.error(error.message)
}
}
}

// Update periodically when in viewport
const interval = setInterval(getStats, refreshInterval)

if (!inView) {
clearInterval(interval)
}

getStats()

return () => {
clearInterval(interval)
source.cancel()
}
}, [inView])
setTotalValueLocked(data.poolFactories[0].totalValueLocked)
setTotalOceanLiquidity(data.poolFactories[0].totalOceanLiquidity)
setPoolCount(data.poolFactories[0].finalizedPoolCount)
}, [data])

return (
<div className={styles.stats} ref={ref}>
Total of <strong>{stats?.datasets.total}</strong> data sets & unique
datatokens published by <strong>{stats?.owners}</strong> accounts.
<br />
<PriceUnit
price={`${stats?.ocean}`}
small
className={styles.total}
conversion
/>{' '}
and{' '}
<PriceUnit
price={`${stats?.datatoken}`}
symbol="datatokens"
small
className={styles.total}
/>{' '}
in <strong>{stats?.datasets.pools}</strong> data set pools.
<br />
<strong>{stats?.datasets.none}</strong> data sets have no price set yet.
<div className={styles.stats}>
<Conversion price={`${totalValueLocked}`} hideApproximateSymbol />{' '}
<abbr title="Total Value Locked">TVL</abbr> across{' '}
<strong>{poolCount}</strong> data set pools that contain{' '}
<PriceUnit price={totalOceanLiquidity} small className={styles.total} />,
plus datatokens for each pool.
<Tooltip
className={styles.info}
content="Counted on-chain from our pool factory. Does not filter out data sets in "
reference="list-purgatory"
link="https://github.com/oceanprotocol/list-purgatory"
/>
</div>
)
}
19 changes: 13 additions & 6 deletions src/helpers/NetworkMonitor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,18 @@ import contractAddresses from '@oceanprotocol/contracts/artifacts/address.json'

const refreshInterval = 5000 // 5 sec.

export function getDevelopmentConfig(): Partial<ConfigHelperConfig> {
return {
factoryAddress: contractAddresses.development?.DTFactory,
poolFactoryAddress: contractAddresses.development?.BFactory,
fixedRateExchangeAddress: contractAddresses.development?.FixedRateExchange,
metadataContractAddress: contractAddresses.development?.Metadata,
oceanTokenAddress: contractAddresses.development?.Ocean,
// There is no subgraph in barge so we hardcode the Rinkeby one for now
subgraphUri: 'https://subgraph.rinkeby.oceanprotocol.com'
}
}

export function NetworkMonitor(): ReactElement {
const {
connect,
Expand All @@ -28,12 +40,7 @@ export function NetworkMonitor(): ReactElement {

// add local dev values
...(chainId === '8996' && {
factoryAddress: contractAddresses.development?.DTFactory,
poolFactoryAddress: contractAddresses.development?.BFactory,
fixedRateExchangeAddress:
contractAddresses.development?.FixedRateExchange,
metadataContractAddress: contractAddresses.development?.Metadata,
oceanTokenAddress: contractAddresses.development?.Ocean
...getDevelopmentConfig()
})
}

Expand Down
23 changes: 17 additions & 6 deletions src/helpers/wrapRootElement.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@ import React, { ReactElement } from 'react'
import { OceanProvider } from '@oceanprotocol/react'
import { ConfigHelper, Config } from '@oceanprotocol/lib'
import { web3ModalOpts } from '../utils/wallet'
import { NetworkMonitor } from './NetworkMonitor'
import { getDevelopmentConfig, NetworkMonitor } from './NetworkMonitor'
import appConfig from '../../app.config'
import {
ConfigHelperNetworkName,
ConfigHelperNetworkId
} from '@oceanprotocol/lib/dist/node/utils/ConfigHelper'
import { UserPreferencesProvider } from '../providers/UserPreferences'
import PricesProvider from '../providers/Prices'
import ApolloClientProvider from '../providers/ApolloClientProvider'

export function getOceanConfig(
network: ConfigHelperNetworkName | ConfigHelperNetworkId
Expand All @@ -26,16 +27,26 @@ export default function wrapRootElement({
element: ReactElement
}): ReactElement {
const { network } = appConfig
const oceanInitialConfig = getOceanConfig(network)
const oceanInitialConfig = {
...getOceanConfig(network),

// add local dev values
...(network === 'development' && {
...getDevelopmentConfig()
})
}

return (
<OceanProvider
initialConfig={oceanInitialConfig}
web3ModalOpts={web3ModalOpts}
>
<UserPreferencesProvider>
<NetworkMonitor />
<PricesProvider>{element}</PricesProvider>
</UserPreferencesProvider>
<ApolloClientProvider>
<UserPreferencesProvider>
<NetworkMonitor />
<PricesProvider>{element}</PricesProvider>
</UserPreferencesProvider>
</ApolloClientProvider>
</OceanProvider>
)
}
53 changes: 53 additions & 0 deletions src/providers/ApolloClientProvider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import {
ApolloClient,
ApolloProvider,
HttpLink,
InMemoryCache,
NormalizedCacheObject
} from '@apollo/client'
import { Logger } from '@oceanprotocol/lib'
import { ConfigHelperConfig } from '@oceanprotocol/lib/dist/node/utils/ConfigHelper'
import { useOcean } from '@oceanprotocol/react'
import fetch from 'cross-fetch'
import React, { useState, useEffect, ReactNode, ReactElement } from 'react'

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 default function ApolloClientProvider({
children
}: {
children: ReactNode
}): ReactElement {
const { config } = useOcean()
const [client, setClient] = useState<ApolloClient<NormalizedCacheObject>>()

useEffect(() => {
if (!(config as ConfigHelperConfig)?.subgraphUri) {
Logger.error(
'No subgraphUri defined, preventing ApolloProvider from initialization.'
)
return
}

const newClient = createClient((config as ConfigHelperConfig).subgraphUri)
setClient(newClient)
}, [config])

return client ? (
<ApolloProvider client={client}>{children}</ApolloProvider>
) : (
<></>
kremalicious marked this conversation as resolved.
Show resolved Hide resolved
)
}

export { ApolloClientProvider }