mirror of
https://github.com/oceanprotocol/market.git
synced 2024-12-02 05:57:29 +01:00
Get pool shares using The Graph (#360)
* added graph query * fixed negative liquidity value for input error * used graph to get poolShares * replaced total pool liquidity with user liquidity, get ddo on row * get symbol from graph, calculate userLiquidity * fixed userLiquidity price and sorted table by userLiquidity * removed ordering by balance * displayed pool and client liquidity, disabled table header hover * order Your Liquidity before Pool Liquidity * removed line height on asset title in pool shares table * limit table to 5 rows, refactor liquidity comp, changed balance color * code climate similar blocks fix * changed lockedValue to valueLocked in pool shares query * removed husky file
This commit is contained in:
parent
3e2ad9674c
commit
b043eab047
@ -9,10 +9,12 @@ const cx = classNames.bind(styles)
|
||||
|
||||
export default function Conversion({
|
||||
price,
|
||||
className
|
||||
className,
|
||||
hideApproximateSymbol
|
||||
}: {
|
||||
price: string // expects price in OCEAN, not wei
|
||||
className?: string
|
||||
hideApproximateSymbol?: boolean
|
||||
}): ReactElement {
|
||||
const { prices } = usePrices()
|
||||
const { currency, locale } = useUserPreferences()
|
||||
@ -59,7 +61,8 @@ export default function Conversion({
|
||||
className={styleClasses}
|
||||
title="Approximation based on current OCEAN spot price on Coingecko"
|
||||
>
|
||||
≈ <strong dangerouslySetInnerHTML={{ __html: priceConverted }} />{' '}
|
||||
{!hideApproximateSymbol && '≈ '}
|
||||
<strong dangerouslySetInnerHTML={{ __html: priceConverted }} />{' '}
|
||||
{!isFiat && currency}
|
||||
</span>
|
||||
)
|
||||
|
@ -15,10 +15,14 @@
|
||||
|
||||
.table [role='columnheader'] {
|
||||
text-transform: uppercase;
|
||||
color: var(--color-secondary);
|
||||
font-size: var(--font-size-small);
|
||||
}
|
||||
|
||||
.table [role='columnheader'] > span,
|
||||
.table [role='columnheader'] > div {
|
||||
color: var(--color-secondary);
|
||||
}
|
||||
|
||||
.table [role='row']:not(:last-of-type) {
|
||||
border-color: var(--border-color);
|
||||
}
|
||||
|
@ -6,6 +6,9 @@ import styles from './Table.module.css'
|
||||
interface TableProps extends IDataTableProps {
|
||||
isLoading?: boolean
|
||||
emptyMessage?: string
|
||||
sortField?: string
|
||||
sortAsc?: boolean
|
||||
className?: string
|
||||
}
|
||||
|
||||
function Empty({ message }: { message?: string }): ReactElement {
|
||||
@ -19,13 +22,16 @@ export default function Table({
|
||||
emptyMessage,
|
||||
pagination,
|
||||
paginationPerPage,
|
||||
sortField,
|
||||
sortAsc,
|
||||
className,
|
||||
...props
|
||||
}: TableProps): ReactElement {
|
||||
return (
|
||||
<DataTable
|
||||
columns={columns}
|
||||
data={data}
|
||||
className={styles.table}
|
||||
className={className ? styles.table + ` ${className}` : styles.table}
|
||||
noHeader
|
||||
pagination={pagination || data?.length >= 9}
|
||||
paginationPerPage={paginationPerPage || 10}
|
||||
@ -33,6 +39,8 @@ export default function Table({
|
||||
noDataComponent={<Empty message={emptyMessage} />}
|
||||
progressPending={isLoading}
|
||||
progressComponent={<Loader />}
|
||||
defaultSortField={sortField}
|
||||
defaultSortAsc={sortAsc}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
|
@ -115,6 +115,7 @@ export default function FormAdd({
|
||||
type="number"
|
||||
name="amount"
|
||||
max={amountMax}
|
||||
min="0"
|
||||
value={`${values.amount}`}
|
||||
step="any"
|
||||
prefix={<CoinSelect dtSymbol={dtSymbol} setCoin={setCoin} />}
|
||||
|
@ -148,7 +148,6 @@ export default function Pool(): ReactElement {
|
||||
const totalCreatorLiquidityInOcean =
|
||||
creatorLiquidity?.ocean + creatorLiquidity?.datatoken * price?.value
|
||||
setCreatorTotalLiquidityInOcean(totalCreatorLiquidityInOcean)
|
||||
|
||||
const creatorPoolShare =
|
||||
price?.ocean &&
|
||||
price?.datatoken &&
|
||||
@ -174,7 +173,6 @@ export default function Pool(): ReactElement {
|
||||
const totalUserLiquidityInOcean =
|
||||
userLiquidity?.ocean + userLiquidity?.datatoken * price?.value
|
||||
setTotalUserLiquidityInOcean(totalUserLiquidityInOcean)
|
||||
|
||||
const totalLiquidityInOcean = price?.ocean + price?.datatoken * price?.value
|
||||
setTotalLiquidityInOcean(totalLiquidityInOcean)
|
||||
}, [userLiquidity, price, poolTokens, totalPoolTokens])
|
||||
|
@ -3,7 +3,6 @@
|
||||
font-weight: var(--font-weight-base) !important;
|
||||
font-size: var(--font-size-small);
|
||||
padding-left: var(--font-size-base);
|
||||
padding-top: calc(var(--spacer) / 10);
|
||||
}
|
||||
|
||||
.totalLiquidity strong {
|
||||
@ -11,3 +10,51 @@
|
||||
color: var(--font-color-text);
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.poolSharesTable [role='gridcell'] {
|
||||
align-items: flex-start;
|
||||
margin: calc(var(--spacer) / 2) 0;
|
||||
}
|
||||
|
||||
.poolSharesTable [class*='AssetListTitle-module--title'] {
|
||||
line-height: 0 !important;
|
||||
}
|
||||
|
||||
.poolSharesTable [class*='Token-module--token'] div {
|
||||
color: var(--color-secondary);
|
||||
}
|
||||
|
||||
@media (min-width: 30rem) {
|
||||
.poolSharesTable [class*='AssetListTitle-module--title'] {
|
||||
line-height: 0 !important;
|
||||
}
|
||||
}
|
||||
|
||||
.yourLiquidity {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-end;
|
||||
}
|
||||
|
||||
.yourLiquidity [class*='Conversion-module--'] {
|
||||
margin-bottom: calc(var(--spacer) / 8);
|
||||
}
|
||||
|
||||
.yourLiquidity [class*='Conversion-module--'] strong {
|
||||
font-size: var(--font-size-base);
|
||||
}
|
||||
|
||||
.yourLiquidity [class*='Token-module--token'] {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
margin-bottom: calc(var(--spacer) / 8);
|
||||
}
|
||||
|
||||
.yourLiquidity [class*='Token-module--token'] div {
|
||||
font-size: var(--font-size-small);
|
||||
}
|
||||
|
||||
.yourLiquidity [class*='Token-module--icon'] {
|
||||
display: none;
|
||||
}
|
||||
|
@ -1,26 +1,107 @@
|
||||
import { useMetadata, useOcean } from '@oceanprotocol/react'
|
||||
import { useOcean } from '@oceanprotocol/react'
|
||||
import React, { ReactElement, useEffect, useState } from 'react'
|
||||
import Table from '../../atoms/Table'
|
||||
import { DDO, Logger, MetadataCache } from '@oceanprotocol/lib'
|
||||
import PriceUnit from '../../atoms/Price/PriceUnit'
|
||||
import Conversion from '../../atoms/Price/Conversion'
|
||||
import styles from './PoolShares.module.css'
|
||||
import AssetTitle from '../../molecules/AssetListTitle'
|
||||
import { gql, useQuery } from '@apollo/client'
|
||||
import {
|
||||
PoolShares as PoolSharesList,
|
||||
PoolShares_poolShares as PoolShare,
|
||||
PoolShares_poolShares_poolId_tokens as PoolSharePoolIdTokens
|
||||
} from '../../../@types/apollo/PoolShares'
|
||||
import web3 from 'web3'
|
||||
import Token from '../../organisms/AssetActions/Pool/Token'
|
||||
|
||||
const poolSharesQuery = gql`
|
||||
query PoolShares($user: String) {
|
||||
poolShares(where: { userAddress: $user, balance_gt: 0.001 }, first: 1000) {
|
||||
id
|
||||
balance
|
||||
userAddress {
|
||||
id
|
||||
}
|
||||
poolId {
|
||||
id
|
||||
datatokenAddress
|
||||
valueLocked
|
||||
tokens {
|
||||
tokenId {
|
||||
symbol
|
||||
}
|
||||
}
|
||||
oceanReserve
|
||||
datatokenReserve
|
||||
totalShares
|
||||
consumePrice
|
||||
spotPrice
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
interface Asset {
|
||||
ddo: DDO
|
||||
shares: string
|
||||
userLiquidity: number
|
||||
poolShare: PoolShare
|
||||
}
|
||||
|
||||
function TotalLiquidity({ ddo }: { ddo: DDO }): ReactElement {
|
||||
const { price } = useMetadata(ddo)
|
||||
const totalLiquidityInOcean = price?.ocean + price?.datatoken * price?.value
|
||||
function calculateUserLiquidity(poolShare: PoolShare) {
|
||||
const ocean =
|
||||
(poolShare.balance / poolShare.poolId.totalShares) *
|
||||
poolShare.poolId.oceanReserve
|
||||
const datatokens =
|
||||
(poolShare.balance / poolShare.poolId.totalShares) *
|
||||
poolShare.poolId.datatokenReserve
|
||||
const totalLiquidity = ocean + datatokens * poolShare.poolId.consumePrice
|
||||
return totalLiquidity
|
||||
}
|
||||
|
||||
function findValidToken(tokens: PoolSharePoolIdTokens[]) {
|
||||
const symbol = tokens.find((token) => token.tokenId !== null)
|
||||
return symbol.tokenId.symbol
|
||||
}
|
||||
|
||||
function Symbol({ tokens }: { tokens: PoolSharePoolIdTokens[] }) {
|
||||
return <>{findValidToken(tokens)}</>
|
||||
}
|
||||
|
||||
function Liquidity({ row, type }: { row: Asset; type: string }) {
|
||||
let price = ``
|
||||
let oceanTokenBalance = ''
|
||||
let dataTokenBalance = ''
|
||||
if (type === 'user') {
|
||||
price = `${row.userLiquidity}`
|
||||
const userShare = row.poolShare.balance / row.poolShare.poolId.totalShares
|
||||
oceanTokenBalance = (
|
||||
userShare * row.poolShare.poolId.oceanReserve
|
||||
).toString()
|
||||
dataTokenBalance = (
|
||||
userShare * row.poolShare.poolId.datatokenReserve
|
||||
).toString()
|
||||
}
|
||||
if (type === 'pool') {
|
||||
price = `${
|
||||
Number(row.poolShare.poolId.oceanReserve) +
|
||||
Number(row.poolShare.poolId.datatokenReserve) *
|
||||
row.poolShare.poolId.consumePrice
|
||||
}`
|
||||
oceanTokenBalance = row.poolShare.poolId.oceanReserve.toString()
|
||||
dataTokenBalance = row.poolShare.poolId.datatokenReserve.toString()
|
||||
}
|
||||
return (
|
||||
<div className={styles.yourLiquidity}>
|
||||
<Conversion
|
||||
price={`${totalLiquidityInOcean}`}
|
||||
price={price}
|
||||
className={styles.totalLiquidity}
|
||||
hideApproximateSymbol
|
||||
/>
|
||||
<Token symbol="OCEAN" balance={oceanTokenBalance} noIcon />
|
||||
<Token
|
||||
symbol={findValidToken(row.poolShare.poolId.tokens)}
|
||||
balance={dataTokenBalance}
|
||||
noIcon
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@ -28,59 +109,68 @@ const columns = [
|
||||
{
|
||||
name: 'Data Set',
|
||||
selector: function getAssetRow(row: Asset) {
|
||||
return <AssetTitle ddo={row.ddo} />
|
||||
const did = web3.utils
|
||||
.toChecksumAddress(row.poolShare.poolId.datatokenAddress)
|
||||
.replace('0x', 'did:op:')
|
||||
return <AssetTitle did={did} />
|
||||
},
|
||||
grow: 2
|
||||
},
|
||||
{
|
||||
name: 'Datatoken',
|
||||
selector: 'ddo.dataTokenInfo.symbol'
|
||||
selector: function getSymbol(row: Asset) {
|
||||
return <Symbol tokens={row.poolShare.poolId.tokens} />
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'Your Pool Shares',
|
||||
name: 'Your Liquidity',
|
||||
selector: function getAssetRow(row: Asset) {
|
||||
return <PriceUnit price={row.shares} symbol="pool shares" small />
|
||||
return <Liquidity row={row} type="user" />
|
||||
},
|
||||
right: true
|
||||
},
|
||||
{
|
||||
name: 'Total Pool Liquidity',
|
||||
name: 'Pool Liquidity',
|
||||
selector: function getAssetRow(row: Asset) {
|
||||
return <TotalLiquidity ddo={row.ddo} />
|
||||
return <Liquidity row={row} type="pool" />
|
||||
},
|
||||
right: true
|
||||
}
|
||||
]
|
||||
|
||||
export default function PoolShares(): ReactElement {
|
||||
const { ocean, accountId, config } = useOcean()
|
||||
const { accountId } = useOcean()
|
||||
const [assets, setAssets] = useState<Asset[]>()
|
||||
const [isLoading, setIsLoading] = useState(false)
|
||||
const { data, loading } = useQuery<PoolSharesList>(poolSharesQuery, {
|
||||
variables: {
|
||||
user: accountId?.toLowerCase()
|
||||
},
|
||||
pollInterval: 20000
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
async function getAssets() {
|
||||
if (!ocean || !accountId || !config?.metadataCacheUri) return
|
||||
setIsLoading(true)
|
||||
if (!data) return
|
||||
const assetList: Asset[] = []
|
||||
data.poolShares.forEach((poolShare) => {
|
||||
const userLiquidity = calculateUserLiquidity(poolShare)
|
||||
assetList.push({
|
||||
poolShare: poolShare,
|
||||
userLiquidity: userLiquidity
|
||||
})
|
||||
})
|
||||
setAssets(assetList)
|
||||
}, [data, loading])
|
||||
|
||||
try {
|
||||
const pools = await ocean.pool.getPoolSharesByAddress(accountId)
|
||||
const metadataCache = new MetadataCache(config.metadataCacheUri, Logger)
|
||||
const result: Asset[] = []
|
||||
|
||||
for (const pool of pools) {
|
||||
const ddo = await metadataCache.retrieveDDO(pool.did)
|
||||
ddo && result.push({ ddo, shares: pool.shares })
|
||||
}
|
||||
|
||||
setAssets(result)
|
||||
} catch (error) {
|
||||
Logger.error(error.message)
|
||||
} finally {
|
||||
setIsLoading(false)
|
||||
}
|
||||
}
|
||||
getAssets()
|
||||
}, [ocean, accountId, config.metadataCacheUri])
|
||||
|
||||
return <Table columns={columns} data={assets} isLoading={isLoading} />
|
||||
return (
|
||||
<Table
|
||||
columns={columns}
|
||||
className={styles.poolSharesTable}
|
||||
data={assets}
|
||||
pagination
|
||||
paginationPerPage={5}
|
||||
isLoading={loading}
|
||||
sortField="userLiquidity"
|
||||
sortAsc={false}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user