1
0
mirror of https://github.com/oceanprotocol/market.git synced 2024-06-26 03:06:49 +02:00

Update Number to Decimal (#653)

* update number to decimal

* Update FormTrade.tsx

* update Pool/index.tsx

* update Pool/utils.ts

* update FormAdd.tsx

* update bugs from switching to decimal

* fixed errors in Output.tsx

* rebase main

* Update FormTrade.tsx

* update Pool/index.tsx

* update Pool/utils.ts

* update FormAdd.tsx

* update bugs from switching to decimal

* fixed errors in Output.tsx

* remove duplication

* added missed conversion

* fix style error

* fixes

* added function return type

* add correct return type for function

Co-authored-by: Matthias Kretschmann <m@kretschmann.io>
This commit is contained in:
Dimo Dzhurenov 2021-08-24 11:11:01 +03:00 committed by GitHub
parent a82ad003e2
commit bccb56a181
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 268 additions and 85 deletions

View File

@ -1,6 +1,6 @@
export interface PoolBalance {
ocean: number
datatoken: number
ocean: string
datatoken: string
}
export interface UserBalance {

View File

@ -15,6 +15,9 @@ import UserLiquidity from '../../../../atoms/UserLiquidity'
import { useOcean } from '../../../../../providers/Ocean'
import { useWeb3 } from '../../../../../providers/Web3'
import { isValidNumber } from './../../../../../utils/numberValidations'
import Decimal from 'decimal.js'
export default function FormAdd({
coin,
dtBalance,
@ -67,6 +70,7 @@ export default function FormAdd({
setNewPoolShare('0')
return
}
if (Number(values.amount) > Number(amountMax)) return
const poolTokens = await ocean.pool.calcPoolOutGivenSingleIn(
@ -74,15 +78,20 @@ export default function FormAdd({
coin === 'OCEAN' ? ocean.pool.oceanAddress : ocean.pool.dtAddress,
`${values.amount}`
)
setNewPoolTokens(poolTokens)
totalBalance &&
setNewPoolShare(
`${
(Number(poolTokens) /
(Number(totalPoolTokens) + Number(poolTokens))) *
100
}`
)
const newPoolShareDecimal =
isValidNumber(poolTokens) && isValidNumber(totalPoolTokens)
? new Decimal(poolTokens)
.dividedBy(
new Decimal(totalPoolTokens).plus(new Decimal(poolTokens))
)
.mul(100)
.toString()
: '0'
totalBalance && setNewPoolShare(newPoolShareDecimal)
}
calculatePoolShares()
}, [

View File

@ -2,6 +2,7 @@ import Conversion from '../../../atoms/Price/Conversion'
import React, { ReactElement, ReactNode } from 'react'
import Token from './Token'
import styles from './TokenList.module.css'
import Decimal from 'decimal.js'
export default function TokenList({
title,
@ -20,7 +21,7 @@ export default function TokenList({
dt: string
dtSymbol: string
poolShares: string
conversion: number
conversion: Decimal
highlight?: boolean
showTVLLabel?: boolean
}): ReactElement {
@ -31,9 +32,9 @@ export default function TokenList({
<div>
<Token symbol="OCEAN" balance={ocean} />
<Token symbol={dtSymbol} balance={dt} />
{conversion > 0 && (
{conversion.greaterThan(0) && (
<Conversion
price={`${conversion}`}
price={conversion.toString()}
className={styles.totalLiquidity}
showTVLLabel={showTVLLabel}
/>

View File

@ -22,8 +22,13 @@ import { useWeb3 } from '../../../../providers/Web3'
import PoolTransactions from '../../../molecules/PoolTransactions'
import { fetchData, getQueryContext } from '../../../../utils/subgraph'
import { isValidNumber } from './../../../../utils/numberValidations'
import Decimal from 'decimal.js'
const REFETCH_INTERVAL = 5000
Decimal.set({ toExpNeg: -18, precision: 18, rounding: 1 })
const contentQuery = graphql`
query PoolQuery {
content: allFile(filter: { relativePath: { eq: "price.json" } }) {
@ -85,11 +90,15 @@ export default function Pool(): ReactElement {
const [hasAddedLiquidity, setHasAddedLiquidity] = useState(false)
const [poolShare, setPoolShare] = useState<string>()
const [totalUserLiquidityInOcean, setTotalUserLiquidityInOcean] = useState(0)
const [totalLiquidityInOcean, setTotalLiquidityInOcean] = useState(0)
const [totalUserLiquidityInOcean, setTotalUserLiquidityInOcean] = useState(
new Decimal(0)
)
const [totalLiquidityInOcean, setTotalLiquidityInOcean] = useState(
new Decimal(0)
)
const [creatorTotalLiquidityInOcean, setCreatorTotalLiquidityInOcean] =
useState(0)
useState(new Decimal(0))
const [creatorLiquidity, setCreatorLiquidity] = useState<PoolBalance>()
const [creatorPoolTokens, setCreatorPoolTokens] = useState<string>()
const [creatorPoolShare, setCreatorPoolShare] = useState<string>()
@ -144,15 +153,28 @@ export default function Pool(): ReactElement {
// Get swap fee
// swapFee is tricky: to get 0.1% you need to convert from 0.001
setSwapFee(`${Number(dataLiquidity.pool.swapFee) * 100}`)
const swapFee = isValidNumber(dataLiquidity.pool.swapFee)
? new Decimal(dataLiquidity.pool.swapFee).mul(100).toString()
: '0'
setSwapFee(swapFee)
// Get weights
const weightDt = dataLiquidity.pool.tokens.filter(
(token: any) => token.tokenAddress === ddo.dataToken.toLowerCase()
)[0].denormWeight
setWeightDt(`${Number(weightDt) * 10}`)
setWeightOcean(`${100 - Number(weightDt) * 10}`)
const weightDtDecimal = isValidNumber(weightDt)
? new Decimal(weightDt).mul(10).toString()
: '0'
setWeightDt(weightDtDecimal)
const weightOceanDecimal = isValidNumber(weightDt)
? new Decimal(100).minus(new Decimal(weightDt).mul(10)).toString()
: '0'
setWeightOcean(weightOceanDecimal)
//
// Get everything the creator put into the pool
@ -161,12 +183,25 @@ export default function Pool(): ReactElement {
const creatorPoolTokens = dataLiquidity.pool.shares[0].balance
setCreatorPoolTokens(creatorPoolTokens)
// Calculate creator's provided liquidity based on pool tokens
const creatorOceanBalance =
(Number(creatorPoolTokens) / Number(totalPoolTokens)) * price.ocean
isValidNumber(creatorPoolTokens) &&
isValidNumber(totalPoolTokens) &&
isValidNumber(price.ocean)
? new Decimal(creatorPoolTokens)
.dividedBy(new Decimal(totalPoolTokens))
.mul(price.ocean)
.toString()
: '0'
const creatorDtBalance =
(Number(creatorPoolTokens) / Number(totalPoolTokens)) * price.datatoken
isValidNumber(creatorPoolTokens) &&
isValidNumber(totalPoolTokens) &&
isValidNumber(price.datatoken)
? new Decimal(creatorPoolTokens)
.dividedBy(new Decimal(totalPoolTokens))
.mul(price.datatoken)
.toString()
: '0'
const creatorLiquidity = {
ocean: creatorOceanBalance,
@ -175,14 +210,30 @@ export default function Pool(): ReactElement {
setCreatorLiquidity(creatorLiquidity)
const totalCreatorLiquidityInOcean =
creatorLiquidity?.ocean +
creatorLiquidity?.datatoken * dataLiquidity.pool.spotPrice
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 &&
((Number(creatorPoolTokens) / Number(totalPoolTokens)) * 100).toFixed(2)
isValidNumber(creatorPoolTokens) &&
isValidNumber(totalPoolTokens)
? new Decimal(creatorPoolTokens)
.dividedBy(new Decimal(totalPoolTokens))
.mul(100)
.toFixed(2)
: '0'
setCreatorPoolShare(creatorPoolShare)
refetchLiquidity()
}
@ -195,17 +246,38 @@ export default function Pool(): ReactElement {
useEffect(() => {
const poolShare =
isValidNumber(poolTokens) &&
isValidNumber(totalPoolTokens) &&
price?.ocean &&
price?.datatoken &&
((Number(poolTokens) / Number(totalPoolTokens)) * 100).toFixed(5)
new Decimal(poolTokens)
.dividedBy(new Decimal(totalPoolTokens))
.mul(100)
.toFixed(5)
setPoolShare(poolShare)
setHasAddedLiquidity(Number(poolShare) > 0)
const totalUserLiquidityInOcean =
userLiquidity?.ocean + userLiquidity?.datatoken * price?.value
isValidNumber(userLiquidity?.ocean) &&
isValidNumber(userLiquidity?.datatoken) &&
isValidNumber(price?.value)
? new Decimal(userLiquidity?.ocean).add(
new Decimal(userLiquidity?.datatoken).mul(price?.value)
)
: new Decimal(0)
setTotalUserLiquidityInOcean(totalUserLiquidityInOcean)
const totalLiquidityInOcean =
Number(price?.ocean) + Number(price?.datatoken) * Number(price?.value)
isValidNumber(price?.ocean) &&
isValidNumber(price?.datatoken) &&
isValidNumber(price?.value)
? new Decimal(price?.ocean).add(
new Decimal(price?.datatoken).mul(price?.value)
)
: new Decimal(0)
setTotalLiquidityInOcean(totalLiquidityInOcean)
}, [userLiquidity, price, poolTokens, totalPoolTokens])
@ -221,11 +293,28 @@ export default function Pool(): ReactElement {
price.address
)
setPoolTokens(poolTokens)
// calculate user's provided liquidity based on pool tokens
const userOceanBalance =
(Number(poolTokens) / Number(totalPoolTokens)) * price.ocean
isValidNumber(poolTokens) &&
isValidNumber(totalPoolTokens) &&
isValidNumber(price.ocean)
? new Decimal(poolTokens)
.dividedBy(new Decimal(totalPoolTokens))
.mul(price.ocean)
.toString()
: '0'
const userDtBalance =
(Number(poolTokens) / Number(totalPoolTokens)) * price.datatoken
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
@ -255,8 +344,8 @@ export default function Pool(): ReactElement {
poolAddress={price.address}
totalPoolTokens={totalPoolTokens}
totalBalance={{
ocean: price.ocean,
datatoken: price.datatoken
ocean: new Decimal(price.ocean).toString(),
datatoken: new Decimal(price.datatoken).toString()
}}
swapFee={swapFee}
dtSymbol={dtSymbol}

View File

@ -1,5 +1,10 @@
import { Ocean } from '@oceanprotocol/lib'
import { isValidNumber } from './../../../../utils/numberValidations'
import Decimal from 'decimal.js'
Decimal.set({ toExpNeg: -18, precision: 18, rounding: 1 })
export async function getMaxPercentRemove(
ocean: Ocean,
poolAddress: string,
@ -15,9 +20,15 @@ export async function getMaxPercentRemove(
amountMaxOcean
)
let amountMaxPercent = `${Math.floor(
(Number(amountMaxPoolShares) / Number(poolTokens)) * 100
)}`
let amountMaxPercent =
isValidNumber(amountMaxPoolShares) && isValidNumber(poolTokens)
? new Decimal(amountMaxPoolShares)
.dividedBy(new Decimal(poolTokens))
.mul(100)
.floor()
.toString()
: '0'
if (Number(amountMaxPercent) > 100) {
amountMaxPercent = '100'
}

View File

@ -42,8 +42,8 @@ export default function FormTrade({
}: {
ddo: DDO
balance: PoolBalance
maxDt: number
maxOcean: number
maxDt: string
maxOcean: string
price: BestPrice
}): ReactElement {
const data = useStaticQuery(contentQuery)
@ -61,12 +61,18 @@ export default function FormTrade({
const validationSchema: Yup.SchemaOf<FormTradeData> = Yup.object()
.shape({
ocean: Yup.number()
.max(maximumOcean, (param) => `Must be more or equal to ${param.max}`)
.max(
Number(maximumOcean),
(param) => `Must be more or equal to ${param.max}`
)
.min(0.001, (param) => `Must be more or equal to ${param.min}`)
.required('Required')
.nullable(),
datatoken: Yup.number()
.max(maximumDt, (param) => `Must be less or equal than ${param.max}`)
.max(
Number(maximumDt),
(param) => `Must be less or equal than ${param.max}`
)
.min(0.00001, (param) => `Must be more or equal to ${param.min}`)
.required('Required')
.nullable(),
@ -77,7 +83,9 @@ export default function FormTrade({
async function handleTrade(values: FormTradeData) {
try {
const impact = new Decimal(100 - Number(values.slippage)).div(100)
const impact = new Decimal(
new Decimal(100).sub(new Decimal(values.slippage))
).div(100)
const precision = 15
const tx =
values.type === 'buy'

View File

@ -5,6 +5,11 @@ import { useOcean } from '../../../../providers/Ocean'
import Token from '../Pool/Token'
import styles from './Output.module.css'
import { isValidNumber } from './../../../../utils/numberValidations'
import Decimal from 'decimal.js'
Decimal.set({ toExpNeg: -18, precision: 18, rounding: 1 })
export default function Output({
dtSymbol,
poolAddress
@ -25,12 +30,20 @@ export default function Output({
async function getSwapFee() {
const swapFee = await ocean.pool.getSwapFee(poolAddress)
// swapFee is tricky: to get 0.1% you need to convert from 0.001
setSwapFee(`${Number(swapFee) * 100}`)
setSwapFee(
isValidNumber(swapFee) ? new Decimal(swapFee).mul(100).toString() : '0'
)
const value =
values.type === 'buy'
? Number(swapFee) * values.ocean
: Number(swapFee) * values.datatoken
? isValidNumber(swapFee) && isValidNumber(values.ocean)
? new Decimal(swapFee).mul(new Decimal(values.ocean))
: 0
: isValidNumber(swapFee) && isValidNumber(values.datatoken)
? new Decimal(swapFee).mul(new Decimal(values.datatoken))
: 0
setSwapFeeValue(value.toString())
}
getSwapFee()
@ -46,8 +59,14 @@ export default function Output({
const maxImpact = 1 - Number(values.slippage) / 100
const maxPrice =
values.type === 'buy'
? (values.datatoken * maxImpact).toString()
: (values.ocean * maxImpact).toString()
? isValidNumber(values.datatoken) && isValidNumber(maxImpact)
? new Decimal(values.datatoken)
.mul(new Decimal(maxImpact))
.toString()
: '0'
: isValidNumber(values.ocean) && isValidNumber(maxImpact)
? new Decimal(values.ocean).mul(new Decimal(maxImpact)).toString()
: '0'
setMaxOutput(maxPrice)
}

View File

@ -12,6 +12,10 @@ import { FormTradeData, TradeItem } from '../../../../models/FormTrade'
import { useOcean } from '../../../../providers/Ocean'
import PriceImpact from './PriceImpact'
import Decimal from 'decimal.js'
Decimal.set({ toExpNeg: -18, precision: 18, rounding: 1 })
export default function Swap({
ddo,
maxDt,
@ -22,23 +26,23 @@ export default function Swap({
setMaximumOcean
}: {
ddo: DDO
maxDt: number
maxOcean: number
maxDt: string
maxOcean: string
balance: PoolBalance
price: BestPrice
setMaximumDt: (value: number) => void
setMaximumOcean: (value: number) => void
setMaximumDt: (value: string) => void
setMaximumOcean: (value: string) => void
}): ReactElement {
const { ocean } = useOcean()
const [oceanItem, setOceanItem] = useState<TradeItem>({
amount: 0,
amount: '0',
token: 'OCEAN',
maxAmount: 0
maxAmount: '0'
})
const [dtItem, setDtItem] = useState<TradeItem>({
amount: 0,
amount: '0',
token: ddo.dataTokenInfo.symbol,
maxAmount: 0
maxAmount: '0'
})
const {
@ -72,32 +76,32 @@ export default function Swap({
const maximumDt =
values.type === 'buy'
? Number(dtAmount) > Number(maxBuyDt)
? Number(maxBuyDt)
: Number(dtAmount)
: Number(dtAmount) > balance.datatoken
? balance.datatoken
: Number(dtAmount)
? new Decimal(maxBuyDt)
: new Decimal(dtAmount)
: Number(dtAmount) > Number(balance.datatoken)
? new Decimal(balance.datatoken)
: new Decimal(dtAmount)
const maximumOcean =
values.type === 'sell'
? Number(oceanAmount) > Number(maxBuyOcean)
? Number(maxBuyOcean)
: Number(oceanAmount)
: Number(oceanAmount) > balance.ocean
? balance.ocean
: Number(oceanAmount)
? new Decimal(maxBuyOcean)
: new Decimal(oceanAmount)
: Number(oceanAmount) > Number(balance.ocean)
? new Decimal(balance.ocean)
: new Decimal(oceanAmount)
setMaximumDt(maximumDt)
setMaximumOcean(maximumOcean)
setMaximumDt(maximumDt.toString())
setMaximumOcean(maximumOcean.toString())
setOceanItem({
...oceanItem,
amount: oceanAmount,
maxAmount: maximumOcean
amount: oceanAmount.toString(),
maxAmount: maximumOcean.toString()
})
setDtItem({
...dtItem,
amount: dtAmount,
maxAmount: maximumDt
amount: dtAmount.toString(),
maxAmount: maximumDt.toString()
})
}
calculateMaximum()

View File

@ -73,7 +73,7 @@ export default function TradeInput({
size="small"
onClick={() => {
setFieldValue(name, item?.maxAmount)
handleValueChange(name, item?.maxAmount)
handleValueChange(name, Number(item?.maxAmount))
}}
>
Use Max

View File

@ -5,13 +5,18 @@ import { useAsset } from '../../../../providers/Asset'
import { useOcean } from '../../../../providers/Ocean'
import { useWeb3 } from '../../../../providers/Web3'
import { isValidNumber } from './../../../../utils/numberValidations'
import Decimal from 'decimal.js'
Decimal.set({ toExpNeg: -18, precision: 18, rounding: 1 })
export default function Trade(): ReactElement {
const { accountId, balance } = useWeb3()
const { ocean } = useOcean()
const [tokenBalance, setTokenBalance] = useState<PoolBalance>()
const { price, ddo } = useAsset()
const [maxDt, setMaxDt] = useState(0)
const [maxOcean, setMaxOcean] = useState(0)
const [maxDt, setMaxDt] = useState('0')
const [maxOcean, setMaxOcean] = useState('0')
// Get datatoken balance, and combine with OCEAN balance from hooks into one object
useEffect(() => {
@ -20,8 +25,8 @@ export default function Trade(): ReactElement {
async function getTokenBalance() {
const dtBalance = await ocean.datatokens.balance(ddo.dataToken, accountId)
setTokenBalance({
ocean: Number(balance.ocean),
datatoken: Number(dtBalance)
ocean: new Decimal(balance.ocean).toString(),
datatoken: new Decimal(dtBalance).toString()
})
}
getTokenBalance()
@ -35,12 +40,20 @@ export default function Trade(): ReactElement {
const maxTokensInPool = await ocean.pool.getDTMaxBuyQuantity(
price.address
)
setMaxDt(Number(maxTokensInPool))
setMaxDt(
isValidNumber(maxTokensInPool)
? new Decimal(maxTokensInPool).toString()
: '0'
)
const maxOceanInPool = await ocean.pool.getOceanMaxBuyQuantity(
price.address
)
setMaxOcean(Number(maxOceanInPool))
setMaxOcean(
isValidNumber(maxOceanInPool)
? new Decimal(maxOceanInPool).toString()
: '0'
)
}
getMaximum()
}, [ocean, balance.ocean, price])

View File

@ -12,6 +12,11 @@ import { DDO } from '@oceanprotocol/lib'
import FormHelp from '../../../../atoms/Input/Help'
import { useSiteMetadata } from '../../../../../hooks/useSiteMetadata'
import { isValidNumber } from './../../../../../utils/numberValidations'
import Decimal from 'decimal.js'
Decimal.set({ toExpNeg: -18, precision: 18, rounding: 1 })
export default function FormPricing({
ddo,
setShowPricing,
@ -41,8 +46,15 @@ export default function FormPricing({
useEffect(() => {
if (type === 'fixed') return
const dtAmount =
(Number(oceanAmount) / Number(weightOnOcean) / price) *
Number(weightOnDataToken)
isValidNumber(oceanAmount) &&
isValidNumber(weightOnOcean) &&
isValidNumber(price) &&
isValidNumber(weightOnDataToken)
? new Decimal(oceanAmount)
.dividedBy(new Decimal(weightOnOcean))
.dividedBy(new Decimal(price))
.mul(new Decimal(weightOnDataToken))
: 0
setFieldValue('dtAmount', dtAmount)
}, [price, oceanAmount, weightOnOcean, weightOnDataToken, type])

View File

@ -17,6 +17,10 @@ import { fetchDataForMultipleChains } from '../../../utils/subgraph'
import NetworkName from '../../atoms/NetworkName'
import axios from 'axios'
import { retrieveDDO } from '../../../utils/aquarius'
import { isValidNumber } from './../../../utils/numberValidations'
import Decimal from 'decimal.js'
Decimal.set({ toExpNeg: -18, precision: 18, rounding: 1 })
const REFETCH_INTERVAL = 20000
@ -90,11 +94,16 @@ function Liquidity({ row, type }: { row: Asset; type: string }) {
).toString()
}
if (type === 'pool') {
price = `${
Number(row.poolShare.poolId.oceanReserve) +
Number(row.poolShare.poolId.datatokenReserve) *
row.poolShare.poolId.consumePrice
}`
price =
isValidNumber(row.poolShare.poolId.oceanReserve) &&
isValidNumber(row.poolShare.poolId.datatokenReserve) &&
isValidNumber(row.poolShare.poolId.consumePrice)
? new Decimal(row.poolShare.poolId.datatokenReserve)
.mul(new Decimal(row.poolShare.poolId.consumePrice))
.plus(row.poolShare.poolId.oceanReserve)
.toString()
: '0'
oceanTokenBalance = row.poolShare.poolId.oceanReserve.toString()
dataTokenBalance = row.poolShare.poolId.datatokenReserve.toString()
}

View File

@ -7,9 +7,9 @@ export interface FormTradeData extends PoolBalance {
}
export interface TradeItem {
amount: number
amount: string
token: string
maxAmount: number
maxAmount: string
}
export const initialValues: FormTradeData = {

View File

@ -0,0 +1,8 @@
export function isValidNumber(value: any): boolean {
const isUndefinedValue = typeof value === 'undefined'
const isNullValue = value === null
const isNaNValue = isNaN(Number(value))
const isEmptyString = value === ''
return !isUndefinedValue && !isNullValue && !isNaNValue && !isEmptyString
}