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({
|
export default function Conversion({
|
||||||
price,
|
price,
|
||||||
className
|
className,
|
||||||
|
hideApproximateSymbol
|
||||||
}: {
|
}: {
|
||||||
price: string // expects price in OCEAN, not wei
|
price: string // expects price in OCEAN, not wei
|
||||||
className?: string
|
className?: string
|
||||||
|
hideApproximateSymbol?: boolean
|
||||||
}): ReactElement {
|
}): ReactElement {
|
||||||
const { prices } = usePrices()
|
const { prices } = usePrices()
|
||||||
const { currency, locale } = useUserPreferences()
|
const { currency, locale } = useUserPreferences()
|
||||||
@ -59,7 +61,8 @@ export default function Conversion({
|
|||||||
className={styleClasses}
|
className={styleClasses}
|
||||||
title="Approximation based on current OCEAN spot price on Coingecko"
|
title="Approximation based on current OCEAN spot price on Coingecko"
|
||||||
>
|
>
|
||||||
≈ <strong dangerouslySetInnerHTML={{ __html: priceConverted }} />{' '}
|
{!hideApproximateSymbol && '≈ '}
|
||||||
|
<strong dangerouslySetInnerHTML={{ __html: priceConverted }} />{' '}
|
||||||
{!isFiat && currency}
|
{!isFiat && currency}
|
||||||
</span>
|
</span>
|
||||||
)
|
)
|
||||||
|
@ -15,10 +15,14 @@
|
|||||||
|
|
||||||
.table [role='columnheader'] {
|
.table [role='columnheader'] {
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
color: var(--color-secondary);
|
|
||||||
font-size: var(--font-size-small);
|
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) {
|
.table [role='row']:not(:last-of-type) {
|
||||||
border-color: var(--border-color);
|
border-color: var(--border-color);
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,9 @@ import styles from './Table.module.css'
|
|||||||
interface TableProps extends IDataTableProps {
|
interface TableProps extends IDataTableProps {
|
||||||
isLoading?: boolean
|
isLoading?: boolean
|
||||||
emptyMessage?: string
|
emptyMessage?: string
|
||||||
|
sortField?: string
|
||||||
|
sortAsc?: boolean
|
||||||
|
className?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
function Empty({ message }: { message?: string }): ReactElement {
|
function Empty({ message }: { message?: string }): ReactElement {
|
||||||
@ -19,13 +22,16 @@ export default function Table({
|
|||||||
emptyMessage,
|
emptyMessage,
|
||||||
pagination,
|
pagination,
|
||||||
paginationPerPage,
|
paginationPerPage,
|
||||||
|
sortField,
|
||||||
|
sortAsc,
|
||||||
|
className,
|
||||||
...props
|
...props
|
||||||
}: TableProps): ReactElement {
|
}: TableProps): ReactElement {
|
||||||
return (
|
return (
|
||||||
<DataTable
|
<DataTable
|
||||||
columns={columns}
|
columns={columns}
|
||||||
data={data}
|
data={data}
|
||||||
className={styles.table}
|
className={className ? styles.table + ` ${className}` : styles.table}
|
||||||
noHeader
|
noHeader
|
||||||
pagination={pagination || data?.length >= 9}
|
pagination={pagination || data?.length >= 9}
|
||||||
paginationPerPage={paginationPerPage || 10}
|
paginationPerPage={paginationPerPage || 10}
|
||||||
@ -33,6 +39,8 @@ export default function Table({
|
|||||||
noDataComponent={<Empty message={emptyMessage} />}
|
noDataComponent={<Empty message={emptyMessage} />}
|
||||||
progressPending={isLoading}
|
progressPending={isLoading}
|
||||||
progressComponent={<Loader />}
|
progressComponent={<Loader />}
|
||||||
|
defaultSortField={sortField}
|
||||||
|
defaultSortAsc={sortAsc}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
|
@ -115,6 +115,7 @@ export default function FormAdd({
|
|||||||
type="number"
|
type="number"
|
||||||
name="amount"
|
name="amount"
|
||||||
max={amountMax}
|
max={amountMax}
|
||||||
|
min="0"
|
||||||
value={`${values.amount}`}
|
value={`${values.amount}`}
|
||||||
step="any"
|
step="any"
|
||||||
prefix={<CoinSelect dtSymbol={dtSymbol} setCoin={setCoin} />}
|
prefix={<CoinSelect dtSymbol={dtSymbol} setCoin={setCoin} />}
|
||||||
|
@ -148,7 +148,6 @@ export default function Pool(): ReactElement {
|
|||||||
const totalCreatorLiquidityInOcean =
|
const totalCreatorLiquidityInOcean =
|
||||||
creatorLiquidity?.ocean + creatorLiquidity?.datatoken * price?.value
|
creatorLiquidity?.ocean + creatorLiquidity?.datatoken * price?.value
|
||||||
setCreatorTotalLiquidityInOcean(totalCreatorLiquidityInOcean)
|
setCreatorTotalLiquidityInOcean(totalCreatorLiquidityInOcean)
|
||||||
|
|
||||||
const creatorPoolShare =
|
const creatorPoolShare =
|
||||||
price?.ocean &&
|
price?.ocean &&
|
||||||
price?.datatoken &&
|
price?.datatoken &&
|
||||||
@ -174,7 +173,6 @@ export default function Pool(): ReactElement {
|
|||||||
const totalUserLiquidityInOcean =
|
const totalUserLiquidityInOcean =
|
||||||
userLiquidity?.ocean + userLiquidity?.datatoken * price?.value
|
userLiquidity?.ocean + userLiquidity?.datatoken * price?.value
|
||||||
setTotalUserLiquidityInOcean(totalUserLiquidityInOcean)
|
setTotalUserLiquidityInOcean(totalUserLiquidityInOcean)
|
||||||
|
|
||||||
const totalLiquidityInOcean = price?.ocean + price?.datatoken * price?.value
|
const totalLiquidityInOcean = price?.ocean + price?.datatoken * price?.value
|
||||||
setTotalLiquidityInOcean(totalLiquidityInOcean)
|
setTotalLiquidityInOcean(totalLiquidityInOcean)
|
||||||
}, [userLiquidity, price, poolTokens, totalPoolTokens])
|
}, [userLiquidity, price, poolTokens, totalPoolTokens])
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
font-weight: var(--font-weight-base) !important;
|
font-weight: var(--font-weight-base) !important;
|
||||||
font-size: var(--font-size-small);
|
font-size: var(--font-size-small);
|
||||||
padding-left: var(--font-size-base);
|
padding-left: var(--font-size-base);
|
||||||
padding-top: calc(var(--spacer) / 10);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.totalLiquidity strong {
|
.totalLiquidity strong {
|
||||||
@ -11,3 +10,51 @@
|
|||||||
color: var(--font-color-text);
|
color: var(--font-color-text);
|
||||||
line-height: 1;
|
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 React, { ReactElement, useEffect, useState } from 'react'
|
||||||
import Table from '../../atoms/Table'
|
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 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 {
|
||||||
|
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 {
|
interface Asset {
|
||||||
ddo: DDO
|
userLiquidity: number
|
||||||
shares: string
|
poolShare: PoolShare
|
||||||
}
|
}
|
||||||
|
|
||||||
function TotalLiquidity({ ddo }: { ddo: DDO }): ReactElement {
|
function calculateUserLiquidity(poolShare: PoolShare) {
|
||||||
const { price } = useMetadata(ddo)
|
const ocean =
|
||||||
const totalLiquidityInOcean = price?.ocean + price?.datatoken * price?.value
|
(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 (
|
return (
|
||||||
|
<div className={styles.yourLiquidity}>
|
||||||
<Conversion
|
<Conversion
|
||||||
price={`${totalLiquidityInOcean}`}
|
price={price}
|
||||||
className={styles.totalLiquidity}
|
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',
|
name: 'Data Set',
|
||||||
selector: function getAssetRow(row: Asset) {
|
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
|
grow: 2
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Datatoken',
|
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) {
|
selector: function getAssetRow(row: Asset) {
|
||||||
return <PriceUnit price={row.shares} symbol="pool shares" small />
|
return <Liquidity row={row} type="user" />
|
||||||
},
|
},
|
||||||
right: true
|
right: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Total Pool Liquidity',
|
name: 'Pool Liquidity',
|
||||||
selector: function getAssetRow(row: Asset) {
|
selector: function getAssetRow(row: Asset) {
|
||||||
return <TotalLiquidity ddo={row.ddo} />
|
return <Liquidity row={row} type="pool" />
|
||||||
},
|
},
|
||||||
right: true
|
right: true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
export default function PoolShares(): ReactElement {
|
export default function PoolShares(): ReactElement {
|
||||||
const { ocean, accountId, config } = useOcean()
|
const { accountId } = useOcean()
|
||||||
const [assets, setAssets] = useState<Asset[]>()
|
const [assets, setAssets] = useState<Asset[]>()
|
||||||
const [isLoading, setIsLoading] = useState(false)
|
const { data, loading } = useQuery<PoolSharesList>(poolSharesQuery, {
|
||||||
|
variables: {
|
||||||
|
user: accountId?.toLowerCase()
|
||||||
|
},
|
||||||
|
pollInterval: 20000
|
||||||
|
})
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
async function getAssets() {
|
if (!data) return
|
||||||
if (!ocean || !accountId || !config?.metadataCacheUri) return
|
const assetList: Asset[] = []
|
||||||
setIsLoading(true)
|
data.poolShares.forEach((poolShare) => {
|
||||||
|
const userLiquidity = calculateUserLiquidity(poolShare)
|
||||||
|
assetList.push({
|
||||||
|
poolShare: poolShare,
|
||||||
|
userLiquidity: userLiquidity
|
||||||
|
})
|
||||||
|
})
|
||||||
|
setAssets(assetList)
|
||||||
|
}, [data, loading])
|
||||||
|
|
||||||
try {
|
return (
|
||||||
const pools = await ocean.pool.getPoolSharesByAddress(accountId)
|
<Table
|
||||||
const metadataCache = new MetadataCache(config.metadataCacheUri, Logger)
|
columns={columns}
|
||||||
const result: Asset[] = []
|
className={styles.poolSharesTable}
|
||||||
|
data={assets}
|
||||||
for (const pool of pools) {
|
pagination
|
||||||
const ddo = await metadataCache.retrieveDDO(pool.did)
|
paginationPerPage={5}
|
||||||
ddo && result.push({ ddo, shares: pool.shares })
|
isLoading={loading}
|
||||||
}
|
sortField="userLiquidity"
|
||||||
|
sortAsc={false}
|
||||||
setAssets(result)
|
/>
|
||||||
} catch (error) {
|
)
|
||||||
Logger.error(error.message)
|
|
||||||
} finally {
|
|
||||||
setIsLoading(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
getAssets()
|
|
||||||
}, [ocean, accountId, config.metadataCacheUri])
|
|
||||||
|
|
||||||
return <Table columns={columns} data={assets} isLoading={isLoading} />
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user