1
0
mirror of https://github.com/oceanprotocol/market.git synced 2024-06-28 16:47:52 +02:00

Merge pull request #1017 from oceanprotocol/v4-liquidity

Restore add/remove liquidity
This commit is contained in:
Matthias Kretschmann 2022-01-28 11:54:41 +00:00 committed by GitHub
commit 2f6323f141
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 251 additions and 392 deletions

View File

@ -4,12 +4,12 @@ export default function DebugOutput({
title,
output
}: {
title: string
title?: string
output: any
}): ReactElement {
return (
<div style={{ marginTop: 'var(--spacer)' }}>
<h5>{title}</h5>
{title && <h5>{title}</h5>}
<pre style={{ wordWrap: 'break-word' }}>
<code>{JSON.stringify(output, null, 2)}</code>
</pre>

View File

@ -7,19 +7,19 @@ import content from '../../../../content/price.json'
export function ButtonApprove({
amount,
coin,
tokenSymbol,
approveTokens,
isLoading
}: {
amount: string
coin: string
tokenSymbol: string
approveTokens: (amount: string) => void
isLoading: boolean
}): ReactElement {
const { infiniteApproval } = useUserPreferences()
return isLoading ? (
<Loader message={`Approving ${coin}...`} />
<Loader message={`Approving ${tokenSymbol}...`} />
) : infiniteApproval ? (
<Button
style="primary"
@ -27,16 +27,22 @@ export function ButtonApprove({
disabled={parseInt(amount) < 1}
onClick={() => approveTokens(`${2 ** 53 - 1}`)}
>
Approve {coin}{' '}
Approve {tokenSymbol}{' '}
<Tooltip
content={content.pool.tooltips.approveInfinite.replace('COIN', coin)}
content={content.pool.tooltips.approveInfinite.replace(
'COIN',
tokenSymbol
)}
/>
</Button>
) : (
<Button style="primary" size="small" onClick={() => approveTokens(amount)}>
Approve {amount} {coin}
Approve {amount} {tokenSymbol}
<Tooltip
content={content.pool.tooltips.approveSpecific.replace('COIN', coin)}
content={content.pool.tooltips.approveSpecific.replace(
'COIN',
tokenSymbol
)}
/>
</Button>
)

View File

@ -2,46 +2,47 @@ import React, { ReactElement, useCallback, useEffect, useState } from 'react'
import { useAsset } from '@context/Asset'
import { useWeb3 } from '@context/Web3'
import Decimal from 'decimal.js'
import { getOceanConfig } from '@utils/ocean'
import { ButtonApprove } from './ButtonApprove'
import { allowance, approve, LoggerInstance } from '@oceanprotocol/lib'
export default function TokenApproval({
actionButton,
disabled,
amount,
coin
tokenAddress,
tokenSymbol
}: {
actionButton: JSX.Element
disabled: boolean
amount: string
coin: string
tokenAddress: string
tokenSymbol: string
}): ReactElement {
const { ddo, price, isAssetNetwork } = useAsset()
const { price, isAssetNetwork } = useAsset()
const [tokenApproved, setTokenApproved] = useState(false)
const [loading, setLoading] = useState(false)
const { accountId } = useWeb3()
const { web3, accountId } = useWeb3()
const config = getOceanConfig(ddo.chainId)
const tokenAddress =
coin === 'OCEAN'
? config.oceanTokenAddress
: ddo.services[0].datatokenAddress
const spender = price.address
const spender = price?.address
const checkTokenApproval = useCallback(async () => {
// if (!tokenAddress || !spender || !isAssetNetwork || !amount) return
// const allowance = await ocean.datatokens.allowance(
// tokenAddress,
// accountId,
// spender
// )
// amount &&
// new Decimal(amount).greaterThan(new Decimal('0')) &&
// setTokenApproved(
// new Decimal(allowance).greaterThanOrEqualTo(new Decimal(amount))
// )
}, [tokenAddress, spender, accountId, amount, isAssetNetwork])
if (!web3 || !tokenAddress || !spender || !isAssetNetwork || !amount) return
const allowanceValue = await allowance(
web3,
tokenAddress,
accountId,
spender
)
LoggerInstance.log(`[token approval] allowanceValue: ${allowanceValue}`)
if (!allowanceValue) return
new Decimal(amount).greaterThan(new Decimal('0')) &&
setTokenApproved(
new Decimal(allowanceValue).greaterThanOrEqualTo(new Decimal(amount))
)
}, [web3, tokenAddress, spender, accountId, amount, isAssetNetwork])
useEffect(() => {
checkTokenApproval()
@ -51,13 +52,17 @@ export default function TokenApproval({
setLoading(true)
try {
// await ocean.datatokens.approve(tokenAddress, spender, amount, accountId)
const tx = await approve(web3, accountId, tokenAddress, spender, amount)
LoggerInstance.log(`[token approval] Approve tokens tx:`, tx)
} catch (error) {
LoggerInstance.error(
`[token approval] Approve tokens tx failed:`,
error.message
)
} finally {
await checkTokenApproval()
setLoading(false)
}
await checkTokenApproval()
setLoading(false)
}
return (
@ -72,7 +77,7 @@ export default function TokenApproval({
) : (
<ButtonApprove
amount={amount}
coin={coin}
tokenSymbol={tokenSymbol}
approveTokens={approveTokens}
isLoading={loading}
/>

View File

@ -14,9 +14,10 @@ export default function Actions({
txId,
actionName,
amount,
coin,
action,
isDisabled
isDisabled,
tokenAddress,
tokenSymbol
}: {
isLoading: boolean
loaderMessage: string
@ -24,9 +25,10 @@ export default function Actions({
txId: string
actionName: string
amount?: string
coin?: string
action: () => void
isDisabled?: boolean
tokenAddress: string
tokenSymbol: string
}): ReactElement {
const { networkId } = useWeb3()
@ -50,7 +52,8 @@ export default function Actions({
<TokenApproval
actionButton={actionButton}
amount={amount}
coin={coin}
tokenAddress={tokenAddress}
tokenSymbol={tokenSymbol}
disabled={isDisabled}
/>
) : (

View File

@ -1,4 +1,4 @@
import React, { ChangeEvent, ReactElement, useEffect } from 'react'
import React, { ReactElement, useEffect } from 'react'
import styles from './FormAdd.module.css'
import Input from '@shared/FormInput'
import {
@ -8,34 +8,27 @@ import {
useFormikContext
} from 'formik'
import Button from '@shared/atoms/Button'
import CoinSelect from '../CoinSelect'
import { FormAddLiquidity } from '.'
import UserLiquidity from '../../UserLiquidity'
import { useWeb3 } from '@context/Web3'
import { isValidNumber } from '@utils/numbers'
import Decimal from 'decimal.js'
import { useAsset } from '@context/Asset'
import { LoggerInstance, Pool } from '@oceanprotocol/lib'
export default function FormAdd({
coin,
dtBalance,
dtSymbol,
tokenInAddress,
tokenInSymbol,
amountMax,
setCoin,
setAmount,
totalPoolTokens,
totalBalance,
poolAddress,
setNewPoolTokens,
setNewPoolShare
}: {
coin: string
dtBalance: string
dtSymbol: string
tokenInAddress: string
tokenInSymbol: string
amountMax: string
setCoin: (value: string) => void
setAmount: (value: string) => void
totalPoolTokens: string
totalBalance: PoolBalance
poolAddress: string
@ -46,75 +39,58 @@ export default function FormAdd({
const { isAssetNetwork } = useAsset()
// Connect with form
const {
touched,
setTouched,
setFieldValue,
validateField,
values
}: FormikContextType<FormAddLiquidity> = useFormikContext()
function handleFieldChange(e: ChangeEvent<HTMLInputElement>) {
// Workaround so validation kicks in on first touch
!touched?.amount && setTouched({ amount: true })
setAmount(e.target.value)
// Manually handle change events instead of using `handleChange` from Formik.
// Solves bug where 0.0 can't be typed.
validateField('amount')
setFieldValue('amount', e.target.value)
}
const { setFieldValue, values }: FormikContextType<FormAddLiquidity> =
useFormikContext()
useEffect(() => {
async function calculatePoolShares() {
// if (!web3) return
// const tokenInAddress =
// coin === 'OCEAN' ? ocean.pool.oceanAddress : ocean.pool.dtAddress
// if (!values.amount || !tokenInAddress) {
// setNewPoolTokens('0')
// setNewPoolShare('0')
// return
// }
// if (Number(values.amount) > Number(amountMax)) return
// const poolTokens = await ocean.pool.calcPoolOutGivenSingleIn(
// poolAddress,
// tokenInAddress,
// `${values.amount}`
// )
// setNewPoolTokens(poolTokens)
// const newPoolShareDecimal =
// isValidNumber(poolTokens) && isValidNumber(totalPoolTokens)
// ? new Decimal(poolTokens)
// .dividedBy(
// new Decimal(totalPoolTokens).plus(new Decimal(poolTokens))
// )
// .mul(100)
// .toString()
// : '0'
// totalBalance && setNewPoolShare(newPoolShareDecimal)
if (!web3) return
if (!values.amount || !tokenInAddress) {
setNewPoolTokens('0')
setNewPoolShare('0')
return
}
if (Number(values.amount) > Number(amountMax)) return
const poolInstance = new Pool(web3, LoggerInstance)
const poolTokens = await poolInstance.calcPoolOutGivenSingleIn(
poolAddress,
tokenInAddress,
values.amount
)
setNewPoolTokens(poolTokens)
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()
}, [
tokenInAddress,
web3,
values.amount,
totalBalance,
totalPoolTokens,
amountMax,
coin,
poolAddress,
setNewPoolTokens,
setNewPoolShare
])
useEffect(() => {
setFieldValue('amount', undefined)
}, [coin])
return (
<>
<UserLiquidity
amount={coin === 'OCEAN' ? balance.ocean : dtBalance}
amount={balance.ocean}
amountMax={amountMax}
symbol={coin}
symbol={tokenInSymbol}
/>
<Field name="amount">
@ -130,34 +106,24 @@ export default function FormAdd({
name="amount"
max={amountMax}
min="0"
value={`${values.amount}`}
value={values.amount}
step="any"
prefix={
<CoinSelect
dtSymbol={dtSymbol}
setCoin={setCoin}
disabled={!web3 || !isAssetNetwork}
/>
}
prefix={tokenInSymbol}
placeholder="0"
field={field}
form={form}
onChange={handleFieldChange}
disabled={!isAssetNetwork}
/>
)}
</Field>
{(Number(balance.ocean) || dtBalance) > (values.amount || 0) && (
{Number(balance.ocean) && (
<Button
className={styles.buttonMax}
style="text"
size="small"
disabled={!web3}
onClick={() => {
setAmount(amountMax)
setFieldValue('amount', amountMax)
}}
onClick={() => setFieldValue('amount', amountMax)}
>
Use Max
</Button>

View File

@ -11,18 +11,16 @@ export default function Output({
newPoolTokens,
newPoolShare,
swapFee,
dtSymbol,
datatokenSymbol,
totalPoolTokens,
totalBalance,
coin
totalBalance
}: {
newPoolTokens: string
newPoolShare: string
swapFee: string
dtSymbol: string
datatokenSymbol: string
totalPoolTokens: string
totalBalance: PoolBalance
coin: string
}): ReactElement {
const { help, titleIn, titleOut } = content.pool.add.output
@ -37,21 +35,14 @@ export default function Output({
return
const newPoolSupply = new Decimal(totalPoolTokens).plus(newPoolTokens)
const ratio = new Decimal(newPoolTokens).div(newPoolSupply)
const newOceanReserve =
coin === 'OCEAN'
? new Decimal(totalBalance.ocean).plus(values.amount)
: new Decimal(totalBalance.ocean)
const newDtReserve =
coin === 'OCEAN'
? new Decimal(totalBalance.datatoken)
: new Decimal(totalBalance.datatoken).plus(values.amount)
const newOceanReserve = new Decimal(totalBalance.ocean).plus(values.amount)
const newDtReserve = new Decimal(totalBalance.datatoken)
const poolOcean = newOceanReserve.mul(ratio).toString()
const poolDatatoken = newDtReserve.mul(ratio).toString()
setPoolOcean(poolOcean)
setPoolDatatoken(poolDatatoken)
}, [
values.amount,
coin,
totalBalance,
totalPoolTokens,
newPoolShare,
@ -72,7 +63,7 @@ export default function Output({
<div>
<p>{titleOut}</p>
<Token symbol="OCEAN" balance={poolOcean} />
<Token symbol={dtSymbol} balance={poolDatatoken} />
<Token symbol={datatokenSymbol} balance={poolDatatoken} />
</div>
</div>
</>

View File

@ -13,14 +13,14 @@ import DebugOutput from '@shared/DebugOutput'
import { useWeb3 } from '@context/Web3'
import { useAsset } from '@context/Asset'
import content from '../../../../../../content/price.json'
import { Datatoken } from '@oceanprotocol/lib'
import { LoggerInstance, Pool } from '@oceanprotocol/lib'
export interface FormAddLiquidity {
amount: number
amount: string
}
const initialValues: FormAddLiquidity = {
amount: undefined
amount: ''
}
export default function Add({
@ -29,8 +29,9 @@ export default function Add({
totalPoolTokens,
totalBalance,
swapFee,
dtSymbol,
dtAddress,
datatokenSymbol,
tokenInSymbol,
tokenInAddress,
fetchAllData
}: {
setShowAdd: (show: boolean) => void
@ -38,18 +39,16 @@ export default function Add({
totalPoolTokens: string
totalBalance: PoolBalance
swapFee: string
dtSymbol: string
dtAddress: string
datatokenSymbol: string
tokenInSymbol: string
tokenInAddress: string
fetchAllData: () => void
}): ReactElement {
const { accountId, balance, web3 } = useWeb3()
const { isAssetNetwork } = useAsset()
const { debug } = useUserPreferences()
const [txId, setTxId] = useState<string>()
const [coin, setCoin] = useState('OCEAN')
const [dtBalance, setDtBalance] = useState<string>()
const [amountMax, setAmountMax] = useState<string>()
const [amount, setAmount] = useState<string>('0')
const [newPoolTokens, setNewPoolTokens] = useState('0')
const [newPoolShare, setNewPoolShare] = useState('0')
const [isWarningAccepted, setIsWarningAccepted] = useState(false)
@ -57,65 +56,65 @@ export default function Add({
// Live validation rules
// https://github.com/jquense/yup#number
const validationSchema: Yup.SchemaOf<FormAddLiquidity> = Yup.object().shape({
amount: Yup.number()
amount: Yup.string()
.min(0.00001, (param) => `Must be more or equal to ${param.min}`)
.max(
Number(amountMax),
`Maximum you can add is ${Number(amountMax).toFixed(2)} ${coin}`
`Maximum you can add is ${Number(amountMax).toFixed(2)} OCEAN`
)
.required('Required')
})
// Get datatoken balance when datatoken selected
// Get maximum amount for OCEAN
useEffect(() => {
if (!web3 || !accountId || !isAssetNetwork || coin === 'OCEAN') return
async function getDtBalance() {
const datatokenInstance = new Datatoken(web3)
const dtBalance = await datatokenInstance.balance(dtAddress, accountId)
setDtBalance(dtBalance)
}
getDtBalance()
}, [web3, accountId, dtAddress, coin, isAssetNetwork])
// Get maximum amount for either OCEAN or datatoken
useEffect(() => {
if (!accountId || !isAssetNetwork || !poolAddress) return
if (!web3 || !accountId || !isAssetNetwork || !poolAddress) return
async function getMaximum() {
// const amountMaxPool =
// coin === 'OCEAN'
// ? await ocean.pool.getOceanMaxAddLiquidity(poolAddress)
// : await ocean.pool.getDTMaxAddLiquidity(poolAddress)
// const amountMax =
// coin === 'OCEAN'
// ? Number(balance.ocean) > Number(amountMaxPool)
// ? amountMaxPool
// : balance.ocean
// : Number(dtBalance) > Number(amountMaxPool)
// ? amountMaxPool
// : dtBalance
// setAmountMax(Number(amountMax).toFixed(3))
try {
const poolInstance = new Pool(web3, LoggerInstance)
const amountMaxPool = await poolInstance.getReserve(
poolAddress,
tokenInAddress
)
const amountMax =
Number(balance.ocean) > Number(amountMaxPool)
? amountMaxPool
: balance.ocean
setAmountMax(Number(amountMax).toFixed(3))
} catch (error) {
LoggerInstance.error(error.message)
}
}
getMaximum()
}, [accountId, isAssetNetwork, poolAddress, coin, dtBalance, balance.ocean])
}, [
web3,
accountId,
isAssetNetwork,
poolAddress,
tokenInAddress,
balance?.ocean
])
// Submit
async function handleAddLiquidity(amount: number, resetForm: () => void) {
async function handleAddLiquidity(amount: string, resetForm: () => void) {
const poolInstance = new Pool(web3, LoggerInstance)
const minPoolAmountOut = '0' // ? TODO: how to get?
try {
// const result =
// coin === 'OCEAN'
// ? await ocean.pool.addOceanLiquidity(
// accountId,
// poolAddress,
// `${amount}`
// )
// : await ocean.pool.addDTLiquidity(accountId, poolAddress, `${amount}`)
// setTxId(result?.transactionHash)
// resetForm()
const result = await poolInstance.joinswapExternAmountIn(
accountId,
poolAddress,
tokenInAddress,
amount,
minPoolAmountOut
)
setTxId(result?.transactionHash)
fetchAllData()
resetForm()
} catch (error) {
console.error(error.message)
LoggerInstance.error(error.message)
toast.error(error.message)
}
}
@ -139,12 +138,9 @@ export default function Add({
<div className={styles.addInput}>
{isWarningAccepted ? (
<FormAdd
coin={coin}
dtBalance={dtBalance}
dtSymbol={dtSymbol}
tokenInAddress={tokenInAddress}
tokenInSymbol={tokenInSymbol}
amountMax={amountMax}
setCoin={setCoin}
setAmount={setAmount}
totalPoolTokens={totalPoolTokens}
totalBalance={totalBalance}
poolAddress={poolAddress}
@ -171,29 +167,30 @@ export default function Add({
newPoolTokens={newPoolTokens}
newPoolShare={newPoolShare}
swapFee={swapFee}
dtSymbol={dtSymbol}
datatokenSymbol={datatokenSymbol}
totalPoolTokens={totalPoolTokens}
totalBalance={totalBalance}
coin={coin}
/>
<Actions
isDisabled={
!isValid ||
!isWarningAccepted ||
amount === '' ||
amount === '0'
!values.amount ||
values.amount === '' ||
values.amount === '0'
}
isLoading={isSubmitting}
loaderMessage="Adding Liquidity..."
successMessage="Successfully added liquidity."
actionName={content.pool.add.action}
action={submitForm}
amount={amount}
coin={coin}
amount={values.amount}
tokenAddress={tokenInAddress}
tokenSymbol={tokenInSymbol}
txId={txId}
/>
{debug && <DebugOutput title="Collected values" output={values} />}
{debug && <DebugOutput output={values} />}
</>
)}
</Formik>

View File

@ -1,26 +0,0 @@
.coinSelect {
composes: select from '@shared/FormInput/InputElement.module.css';
font-size: var(--font-size-small);
font-weight: var(--font-weight-base);
border: none;
margin-left: -0.5rem;
margin-right: -0.5rem;
background-color: var(--background-highlight);
width: auto;
padding: 0 1.25rem 0 0.25rem;
height: 41px;
text-align: center;
/* custom arrow, without the divider line */
background-image: linear-gradient(
45deg,
transparent 50%,
var(--font-color-text) 50%
),
linear-gradient(135deg, var(--font-color-text) 50%, transparent 50%);
background-position: calc(100% - 14px) 1.2rem, calc(100% - 9px) 1.2rem, 100% 0;
}
.option {
color: var(--font-color-heading);
}

View File

@ -1,27 +0,0 @@
import React, { ReactElement } from 'react'
import styles from './CoinSelect.module.css'
export default function CoinSelect({
dtSymbol,
disabled,
setCoin
}: {
dtSymbol: string
disabled: boolean
setCoin: (coin: string) => void
}): ReactElement {
return (
<select
className={styles.coinSelect}
onChange={(e) => setCoin(e.target.value)}
disabled={disabled}
>
<option className={styles.option} value="OCEAN">
OCEAN
</option>
<option className={styles.option} value={dtSymbol}>
{dtSymbol}
</option>
</select>
)
}

View File

@ -3,14 +3,13 @@ import React, {
useState,
ChangeEvent,
useEffect,
FormEvent,
useRef
} from 'react'
import styles from './Remove.module.css'
import Header from './Header'
import { toast } from 'react-toastify'
import Actions from './Actions'
import { LoggerInstance } from '@oceanprotocol/lib'
import { LoggerInstance, Pool } from '@oceanprotocol/lib'
import Token from './Token'
import FormHelp from '@shared/FormInput/Help'
import Button from '@shared/atoms/Button'
@ -23,57 +22,53 @@ import Decimal from 'decimal.js'
import { useAsset } from '@context/Asset'
import content from '../../../../../content/price.json'
const slippagePresets = ['5', '10', '15', '25', '50']
export default function Remove({
setShowRemove,
poolAddress,
poolTokens,
totalPoolTokens,
dtSymbol,
tokenOutAddress,
tokenOutSymbol,
fetchAllData
}: {
setShowRemove: (show: boolean) => void
poolAddress: string
poolTokens: string
totalPoolTokens: string
dtSymbol: string
tokenOutAddress: string
tokenOutSymbol: string
fetchAllData: () => void
}): ReactElement {
const slippagePresets = ['5', '10', '15', '25', '50']
const { accountId } = useWeb3()
const { accountId, web3 } = useWeb3()
const { isAssetNetwork } = useAsset()
const [amountPercent, setAmountPercent] = useState('0')
const [amountMaxPercent, setAmountMaxPercent] = useState('100')
const [amountPoolShares, setAmountPoolShares] = useState('0')
const [amountOcean, setAmountOcean] = useState('0')
const [amountDatatoken, setAmountDatatoken] = useState('0')
const [isAdvanced, setIsAdvanced] = useState(false)
const [isLoading, setIsLoading] = useState<boolean>()
const [txId, setTxId] = useState<string>()
const [slippage, setSlippage] = useState<string>('5')
const [minOceanAmount, setMinOceanAmount] = useState<string>('0')
const [minDatatokenAmount, setMinDatatokenAmount] = useState<string>('0')
// TODO: precision needs to be set based on baseToken decimals
Decimal.set({ toExpNeg: -18, precision: 18, rounding: 1 })
const poolInstance = new Pool(web3, LoggerInstance)
async function handleRemoveLiquidity() {
setIsLoading(true)
try {
// const result =
// isAdvanced === true
// ? await ocean.pool.removePoolLiquidity(
// accountId,
// poolAddress,
// amountPoolShares,
// minDatatokenAmount,
// minOceanAmount
// )
// : await ocean.pool.removeOceanLiquidityWithMinimum(
// accountId,
// poolAddress,
// amountPoolShares,
// minOceanAmount
// )
// setTxId(result?.transactionHash)
const result = await poolInstance.exitswapPoolAmountIn(
accountId,
poolAddress,
tokenOutAddress,
amountPoolShares,
minOceanAmount
)
setTxId(result?.transactionHash)
fetchAllData()
} catch (error) {
LoggerInstance.error(error.message)
@ -83,50 +78,33 @@ export default function Remove({
}
}
// Get and set max percentage
// TODO: Get and set max percentage
useEffect(() => {
if (!accountId || !poolTokens) return
async function getMax() {
// const amountMaxPercent =
// isAdvanced === true
// ? '100'
// : await getMaxPercentRemove(poolAddress, poolTokens)
// const amountMaxPercent = await getMaxPercentRemove(poolAddress, poolTokens)
// setAmountMaxPercent(amountMaxPercent)
}
getMax()
}, [accountId, isAdvanced, poolAddress, poolTokens])
}, [accountId, poolAddress, poolTokens])
const getValues = useRef(
debounce(async (newAmountPoolShares, isAdvanced) => {
// if (isAdvanced === true) {
// const tokens = await ocean.pool.getTokensRemovedforPoolShares(
// poolAddress,
// `${newAmountPoolShares}`
// )
// setAmountOcean(tokens?.oceanAmount)
// setAmountDatatoken(tokens?.dtAmount)
// return
// }
// const amountOcean = await ocean.pool.getOceanRemovedforPoolShares(
// poolAddress,
// newAmountPoolShares
// )
// setAmountOcean(amountOcean)
debounce(async (newAmountPoolShares) => {
const newAmountOcean = await poolInstance.calcSingleOutGivenPoolIn(
poolAddress,
tokenOutAddress,
newAmountPoolShares
)
setAmountOcean(newAmountOcean)
}, 150)
)
// Check and set outputs when amountPoolShares changes
useEffect(() => {
if (!accountId || !poolTokens) return
getValues.current(amountPoolShares, isAdvanced)
}, [
amountPoolShares,
isAdvanced,
accountId,
poolTokens,
poolAddress,
totalPoolTokens
])
getValues.current(amountPoolShares)
}, [amountPoolShares, accountId, poolTokens, poolAddress, totalPoolTokens])
useEffect(() => {
const minOceanAmount = new Decimal(amountOcean)
@ -134,14 +112,8 @@ export default function Remove({
.dividedBy(100)
.toString()
const minDatatokenAmount = new Decimal(amountDatatoken)
.mul(new Decimal(100).minus(new Decimal(slippage)))
.dividedBy(100)
.toString()
setMinOceanAmount(minOceanAmount.slice(0, 18))
setMinDatatokenAmount(minDatatokenAmount.slice(0, 18))
}, [slippage, amountOcean, amountDatatoken, isAdvanced])
}, [slippage, amountOcean])
// Set amountPoolShares based on set slider value
function handleAmountPercentChange(e: ChangeEvent<HTMLInputElement>) {
@ -168,22 +140,6 @@ export default function Remove({
setAmountPoolShares(`${amountPoolShares.slice(0, 18)}`)
}
function handleAdvancedButton(e: FormEvent<HTMLButtonElement>) {
e.preventDefault()
setIsAdvanced(!isAdvanced)
setAmountPoolShares('0')
setAmountPercent('0')
setAmountOcean('0')
setSlippage('5')
setMinOceanAmount('0')
setMinDatatokenAmount('0')
if (isAdvanced === true) {
setAmountDatatoken('0')
}
}
function handleSlippageChange(e: ChangeEvent<HTMLSelectElement>) {
setSlippage(e.target.value)
}
@ -219,20 +175,7 @@ export default function Remove({
</Button>
</div>
<FormHelp>
{isAdvanced === true
? content.pool.remove.advanced
: content.pool.remove.simple}
</FormHelp>
<Button
style="text"
size="small"
onClick={handleAdvancedButton}
disabled={!isAssetNetwork}
className={styles.toggle}
>
{isAdvanced === true ? 'Simple' : 'Advanced'}
</Button>
<FormHelp>{content.pool.remove.simple}</FormHelp>
</div>
</form>
<div className={styles.output}>
@ -242,14 +185,7 @@ export default function Remove({
</div>
<div>
<p>{content.pool.remove.output.titleOut} minimum</p>
{isAdvanced === true ? (
<>
<Token symbol="OCEAN" balance={minOceanAmount} />
<Token symbol={dtSymbol} balance={minDatatokenAmount} />
</>
) : (
<Token symbol="OCEAN" balance={minOceanAmount} />
)}
<Token symbol={tokenOutSymbol} balance={minOceanAmount} />
</div>
</div>
<div className={styles.slippage}>
@ -274,6 +210,8 @@ export default function Remove({
successMessage="Successfully removed liquidity."
isDisabled={!isAssetNetwork}
txId={txId}
tokenAddress={tokenOutAddress}
tokenSymbol={tokenOutSymbol}
/>
</div>
)

View File

@ -7,10 +7,10 @@ import Decimal from 'decimal.js'
export default function TokenList({
title,
children,
ocean,
oceanSymbol,
dt,
dtSymbol,
baseTokenValue,
baseTokenSymbol,
datatokenValue,
datatokenSymbol,
poolShares,
conversion,
highlight,
@ -18,10 +18,10 @@ export default function TokenList({
}: {
title: string | ReactNode
children: ReactNode
ocean: string
oceanSymbol: string
dt: string
dtSymbol: string
baseTokenValue: string
baseTokenSymbol: string
datatokenValue: string
datatokenSymbol: string
poolShares: string
conversion: Decimal
highlight?: boolean
@ -32,8 +32,8 @@ export default function TokenList({
<h3 className={styles.title}>{title}</h3>
<div className={styles.tokens}>
<div>
<Token symbol={oceanSymbol} balance={ocean} />
<Token symbol={dtSymbol} balance={dt} />
<Token symbol={baseTokenSymbol} balance={baseTokenValue} />
<Token symbol={datatokenSymbol} balance={datatokenValue} />
{conversion.greaterThan(0) && (
<Conversion
price={conversion.toString()}
@ -45,7 +45,6 @@ export default function TokenList({
<div>
<Token symbol="pool shares" balance={poolShares} noIcon />
{children}
</div>
</div>

View File

@ -29,10 +29,11 @@ function getWeight(weight: string) {
interface PoolInfo {
poolFee: string
weightOcean: string
weightBaseToken: string
weightDt: string
dtSymbol: string
oceanSymbol: string
datatokenSymbol: string
baseTokenSymbol: string
baseTokenAddress: string
totalPoolTokens: string
totalLiquidityInOcean: Decimal
}
@ -158,10 +159,11 @@ export default function Pool(): ReactElement {
const newPoolInfo = {
poolFee,
weightOcean: getWeight(poolData.baseTokenWeight),
weightBaseToken: getWeight(poolData.baseTokenWeight),
weightDt: getWeight(poolData.datatokenWeight),
dtSymbol: poolData.datatoken.symbol,
oceanSymbol: poolData.baseToken.symbol,
datatokenSymbol: poolData.datatoken.symbol,
baseTokenSymbol: poolData.baseToken.symbol,
baseTokenAddress: poolData.baseToken.address,
totalPoolTokens: poolData.totalShares,
totalLiquidityInOcean
}
@ -327,7 +329,6 @@ export default function Pool(): ReactElement {
//
useEffect(() => {
if (!owner || !accountId) return
setIsRemoveDisabled(isInPurgatory && owner === accountId)
}, [isInPurgatory, owner, accountId])
@ -337,32 +338,34 @@ export default function Pool(): ReactElement {
<Add
setShowAdd={setShowAdd}
poolAddress={price?.address}
totalPoolTokens={poolInfo.totalPoolTokens}
totalPoolTokens={poolInfo?.totalPoolTokens}
totalBalance={{
ocean: new Decimal(price?.ocean).toString(),
datatoken: new Decimal(price?.datatoken).toString()
}}
swapFee={poolInfo.poolFee}
dtSymbol={poolInfo.dtSymbol}
dtAddress={ddo?.services[0].datatokenAddress}
swapFee={poolInfo?.poolFee}
datatokenSymbol={poolInfo?.datatokenSymbol}
tokenInAddress={poolInfo?.baseTokenAddress}
tokenInSymbol={poolInfo?.baseTokenSymbol}
fetchAllData={fetchAllData}
/>
) : showRemove ? (
<Remove
setShowRemove={setShowRemove}
poolAddress={price?.address}
poolTokens={poolInfoUser.poolShares}
poolTokens={poolInfoUser?.poolShares}
totalPoolTokens={poolInfo?.totalPoolTokens}
dtSymbol={poolInfo?.dtSymbol}
tokenOutAddress={poolInfo?.baseTokenAddress}
tokenOutSymbol={poolInfo?.baseTokenSymbol}
fetchAllData={fetchAllData}
/>
) : (
<>
<div className={styles.dataToken}>
<PriceUnit price="1" symbol={poolInfo?.dtSymbol} /> ={' '}
<PriceUnit price="1" symbol={poolInfo?.datatokenSymbol} /> ={' '}
<PriceUnit
price={`${price?.value}`}
symbol={poolInfo?.oceanSymbol}
symbol={poolInfo?.baseTokenSymbol}
/>
<Tooltip content={content.pool.tooltips.price} />
<div className={styles.dataTokenLinks}>
@ -397,10 +400,10 @@ export default function Pool(): ReactElement {
/>
</>
}
ocean={`${poolInfoUser?.liquidity?.ocean}`}
oceanSymbol={poolInfo?.oceanSymbol}
dt={`${poolInfoUser?.liquidity?.datatoken}`}
dtSymbol={poolInfo?.dtSymbol}
baseTokenValue={`${poolInfoUser?.liquidity?.ocean}`}
baseTokenSymbol={poolInfo?.baseTokenSymbol}
datatokenValue={`${poolInfoUser?.liquidity?.datatoken}`}
datatokenSymbol={poolInfo?.datatokenSymbol}
poolShares={poolInfoUser?.poolShares}
conversion={poolInfoUser?.totalLiquidityInOcean}
highlight
@ -414,10 +417,10 @@ export default function Pool(): ReactElement {
<TokenList
title="Pool Creator Statistics"
ocean={`${poolInfoOwner?.liquidity?.ocean}`}
oceanSymbol={poolInfo?.oceanSymbol}
dt={`${poolInfoOwner?.liquidity?.datatoken}`}
dtSymbol={poolInfo?.dtSymbol}
baseTokenValue={`${poolInfoOwner?.liquidity?.ocean}`}
baseTokenSymbol={poolInfo?.baseTokenSymbol}
datatokenValue={`${poolInfoOwner?.liquidity?.datatoken}`}
datatokenSymbol={poolInfo?.datatokenSymbol}
poolShares={poolInfoOwner?.poolShares}
conversion={poolInfoOwner?.totalLiquidityInOcean}
>
@ -435,18 +438,18 @@ export default function Pool(): ReactElement {
{poolInfo?.weightDt && (
<span
className={styles.titleInfo}
title={`Weight of ${poolInfo?.weightOcean}% OCEAN & ${poolInfo?.weightDt}% ${poolInfo?.dtSymbol}`}
title={`Weight of ${poolInfo?.weightBaseToken}% ${poolInfo?.baseTokenSymbol} & ${poolInfo?.weightDt}% ${poolInfo?.datatokenSymbol}`}
>
{poolInfo?.weightOcean}/{poolInfo?.weightDt}
{poolInfo?.weightBaseToken}/{poolInfo?.weightDt}
</span>
)}
<Graph />
</>
}
ocean={`${price?.ocean}`}
oceanSymbol={poolInfo?.oceanSymbol}
dt={`${price?.datatoken}`}
dtSymbol={poolInfo?.dtSymbol}
baseTokenValue={`${price?.ocean}`}
baseTokenSymbol={poolInfo?.baseTokenSymbol}
datatokenValue={`${price?.datatoken}`}
datatokenSymbol={poolInfo?.datatokenSymbol}
poolShares={poolInfo?.totalPoolTokens}
conversion={poolInfo?.totalLiquidityInOcean}
showTVLLabel

View File

@ -38,6 +38,9 @@ export default function FormTrade({
const [maximumDt, setMaximumDt] = useState(maxDt)
const [isWarningAccepted, setIsWarningAccepted] = useState(false)
const tokenAddress = ''
const tokenSymbol = ''
const validationSchema: Yup.SchemaOf<FormTradeData> = Yup.object()
.shape({
ocean: Yup.number()
@ -152,8 +155,9 @@ export default function FormTrade({
: undefined
}
action={submitForm}
coin={coinFrom}
txId={txId}
tokenAddress={tokenAddress}
tokenSymbol={tokenSymbol}
/>
{debug && (