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

Pool tab refactor (#1009)

* refactor and simplify

* fix user pool transaction section

* split up fetching and data manipulation

* restore refetch after add/remove, rename all the things

* more naming and logging

* new state structure unifying multiple data structures

* another response failsafe

* naming
This commit is contained in:
Matthias Kretschmann 2022-01-21 14:09:15 +00:00 committed by GitHub
parent 42323cb8c4
commit f55d8d9a91
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 399 additions and 329 deletions

View File

@ -25,6 +25,7 @@ import {
} from '../@types/subgraph/PoolShares' } from '../@types/subgraph/PoolShares'
import { OrdersData_orders as OrdersData } from '../@types/subgraph/OrdersData' import { OrdersData_orders as OrdersData } from '../@types/subgraph/OrdersData'
import { UserSalesQuery as UsersSalesList } from '../@types/subgraph/UserSalesQuery' import { UserSalesQuery as UsersSalesList } from '../@types/subgraph/UserSalesQuery'
import { PoolLiquidity } from 'src/@types/subgraph/PoolLiquidity'
export interface UserLiquidity { export interface UserLiquidity {
price: string price: string
@ -281,6 +282,44 @@ const TopSalesQuery = gql`
} }
` `
const poolLiquidityQuery = gql`
query PoolLiquidity($pool: ID!, $owner: String!) {
pool(id: $pool) {
id
totalShares
poolFee
opfFee
marketFee
spotPrice
baseToken {
address
symbol
}
baseTokenWeight
baseTokenLiquidity
datatoken {
address
symbol
}
datatokenWeight
datatokenLiquidity
shares(where: { user: $owner }) {
shares
}
}
}
`
const userPoolShareQuery = gql`
query PoolShare($pool: ID!, $user: String!) {
pool(id: $pool) {
shares(where: { user: $user }) {
shares
}
}
}
`
export function getSubgraphUri(chainId: number): string { export function getSubgraphUri(chainId: number): string {
const config = getOceanConfig(chainId) const config = getOceanConfig(chainId)
return config.subgraphUri return config.subgraphUri
@ -776,3 +815,37 @@ export async function getTopAssetsPublishers(
return publisherSales.slice(0, nrItems) return publisherSales.slice(0, nrItems)
} }
export async function getPoolData(
chainId: number,
pool: string,
owner: string
) {
const queryVariables = {
pool: pool.toLowerCase(),
owner: owner.toLowerCase()
}
const response: OperationResult<PoolLiquidity> = await fetchData(
poolLiquidityQuery,
queryVariables,
getQueryContext(chainId)
)
return response?.data?.pool
}
export async function getUserPoolShareBalance(
chainId: number,
pool: string,
accountId: string
): Promise<string> {
const queryVariables = {
pool: pool.toLowerCase(),
user: accountId.toLowerCase()
}
const response: OperationResult<PoolLiquidity> = await fetchData(
userPoolShareQuery,
queryVariables,
getQueryContext(chainId)
)
return response?.data?.pool?.shares[0]?.shares || '0'
}

View File

@ -1,5 +1,5 @@
.actions { .actions {
/* composes: container from './AssetActions/Pool/index.module.css'; */ composes: container from './Pool/index.module.css';
border-top: 1px solid var(--border-color); border-top: 1px solid var(--border-color);
margin-top: calc(var(--spacer) / 1.5); margin-top: calc(var(--spacer) / 1.5);
padding: calc(var(--spacer) / 1.5); padding: calc(var(--spacer) / 1.5);
@ -12,7 +12,7 @@
} }
.title { .title {
/* composes: title from './AssetActions/Pool/index.module.css'; */ composes: title from './Pool/index.module.css';
margin-bottom: 0; margin-bottom: 0;
display: flex; display: flex;
align-items: center; align-items: center;

View File

@ -25,22 +25,22 @@ const initialValues: FormAddLiquidity = {
export default function Add({ export default function Add({
setShowAdd, setShowAdd,
refreshInfo,
poolAddress, poolAddress,
totalPoolTokens, totalPoolTokens,
totalBalance, totalBalance,
swapFee, swapFee,
dtSymbol, dtSymbol,
dtAddress dtAddress,
fetchAllData
}: { }: {
setShowAdd: (show: boolean) => void setShowAdd: (show: boolean) => void
refreshInfo: () => void
poolAddress: string poolAddress: string
totalPoolTokens: string totalPoolTokens: string
totalBalance: PoolBalance totalBalance: PoolBalance
swapFee: string swapFee: string
dtSymbol: string dtSymbol: string
dtAddress: string dtAddress: string
fetchAllData: () => void
}): ReactElement { }): ReactElement {
const { accountId, balance, web3 } = useWeb3() const { accountId, balance, web3 } = useWeb3()
const { isAssetNetwork } = useAsset() const { isAssetNetwork } = useAsset()
@ -76,7 +76,7 @@ export default function Add({
setDtBalance(dtBalance) setDtBalance(dtBalance)
} }
getDtBalance() getDtBalance()
}, [web3, accountId, dtAddress, coin]) }, [web3, accountId, dtAddress, coin, isAssetNetwork])
// Get maximum amount for either OCEAN or datatoken // Get maximum amount for either OCEAN or datatoken
useEffect(() => { useEffect(() => {
@ -113,7 +113,7 @@ export default function Add({
// : await ocean.pool.addDTLiquidity(accountId, poolAddress, `${amount}`) // : await ocean.pool.addDTLiquidity(accountId, poolAddress, `${amount}`)
// setTxId(result?.transactionHash) // setTxId(result?.transactionHash)
// resetForm() // resetForm()
// refreshInfo() fetchAllData()
} catch (error) { } catch (error) {
console.error(error.message) console.error(error.message)
toast.error(error.message) toast.error(error.message)

View File

@ -25,18 +25,18 @@ import content from '../../../../../content/price.json'
export default function Remove({ export default function Remove({
setShowRemove, setShowRemove,
refreshInfo,
poolAddress, poolAddress,
poolTokens, poolTokens,
totalPoolTokens, totalPoolTokens,
dtSymbol dtSymbol,
fetchAllData
}: { }: {
setShowRemove: (show: boolean) => void setShowRemove: (show: boolean) => void
refreshInfo: () => void
poolAddress: string poolAddress: string
poolTokens: string poolTokens: string
totalPoolTokens: string totalPoolTokens: string
dtSymbol: string dtSymbol: string
fetchAllData: () => void
}): ReactElement { }): ReactElement {
const slippagePresets = ['5', '10', '15', '25', '50'] const slippagePresets = ['5', '10', '15', '25', '50']
const { accountId } = useWeb3() const { accountId } = useWeb3()
@ -74,7 +74,7 @@ export default function Remove({
// minOceanAmount // minOceanAmount
// ) // )
// setTxId(result?.transactionHash) // setTxId(result?.transactionHash)
// refreshInfo() fetchAllData()
} catch (error) { } catch (error) {
LoggerInstance.error(error.message) LoggerInstance.error(error.message)
toast.error(error.message) toast.error(error.message)

View File

@ -13,380 +13,369 @@ import TokenList from './TokenList'
import AssetActionHistoryTable from '../AssetActionHistoryTable' import AssetActionHistoryTable from '../AssetActionHistoryTable'
import Graph from './Graph' import Graph from './Graph'
import { useAsset } from '@context/Asset' import { useAsset } from '@context/Asset'
import { gql, OperationResult } from 'urql' import { PoolLiquidity_pool as PoolLiquidityData } from '../../../../@types/subgraph/PoolLiquidity'
import { PoolLiquidity } from '../../../../@types/subgraph/PoolLiquidity'
import { useWeb3 } from '@context/Web3' import { useWeb3 } from '@context/Web3'
import PoolTransactions from '@shared/PoolTransactions' import PoolTransactions from '@shared/PoolTransactions'
import { fetchData, getQueryContext } from '@utils/subgraph'
import { isValidNumber } from '@utils/numbers' import { isValidNumber } from '@utils/numbers'
import Decimal from 'decimal.js' import Decimal from 'decimal.js'
import content from '../../../../../content/price.json' import content from '../../../../../content/price.json'
import { getPoolData, getUserPoolShareBalance } from '@utils/subgraph'
Decimal.set({ toExpNeg: -18, precision: 18, rounding: 1 }) Decimal.set({ toExpNeg: -18, precision: 18, rounding: 1 })
const poolLiquidityQuery = gql` function getWeight(weight: string) {
query PoolLiquidity($pool: ID!, $owner: String) { return isValidNumber(weight) ? new Decimal(weight).mul(10).toString() : '0'
pool(id: $pool) { }
id
totalShares
poolFee
opfFee
marketFee
spotPrice
baseToken {
address
symbol
}
baseTokenWeight
baseTokenLiquidity
datatoken {
address
symbol
}
datatokenWeight
datatokenLiquidity
shares(where: { user: $owner }) {
shares
}
}
}
`
const userPoolShareQuery = gql` interface PoolInfo {
query PoolShare($pool: ID!, $user: String) { poolFee: string
pool(id: $pool) { weightOcean: string
id weightDt: string
shares(where: { user: $user }) { dtSymbol: string
shares oceanSymbol: string
} totalPoolTokens: string
} totalLiquidityInOcean: Decimal
} }
`
interface PoolInfoUser {
totalLiquidityInOcean: Decimal
liquidity: PoolBalance
poolShares: string
poolShare: string // in %
}
const initialPoolInfo: Partial<PoolInfo> = {
totalLiquidityInOcean: new Decimal(0)
}
const initialPoolInfoUser: Partial<PoolInfoUser> = {
totalLiquidityInOcean: new Decimal(0)
}
const initialPoolInfoCreator: Partial<PoolInfoUser> = initialPoolInfoUser
export default function Pool(): ReactElement { export default function Pool(): ReactElement {
const { accountId } = useWeb3() const { accountId } = useWeb3()
const [dtSymbol, setDtSymbol] = useState<string>()
const [oceanSymbol, setOceanSymbol] = useState<string>()
const { isInPurgatory, ddo, owner, price, refreshInterval, isAssetNetwork } = const { isInPurgatory, ddo, owner, price, refreshInterval, isAssetNetwork } =
useAsset() useAsset()
const [poolTokens, setPoolTokens] = useState<string>() const [poolData, setPoolData] = useState<PoolLiquidityData>()
const [totalPoolTokens, setTotalPoolTokens] = useState<string>() const [poolInfo, setPoolInfo] = useState<PoolInfo>(
const [userLiquidity, setUserLiquidity] = useState<PoolBalance>() initialPoolInfo as PoolInfo
const [swapFee, setSwapFee] = useState<string>() )
const [weightOcean, setWeightOcean] = useState<string>() const [poolInfoOwner, setPoolInfoOwner] = useState<PoolInfoUser>(
const [weightDt, setWeightDt] = useState<string>() initialPoolInfoCreator as PoolInfoUser
)
const [poolInfoUser, setPoolInfoUser] = useState<PoolInfoUser>(
initialPoolInfoUser as PoolInfoUser
)
const [hasUserAddedLiquidity, setUserHasAddedLiquidity] = useState(false)
const [showAdd, setShowAdd] = useState(false) const [showAdd, setShowAdd] = useState(false)
const [showRemove, setShowRemove] = useState(false) const [showRemove, setShowRemove] = useState(false)
const [isRemoveDisabled, setIsRemoveDisabled] = useState(false) const [isRemoveDisabled, setIsRemoveDisabled] = useState(false)
const [fetchInterval, setFetchInterval] = useState<NodeJS.Timeout>()
const [hasAddedLiquidity, setHasAddedLiquidity] = useState(false) const fetchPoolData = useCallback(async () => {
const [poolShare, setPoolShare] = useState<string>()
const [totalUserLiquidityInOcean, setTotalUserLiquidityInOcean] = useState(
new Decimal(0)
)
const [totalLiquidityInOcean, setTotalLiquidityInOcean] = useState(
new Decimal(0)
)
const [creatorTotalLiquidityInOcean, setCreatorTotalLiquidityInOcean] =
useState(new Decimal(0))
const [creatorLiquidity, setCreatorLiquidity] = useState<PoolBalance>()
const [creatorPoolTokens, setCreatorPoolTokens] = useState<string>()
const [creatorPoolShare, setCreatorPoolShare] = useState<string>()
const [dataLiquidity, setdataLiquidity] = useState<PoolLiquidity>()
const [liquidityFetchInterval, setLiquidityFetchInterval] =
useState<NodeJS.Timeout>()
// the purpose of the value is just to trigger the effect
const [refreshPool, setRefreshPool] = useState(false)
const getPoolLiquidity = useCallback(async () => {
if (!ddo?.chainId || !price?.address || !owner) return if (!ddo?.chainId || !price?.address || !owner) return
const queryVariables = { const poolData = await getPoolData(ddo.chainId, price.address, owner)
pool: price.address.toLowerCase(), setPoolData(poolData)
owner: owner.toLowerCase() LoggerInstance.log('[pool] Fetched pool data:', poolData)
}
const queryResult: OperationResult<PoolLiquidity> = await fetchData(
poolLiquidityQuery,
queryVariables,
getQueryContext(ddo.chainId)
)
setdataLiquidity(queryResult?.data)
}, [ddo?.chainId, price?.address, owner]) }, [ddo?.chainId, price?.address, owner])
async function getUserPoolShareBalance() { const fetchUserShares = useCallback(async () => {
const queryVariables = { if (!ddo?.chainId || !price?.address || !accountId) return
pool: price.address.toLowerCase(),
user: accountId.toLowerCase() const userShares = await getUserPoolShareBalance(
} ddo.chainId,
const queryResult: OperationResult<PoolLiquidity> = await fetchData( price.address,
userPoolShareQuery, accountId
queryVariables,
getQueryContext(ddo.chainId)
) )
return queryResult?.data.pool.shares[0]?.shares setPoolInfoUser((prevState) => ({
} ...prevState,
poolShares: userShares
}))
LoggerInstance.log(`[pool] Fetched user shares: ${userShares}`)
}, [ddo?.chainId, price?.address, accountId])
const refetchLiquidity = useCallback(() => { // Helper: fetch everything
if (liquidityFetchInterval) return const fetchAllData = useCallback(() => {
fetchPoolData()
fetchUserShares()
}, [fetchPoolData, fetchUserShares])
const newInterval = setInterval(() => getPoolLiquidity(), refreshInterval) // Helper: start interval fetching
setLiquidityFetchInterval(newInterval) const initFetchInterval = useCallback(() => {
}, [liquidityFetchInterval, getPoolLiquidity, refreshInterval]) if (fetchInterval) return
const newInterval = setInterval(() => {
fetchAllData()
LoggerInstance.log(
`[pool] Refetch interval fired after ${refreshInterval / 1000}s`
)
}, refreshInterval)
setFetchInterval(newInterval)
}, [fetchInterval, fetchAllData, refreshInterval])
useEffect(() => { useEffect(() => {
return () => { return () => {
clearInterval(liquidityFetchInterval) clearInterval(fetchInterval)
} }
}, [liquidityFetchInterval]) }, [fetchInterval])
//
// 0 Fetch all the data on mount
// All further effects depend on the fetched data
// and only do further data checking and manipulation.
//
useEffect(() => { useEffect(() => {
async function init() { fetchAllData()
if (!dataLiquidity?.pool) { initFetchInterval()
await getPoolLiquidity() }, [fetchAllData, initFetchInterval])
return
}
// Set symbols //
setOceanSymbol(dataLiquidity.pool.baseToken.symbol) // 1 General Pool Info
setDtSymbol(dataLiquidity.pool.datatoken.symbol) //
useEffect(() => {
if (!poolData || !price?.ocean || !price?.datatoken) return
// Total pool shares // Pool Fee (swap fee)
const totalPoolTokens = dataLiquidity.pool.totalShares // poolFee is tricky: to get 0.1% you need to convert from 0.001
setTotalPoolTokens(totalPoolTokens) const poolFee = isValidNumber(poolData.poolFee)
? new Decimal(poolData.poolFee).mul(100).toString()
: '0'
// Get poolFee // Total Liquidity
// poolFee is tricky: to get 0.1% you need to convert from 0.001 const totalLiquidityInOcean =
const swapFee = isValidNumber(dataLiquidity.pool.poolFee) isValidNumber(price.ocean) &&
? new Decimal(dataLiquidity.pool.poolFee).mul(100).toString() isValidNumber(price.datatoken) &&
isValidNumber(poolData.spotPrice)
? new Decimal(price.ocean).add(
new Decimal(price.datatoken).mul(poolData.spotPrice)
)
: new Decimal(0)
const newPoolInfo = {
poolFee,
weightOcean: getWeight(poolData.baseTokenWeight),
weightDt: getWeight(poolData.datatokenWeight),
dtSymbol: poolData.datatoken.symbol,
oceanSymbol: poolData.baseToken.symbol,
totalPoolTokens: poolData.totalShares,
totalLiquidityInOcean
}
setPoolInfo(newPoolInfo)
LoggerInstance.log('[pool] Created new pool info:', newPoolInfo)
}, [poolData, price?.datatoken, price?.ocean])
//
// 2 Pool Creator Info
//
useEffect(() => {
if (
!poolData ||
!poolInfo?.totalPoolTokens ||
!price?.ocean ||
!price?.datatoken
)
return
const ownerPoolTokens = poolData.shares[0]?.shares
const ownerOceanBalance =
isValidNumber(ownerPoolTokens) &&
isValidNumber(poolInfo.totalPoolTokens) &&
isValidNumber(price.ocean)
? new Decimal(ownerPoolTokens)
.dividedBy(new Decimal(poolInfo.totalPoolTokens))
.mul(price.ocean)
.toString()
: '0' : '0'
setSwapFee(swapFee)
// Get weights const ownerDtBalance =
function getWeight(weight: string) { isValidNumber(ownerPoolTokens) &&
return isValidNumber(weight) isValidNumber(poolInfo.totalPoolTokens) &&
? new Decimal(weight).mul(10).toString() isValidNumber(price.datatoken)
: '0' ? new Decimal(ownerPoolTokens)
} .dividedBy(new Decimal(poolInfo.totalPoolTokens))
const weightDt = dataLiquidity.pool.datatokenWeight .mul(price.datatoken)
const weightDtDecimal = getWeight(weightDt) .toString()
setWeightDt(weightDtDecimal) : '0'
const weightOcean = dataLiquidity.pool.baseTokenWeight const liquidity = {
const weightOceanDecimal = getWeight(weightOcean) ocean: ownerOceanBalance,
setWeightOcean(weightOceanDecimal) datatoken: ownerDtBalance
//
// Get everything the creator put into the pool
//
const creatorPoolTokens = dataLiquidity.pool.shares[0]?.shares
setCreatorPoolTokens(creatorPoolTokens)
const creatorOceanBalance =
isValidNumber(creatorPoolTokens) &&
isValidNumber(totalPoolTokens) &&
isValidNumber(price.ocean)
? new Decimal(creatorPoolTokens)
.dividedBy(new Decimal(totalPoolTokens))
.mul(price.ocean)
.toString()
: '0'
const creatorDtBalance =
isValidNumber(creatorPoolTokens) &&
isValidNumber(totalPoolTokens) &&
isValidNumber(price.datatoken)
? new Decimal(creatorPoolTokens)
.dividedBy(new Decimal(totalPoolTokens))
.mul(price.datatoken)
.toString()
: '0'
const creatorLiquidity = {
ocean: creatorOceanBalance,
datatoken: creatorDtBalance
}
setCreatorLiquidity(creatorLiquidity)
const totalCreatorLiquidityInOcean =
isValidNumber(creatorLiquidity?.ocean) &&
isValidNumber(creatorLiquidity?.datatoken) &&
isValidNumber(dataLiquidity.pool.spotPrice)
? new Decimal(creatorLiquidity?.ocean).add(
new Decimal(creatorLiquidity?.datatoken).mul(
new Decimal(dataLiquidity.pool.spotPrice)
)
)
: new Decimal(0)
setCreatorTotalLiquidityInOcean(totalCreatorLiquidityInOcean)
const creatorPoolShare =
price?.ocean &&
price?.datatoken &&
creatorLiquidity &&
isValidNumber(creatorPoolTokens) &&
isValidNumber(totalPoolTokens)
? new Decimal(creatorPoolTokens)
.dividedBy(new Decimal(totalPoolTokens))
.mul(100)
.toFixed(2)
: '0'
setCreatorPoolShare(creatorPoolShare)
refetchLiquidity()
} }
init()
}, [
dataLiquidity,
price?.datatoken,
price?.ocean,
getPoolLiquidity,
refetchLiquidity
])
useEffect(() => { const totalLiquidityInOcean =
setIsRemoveDisabled(isInPurgatory && owner === accountId) isValidNumber(liquidity.ocean) &&
}, [isInPurgatory, owner, accountId]) isValidNumber(liquidity.datatoken) &&
isValidNumber(poolData.spotPrice)
useEffect(() => { ? new Decimal(liquidity.ocean).add(
if (!dataLiquidity) return new Decimal(liquidity.datatoken).mul(
new Decimal(poolData.spotPrice)
)
)
: new Decimal(0)
const poolShare = const poolShare =
isValidNumber(poolTokens) && liquidity &&
isValidNumber(totalPoolTokens) && isValidNumber(ownerPoolTokens) &&
price?.ocean && isValidNumber(poolInfo.totalPoolTokens)
price?.datatoken && ? new Decimal(ownerPoolTokens)
new Decimal(poolTokens) .dividedBy(new Decimal(poolInfo.totalPoolTokens))
.dividedBy(new Decimal(totalPoolTokens)) .mul(100)
.toFixed(2)
: '0'
const newPoolOwnerInfo = {
totalLiquidityInOcean,
liquidity,
poolShares: ownerPoolTokens,
poolShare
}
setPoolInfoOwner(newPoolOwnerInfo)
LoggerInstance.log('[pool] Created new owner pool info:', newPoolOwnerInfo)
}, [poolData, price?.ocean, price?.datatoken, poolInfo?.totalPoolTokens])
//
// 3 User Pool Info
//
useEffect(() => {
if (
!poolData?.spotPrice ||
!poolInfo?.totalPoolTokens ||
!ddo?.chainId ||
!accountId ||
!price?.ocean ||
!price?.datatoken
)
return
const poolShare =
isValidNumber(poolInfoUser.poolShares) &&
isValidNumber(poolInfo.totalPoolTokens) &&
new Decimal(poolInfoUser.poolShares)
.dividedBy(new Decimal(poolInfo.totalPoolTokens))
.mul(100) .mul(100)
.toFixed(5) .toFixed(5)
setPoolShare(poolShare) setUserHasAddedLiquidity(Number(poolShare) > 0)
setHasAddedLiquidity(Number(poolShare) > 0)
const totalUserLiquidityInOcean = // calculate user's provided liquidity based on pool tokens
isValidNumber(userLiquidity?.ocean) && const userOceanBalance =
isValidNumber(userLiquidity?.datatoken) && isValidNumber(poolInfoUser.poolShares) &&
isValidNumber(dataLiquidity.pool.spotPrice) isValidNumber(poolInfo.totalPoolTokens) &&
? new Decimal(userLiquidity?.ocean).add( isValidNumber(price.ocean)
new Decimal(userLiquidity?.datatoken).mul( ? new Decimal(poolInfoUser.poolShares)
dataLiquidity.pool.spotPrice .dividedBy(new Decimal(poolInfo.totalPoolTokens))
) .mul(price.ocean)
) .toString()
: new Decimal(0) : '0'
setTotalUserLiquidityInOcean(totalUserLiquidityInOcean) const userDtBalance =
isValidNumber(poolInfoUser.poolShares) &&
isValidNumber(poolInfo.totalPoolTokens) &&
isValidNumber(price.datatoken)
? new Decimal(poolInfoUser.poolShares)
.dividedBy(new Decimal(poolInfo.totalPoolTokens))
.mul(price.datatoken)
.toString()
: '0'
const liquidity = {
ocean: userOceanBalance,
datatoken: userDtBalance
}
const totalLiquidityInOcean = const totalLiquidityInOcean =
isValidNumber(price?.ocean) && isValidNumber(liquidity.ocean) &&
isValidNumber(price?.datatoken) && isValidNumber(liquidity.datatoken) &&
isValidNumber(dataLiquidity.pool.spotPrice) isValidNumber(poolData.spotPrice)
? new Decimal(price?.ocean).add( ? new Decimal(liquidity.ocean).add(
new Decimal(price?.datatoken).mul(dataLiquidity.pool.spotPrice) new Decimal(liquidity.datatoken).mul(poolData.spotPrice)
) )
: new Decimal(0) : new Decimal(0)
setTotalLiquidityInOcean(totalLiquidityInOcean) const newPoolInfoUser = {
}, [dataLiquidity, userLiquidity, price, poolTokens, totalPoolTokens]) totalLiquidityInOcean,
liquidity,
useEffect(() => { poolShare
if (!accountId || !price) return
async function init() {
try {
//
// Get everything the user has put into the pool
//
const poolTokens = await getUserPoolShareBalance()
setPoolTokens(poolTokens)
// calculate user's provided liquidity based on pool tokens
const userOceanBalance =
isValidNumber(poolTokens) &&
isValidNumber(totalPoolTokens) &&
isValidNumber(price.ocean)
? new Decimal(poolTokens)
.dividedBy(new Decimal(totalPoolTokens))
.mul(price.ocean)
.toString()
: '0'
const userDtBalance =
isValidNumber(poolTokens) &&
isValidNumber(totalPoolTokens) &&
isValidNumber(price.datatoken)
? new Decimal(poolTokens)
.dividedBy(new Decimal(totalPoolTokens))
.mul(price.datatoken)
.toString()
: '0'
const userLiquidity = {
ocean: userOceanBalance,
datatoken: userDtBalance
}
setUserLiquidity(userLiquidity)
} catch (error) {
LoggerInstance.error(error.message)
}
} }
init() setPoolInfoUser((prevState: PoolInfoUser) => ({
}, [accountId, price, ddo, refreshPool, owner, totalPoolTokens]) ...prevState,
...newPoolInfoUser
}))
const refreshInfo = async () => { LoggerInstance.log('[pool] Created new user pool info:', {
setRefreshPool(!refreshPool) poolShares: poolInfoUser?.poolShares,
...newPoolInfoUser
})
}, [
poolData?.spotPrice,
poolInfoUser?.poolShares,
accountId,
price,
ddo?.chainId,
owner,
poolInfo?.totalPoolTokens
])
// need some form of replacement or something. //
// await refreshPrice() // Check if removing liquidity should be disabled.
} //
useEffect(() => {
if (!owner || !accountId) return
setIsRemoveDisabled(isInPurgatory && owner === accountId)
}, [isInPurgatory, owner, accountId])
return ( return (
<> <>
{showAdd ? ( {showAdd ? (
<Add <Add
setShowAdd={setShowAdd} setShowAdd={setShowAdd}
refreshInfo={refreshInfo} poolAddress={price?.address}
poolAddress={price.address} totalPoolTokens={poolInfo.totalPoolTokens}
totalPoolTokens={totalPoolTokens}
totalBalance={{ totalBalance={{
ocean: new Decimal(price.ocean).toString(), ocean: new Decimal(price?.ocean).toString(),
datatoken: new Decimal(price.datatoken).toString() datatoken: new Decimal(price?.datatoken).toString()
}} }}
swapFee={swapFee} swapFee={poolInfo.poolFee}
dtSymbol={dtSymbol} dtSymbol={poolInfo.dtSymbol}
dtAddress={ddo.services[0].datatokenAddress} dtAddress={ddo?.services[0].datatokenAddress}
fetchAllData={fetchAllData}
/> />
) : showRemove ? ( ) : showRemove ? (
<Remove <Remove
setShowRemove={setShowRemove} setShowRemove={setShowRemove}
refreshInfo={refreshInfo} poolAddress={price?.address}
poolAddress={price.address} poolTokens={poolInfoUser.poolShares}
poolTokens={poolTokens} totalPoolTokens={poolInfo?.totalPoolTokens}
totalPoolTokens={totalPoolTokens} dtSymbol={poolInfo?.dtSymbol}
dtSymbol={dtSymbol} fetchAllData={fetchAllData}
/> />
) : ( ) : (
<> <>
<div className={styles.dataToken}> <div className={styles.dataToken}>
<PriceUnit price="1" symbol={dtSymbol} /> ={' '} <PriceUnit price="1" symbol={poolInfo?.dtSymbol} /> ={' '}
<PriceUnit price={`${price?.value}`} symbol={oceanSymbol} /> <PriceUnit
price={`${price?.value}`}
symbol={poolInfo?.oceanSymbol}
/>
<Tooltip content={content.pool.tooltips.price} /> <Tooltip content={content.pool.tooltips.price} />
<div className={styles.dataTokenLinks}> <div className={styles.dataTokenLinks}>
<ExplorerLink <ExplorerLink
networkId={ddo.chainId} networkId={ddo?.chainId}
path={`address/${price?.address}`} path={`address/${price?.address}`}
> >
Pool Pool
</ExplorerLink> </ExplorerLink>
<ExplorerLink <ExplorerLink
networkId={ddo.chainId} networkId={ddo?.chainId}
path={ path={
ddo.chainId === 2021000 || ddo.chainId === 1287 ddo?.chainId === 2021000 || ddo?.chainId === 1287
? `tokens/${ddo.services[0].datatokenAddress}` ? `tokens/${ddo.services[0].datatokenAddress}`
: `token/${ddo.services[0].datatokenAddress}` : `token/${ddo.services[0].datatokenAddress}`
} }
@ -403,58 +392,66 @@ export default function Pool(): ReactElement {
<Tooltip <Tooltip
content={content.pool.tooltips.liquidity.replace( content={content.pool.tooltips.liquidity.replace(
'SWAPFEE', 'SWAPFEE',
swapFee poolInfo?.poolFee
)} )}
/> />
</> </>
} }
ocean={`${userLiquidity?.ocean}`} ocean={`${poolInfoUser?.liquidity?.ocean}`}
oceanSymbol={oceanSymbol} oceanSymbol={poolInfo?.oceanSymbol}
dt={`${userLiquidity?.datatoken}`} dt={`${poolInfoUser?.liquidity?.datatoken}`}
dtSymbol={dtSymbol} dtSymbol={poolInfo?.dtSymbol}
poolShares={poolTokens} poolShares={poolInfoUser?.poolShares}
conversion={totalUserLiquidityInOcean} conversion={poolInfoUser?.totalLiquidityInOcean}
highlight highlight
> >
<Token symbol="% of pool" balance={poolShare} noIcon /> <Token
symbol="% of pool"
balance={poolInfoUser?.poolShare}
noIcon
/>
</TokenList> </TokenList>
<TokenList <TokenList
title="Pool Creator Statistics" title="Pool Creator Statistics"
ocean={`${creatorLiquidity?.ocean}`} ocean={`${poolInfoOwner?.liquidity?.ocean}`}
oceanSymbol={oceanSymbol} oceanSymbol={poolInfo?.oceanSymbol}
dt={`${creatorLiquidity?.datatoken}`} dt={`${poolInfoOwner?.liquidity?.datatoken}`}
dtSymbol={dtSymbol} dtSymbol={poolInfo?.dtSymbol}
poolShares={creatorPoolTokens} poolShares={poolInfoOwner?.poolShares}
conversion={creatorTotalLiquidityInOcean} conversion={poolInfoOwner?.totalLiquidityInOcean}
> >
<Token symbol="% of pool" balance={creatorPoolShare} noIcon /> <Token
symbol="% of pool"
balance={poolInfoOwner?.poolShare}
noIcon
/>
</TokenList> </TokenList>
<TokenList <TokenList
title={ title={
<> <>
Pool Statistics Pool Statistics
{weightDt && ( {poolInfo?.weightDt && (
<span <span
className={styles.titleInfo} className={styles.titleInfo}
title={`Weight of ${weightOcean}% OCEAN & ${weightDt}% ${dtSymbol}`} title={`Weight of ${poolInfo?.weightOcean}% OCEAN & ${poolInfo?.weightDt}% ${poolInfo?.dtSymbol}`}
> >
{weightOcean}/{weightDt} {poolInfo?.weightOcean}/{poolInfo?.weightDt}
</span> </span>
)} )}
<Graph /> <Graph />
</> </>
} }
ocean={`${price?.ocean}`} ocean={`${price?.ocean}`}
oceanSymbol={oceanSymbol} oceanSymbol={poolInfo?.oceanSymbol}
dt={`${price?.datatoken}`} dt={`${price?.datatoken}`}
dtSymbol={dtSymbol} dtSymbol={poolInfo?.dtSymbol}
poolShares={totalPoolTokens} poolShares={poolInfo?.totalPoolTokens}
conversion={totalLiquidityInOcean} conversion={poolInfo?.totalLiquidityInOcean}
showTVLLabel showTVLLabel
> >
<Token symbol="% swap fee" balance={swapFee} noIcon /> <Token symbol="% pool fee" balance={poolInfo?.poolFee} noIcon />
</TokenList> </TokenList>
<div className={styles.update}> <div className={styles.update}>
@ -471,7 +468,7 @@ export default function Pool(): ReactElement {
Add Liquidity Add Liquidity
</Button> </Button>
{hasAddedLiquidity && !isRemoveDisabled && ( {hasUserAddedLiquidity && !isRemoveDisabled && (
<Button <Button
size="small" size="small"
onClick={() => setShowRemove(true)} onClick={() => setShowRemove(true)}
@ -487,7 +484,7 @@ export default function Pool(): ReactElement {
<PoolTransactions <PoolTransactions
accountId={accountId} accountId={accountId}
poolAddress={price?.address} poolAddress={price?.address}
poolChainId={[ddo.chainId]} poolChainId={[ddo?.chainId]}
minimal minimal
/> />
</AssetActionHistoryTable> </AssetActionHistoryTable>