mirror of
https://github.com/oceanprotocol/market.git
synced 2024-12-02 05:57:29 +01:00
put back Remove Liquidity components (#1551)
* put back Remove Liquidity components * remove Pool Share Lock action
This commit is contained in:
parent
e885a5c921
commit
65045ba7b9
@ -0,0 +1,25 @@
|
|||||||
|
.actions {
|
||||||
|
margin-left: -2rem;
|
||||||
|
margin-right: -2rem;
|
||||||
|
padding-left: var(--spacer);
|
||||||
|
padding-right: var(--spacer);
|
||||||
|
padding-top: calc(var(--spacer) / 1.5);
|
||||||
|
border-top: 1px solid var(--border-color);
|
||||||
|
text-align: center;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.success {
|
||||||
|
margin-top: calc(var(--spacer) / 2);
|
||||||
|
margin-bottom: calc(var(--spacer) / 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.actions button {
|
||||||
|
margin-left: calc(var(--spacer) / 4);
|
||||||
|
margin-right: calc(var(--spacer) / 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
.actions button svg {
|
||||||
|
fill: currentColor;
|
||||||
|
}
|
75
src/components/organisms/AssetActions/Pool/Actions.tsx
Normal file
75
src/components/organisms/AssetActions/Pool/Actions.tsx
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
import React, { ReactElement } from 'react'
|
||||||
|
import Loader from '../../../atoms/Loader'
|
||||||
|
import Button from '../../../atoms/Button'
|
||||||
|
import styles from './Actions.module.css'
|
||||||
|
import ExplorerLink from '../../../atoms/ExplorerLink'
|
||||||
|
import SuccessConfetti from '../../../atoms/SuccessConfetti'
|
||||||
|
import { useOcean } from '../../../../providers/Ocean'
|
||||||
|
import { useWeb3 } from '../../../../providers/Web3'
|
||||||
|
import TokenApproval from '../../../molecules/TokenApproval'
|
||||||
|
|
||||||
|
export default function Actions({
|
||||||
|
isLoading,
|
||||||
|
loaderMessage,
|
||||||
|
successMessage,
|
||||||
|
txId,
|
||||||
|
actionName,
|
||||||
|
amount,
|
||||||
|
coin,
|
||||||
|
action,
|
||||||
|
isDisabled
|
||||||
|
}: {
|
||||||
|
isLoading: boolean
|
||||||
|
loaderMessage: string
|
||||||
|
successMessage: string
|
||||||
|
txId: string
|
||||||
|
actionName: string
|
||||||
|
amount?: string
|
||||||
|
coin?: string
|
||||||
|
action: () => void
|
||||||
|
isDisabled?: boolean
|
||||||
|
}): ReactElement {
|
||||||
|
const { networkId } = useWeb3()
|
||||||
|
const { ocean } = useOcean()
|
||||||
|
|
||||||
|
const actionButton = (
|
||||||
|
<Button
|
||||||
|
style="primary"
|
||||||
|
size="small"
|
||||||
|
onClick={() => action()}
|
||||||
|
disabled={!ocean || isDisabled}
|
||||||
|
>
|
||||||
|
{actionName}
|
||||||
|
</Button>
|
||||||
|
)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className={styles.actions}>
|
||||||
|
{isLoading ? (
|
||||||
|
<Loader message={loaderMessage} />
|
||||||
|
) : actionName === 'Supply' || actionName === 'Swap' ? (
|
||||||
|
<TokenApproval
|
||||||
|
actionButton={actionButton}
|
||||||
|
amount={amount}
|
||||||
|
coin={coin}
|
||||||
|
disabled={!ocean || isDisabled}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
actionButton
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
{txId && (
|
||||||
|
<SuccessConfetti
|
||||||
|
className={styles.success}
|
||||||
|
success={successMessage}
|
||||||
|
action={
|
||||||
|
<ExplorerLink networkId={networkId} path={`/tx/${txId}`}>
|
||||||
|
View transaction
|
||||||
|
</ExplorerLink>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
.output {
|
||||||
|
display: grid;
|
||||||
|
gap: var(--spacer);
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
padding-bottom: calc(var(--spacer) / 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.output p {
|
||||||
|
font-weight: var(--font-weight-bold);
|
||||||
|
margin-bottom: calc(var(--spacer) / 8);
|
||||||
|
font-size: var(--font-size-small);
|
||||||
|
}
|
||||||
|
|
||||||
|
.output div:first-child [class*='token'] {
|
||||||
|
white-space: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.output div:first-child [class*='token'] > figure {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.help {
|
||||||
|
text-align: center;
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
.addInput {
|
||||||
|
margin: 0 auto calc(var(--spacer) / 1.5) auto;
|
||||||
|
background: var(--background-highlight);
|
||||||
|
padding: var(--spacer) calc(var(--spacer) * 2.5) calc(var(--spacer) * 1.2)
|
||||||
|
calc(var(--spacer) * 2.5);
|
||||||
|
border-bottom: 1px solid var(--border-color);
|
||||||
|
margin-top: -2rem;
|
||||||
|
margin-left: -2rem;
|
||||||
|
margin-right: -2rem;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.addInput input {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.addInput div[class*='field'] {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.warning {
|
||||||
|
margin-left: -3rem;
|
||||||
|
margin-right: -3rem;
|
||||||
|
}
|
70
src/components/organisms/AssetActions/Pool/Remove.module.css
Normal file
70
src/components/organisms/AssetActions/Pool/Remove.module.css
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
.removeInput {
|
||||||
|
composes: addInput from './Add/index.module.css';
|
||||||
|
padding-left: calc(var(--spacer) * 2);
|
||||||
|
padding-right: calc(var(--spacer) * 2);
|
||||||
|
padding-bottom: calc(var(--spacer) / 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.range {
|
||||||
|
margin-top: calc(var(--spacer) / 2);
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.range h3 {
|
||||||
|
margin-bottom: calc(var(--spacer) / 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
.range input {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.range p {
|
||||||
|
margin-bottom: 0;
|
||||||
|
margin-left: -2rem;
|
||||||
|
margin-right: -2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slider {
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.maximum {
|
||||||
|
position: absolute;
|
||||||
|
right: -2rem;
|
||||||
|
bottom: 2rem;
|
||||||
|
font-size: var(--font-size-mini);
|
||||||
|
min-width: 5rem;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle {
|
||||||
|
margin-top: calc(var(--spacer) / 2);
|
||||||
|
margin-bottom: 0;
|
||||||
|
font-size: var(--font-size-mini);
|
||||||
|
margin-bottom: -2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.output {
|
||||||
|
composes: output from './Add/Output.module.css';
|
||||||
|
}
|
||||||
|
|
||||||
|
.output [class*='token'] {
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.output [class*='token'] > figure {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.output figure[class*='pool shares'] {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.output p {
|
||||||
|
font-size: var(--font-size-small);
|
||||||
|
}
|
||||||
|
|
||||||
|
.slippage {
|
||||||
|
composes: slippage from '../Trade/Slippage.module.css';
|
||||||
|
}
|
313
src/components/organisms/AssetActions/Pool/Remove.tsx
Normal file
313
src/components/organisms/AssetActions/Pool/Remove.tsx
Normal file
@ -0,0 +1,313 @@
|
|||||||
|
import React, {
|
||||||
|
ReactElement,
|
||||||
|
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 { Logger } from '@oceanprotocol/lib'
|
||||||
|
import Token from './Token'
|
||||||
|
import FormHelp from '../../../atoms/Input/Help'
|
||||||
|
import Button from '../../../atoms/Button'
|
||||||
|
import { getMaxPercentRemove } from './utils'
|
||||||
|
import { graphql, useStaticQuery } from 'gatsby'
|
||||||
|
import debounce from 'lodash.debounce'
|
||||||
|
import UserLiquidity from '../../../atoms/UserLiquidity'
|
||||||
|
import InputElement from '../../../atoms/Input/InputElement'
|
||||||
|
import { useOcean } from '../../../../providers/Ocean'
|
||||||
|
import { useWeb3 } from '../../../../providers/Web3'
|
||||||
|
import Decimal from 'decimal.js'
|
||||||
|
import { useAsset } from '../../../../providers/Asset'
|
||||||
|
|
||||||
|
const contentQuery = graphql`
|
||||||
|
query PoolRemoveQuery {
|
||||||
|
content: allFile(filter: { relativePath: { eq: "price.json" } }) {
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
childContentJson {
|
||||||
|
pool {
|
||||||
|
remove {
|
||||||
|
title
|
||||||
|
simple
|
||||||
|
advanced
|
||||||
|
output {
|
||||||
|
titleIn
|
||||||
|
titleOut
|
||||||
|
}
|
||||||
|
action
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
export default function Remove({
|
||||||
|
setShowRemove,
|
||||||
|
refreshInfo,
|
||||||
|
poolAddress,
|
||||||
|
poolTokens,
|
||||||
|
totalPoolTokens,
|
||||||
|
dtSymbol
|
||||||
|
}: {
|
||||||
|
setShowRemove: (show: boolean) => void
|
||||||
|
refreshInfo: () => void
|
||||||
|
poolAddress: string
|
||||||
|
poolTokens: string
|
||||||
|
totalPoolTokens: string
|
||||||
|
dtSymbol: string
|
||||||
|
}): ReactElement {
|
||||||
|
const data = useStaticQuery(contentQuery)
|
||||||
|
const content = data.content.edges[0].node.childContentJson.pool.remove
|
||||||
|
|
||||||
|
const slippagePresets = ['5', '10', '15', '25', '50']
|
||||||
|
const { accountId } = useWeb3()
|
||||||
|
const { ocean } = useOcean()
|
||||||
|
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')
|
||||||
|
|
||||||
|
Decimal.set({ toExpNeg: -18, precision: 18, rounding: 1 })
|
||||||
|
|
||||||
|
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)
|
||||||
|
refreshInfo()
|
||||||
|
} catch (error) {
|
||||||
|
Logger.error(error.message)
|
||||||
|
toast.error(error.message)
|
||||||
|
} finally {
|
||||||
|
setIsLoading(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get and set max percentage
|
||||||
|
useEffect(() => {
|
||||||
|
if (!ocean || !poolTokens) return
|
||||||
|
|
||||||
|
async function getMax() {
|
||||||
|
const amountMaxPercent =
|
||||||
|
isAdvanced === true
|
||||||
|
? '100'
|
||||||
|
: await getMaxPercentRemove(ocean, poolAddress, poolTokens)
|
||||||
|
setAmountMaxPercent(amountMaxPercent)
|
||||||
|
}
|
||||||
|
getMax()
|
||||||
|
}, [ocean, isAdvanced, 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)
|
||||||
|
}, 150)
|
||||||
|
)
|
||||||
|
// Check and set outputs when amountPoolShares changes
|
||||||
|
useEffect(() => {
|
||||||
|
if (!ocean || !poolTokens) return
|
||||||
|
getValues.current(amountPoolShares, isAdvanced)
|
||||||
|
}, [
|
||||||
|
amountPoolShares,
|
||||||
|
isAdvanced,
|
||||||
|
ocean,
|
||||||
|
poolTokens,
|
||||||
|
poolAddress,
|
||||||
|
totalPoolTokens
|
||||||
|
])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const minOceanAmount = new Decimal(amountOcean)
|
||||||
|
.mul(new Decimal(100).minus(new Decimal(slippage)))
|
||||||
|
.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])
|
||||||
|
|
||||||
|
// Set amountPoolShares based on set slider value
|
||||||
|
function handleAmountPercentChange(e: ChangeEvent<HTMLInputElement>) {
|
||||||
|
setAmountPercent(e.target.value)
|
||||||
|
if (!poolTokens) return
|
||||||
|
|
||||||
|
const amountPoolShares = new Decimal(e.target.value)
|
||||||
|
.dividedBy(100)
|
||||||
|
.mul(new Decimal(poolTokens))
|
||||||
|
.toString()
|
||||||
|
|
||||||
|
setAmountPoolShares(`${amountPoolShares.slice(0, 18)}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleMaxButton(e: ChangeEvent<HTMLInputElement>) {
|
||||||
|
e.preventDefault()
|
||||||
|
setAmountPercent(amountMaxPercent)
|
||||||
|
|
||||||
|
const amountPoolShares = new Decimal(amountMaxPercent)
|
||||||
|
.dividedBy(100)
|
||||||
|
.mul(new Decimal(poolTokens))
|
||||||
|
.toString()
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={styles.remove}>
|
||||||
|
<Header title={content.title} backAction={() => setShowRemove(false)} />
|
||||||
|
|
||||||
|
<form className={styles.removeInput}>
|
||||||
|
<UserLiquidity amount={poolTokens} symbol="pool shares" />
|
||||||
|
<div className={styles.range}>
|
||||||
|
<h3>{amountPercent}%</h3>
|
||||||
|
<div className={styles.slider}>
|
||||||
|
<input
|
||||||
|
type="range"
|
||||||
|
min="0"
|
||||||
|
max={amountMaxPercent}
|
||||||
|
disabled={!isAssetNetwork}
|
||||||
|
value={amountPercent}
|
||||||
|
onChange={(e: ChangeEvent<HTMLInputElement>) =>
|
||||||
|
handleAmountPercentChange(e)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
style="text"
|
||||||
|
size="small"
|
||||||
|
className={styles.maximum}
|
||||||
|
disabled={!isAssetNetwork}
|
||||||
|
onClick={(e: ChangeEvent<HTMLInputElement>) => handleMaxButton(e)}
|
||||||
|
>
|
||||||
|
{`${amountMaxPercent}% max`}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<FormHelp>
|
||||||
|
{isAdvanced === true ? content.advanced : content.simple}
|
||||||
|
</FormHelp>
|
||||||
|
<Button
|
||||||
|
style="text"
|
||||||
|
size="small"
|
||||||
|
onClick={(e: FormEvent<HTMLButtonElement>) =>
|
||||||
|
handleAdvancedButton(e)
|
||||||
|
}
|
||||||
|
disabled={!isAssetNetwork}
|
||||||
|
className={styles.toggle}
|
||||||
|
>
|
||||||
|
{isAdvanced === true ? 'Simple' : 'Advanced'}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
<div className={styles.output}>
|
||||||
|
<div>
|
||||||
|
<p>{content.output.titleIn}</p>
|
||||||
|
<Token symbol="pool shares" balance={amountPoolShares} noIcon />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p>{content.output.titleOut} minimum</p>
|
||||||
|
{isAdvanced === true ? (
|
||||||
|
<>
|
||||||
|
<Token symbol="OCEAN" balance={minOceanAmount} />
|
||||||
|
<Token symbol={dtSymbol} balance={minDatatokenAmount} />
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<Token symbol="OCEAN" balance={minOceanAmount} />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className={styles.slippage}>
|
||||||
|
<strong>Expected price impact</strong>
|
||||||
|
<InputElement
|
||||||
|
name="slippage"
|
||||||
|
type="select"
|
||||||
|
size="mini"
|
||||||
|
postfix="%"
|
||||||
|
sortOptions={false}
|
||||||
|
options={slippagePresets}
|
||||||
|
disabled={!isAssetNetwork}
|
||||||
|
value={slippage}
|
||||||
|
onChange={(e: ChangeEvent<HTMLSelectElement>) =>
|
||||||
|
handleSlippageChange(e)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<Actions
|
||||||
|
isLoading={isLoading}
|
||||||
|
loaderMessage="Removing Liquidity..."
|
||||||
|
actionName={content.action}
|
||||||
|
action={() => handleRemoveLiquidity()}
|
||||||
|
successMessage="Successfully removed liquidity."
|
||||||
|
isDisabled={!isAssetNetwork}
|
||||||
|
txId={txId}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
@ -1,8 +1,8 @@
|
|||||||
import React, { ReactElement, useEffect, useState } from 'react'
|
import React, { ReactElement, useEffect, useState } from 'react'
|
||||||
import { Logger } from '@oceanprotocol/lib'
|
import { Logger } from '@oceanprotocol/lib'
|
||||||
import styles from './index.module.css'
|
import styles from './index.module.css'
|
||||||
|
import stylesActions from './Actions.module.css'
|
||||||
import PriceUnit from '../../../atoms/Price/PriceUnit'
|
import PriceUnit from '../../../atoms/Price/PriceUnit'
|
||||||
import Alert from '../../../atoms/Alert'
|
|
||||||
import Tooltip from '../../../atoms/Tooltip'
|
import Tooltip from '../../../atoms/Tooltip'
|
||||||
import ExplorerLink from '../../../atoms/ExplorerLink'
|
import ExplorerLink from '../../../atoms/ExplorerLink'
|
||||||
import Token from './Token'
|
import Token from './Token'
|
||||||
@ -19,10 +19,8 @@ import PoolTransactions from '../../../molecules/PoolTransactions'
|
|||||||
import { fetchData, getQueryContext } from '../../../../utils/subgraph'
|
import { fetchData, getQueryContext } from '../../../../utils/subgraph'
|
||||||
import { isValidNumber } from './../../../../utils/numberValidations'
|
import { isValidNumber } from './../../../../utils/numberValidations'
|
||||||
import Decimal from 'decimal.js'
|
import Decimal from 'decimal.js'
|
||||||
import {
|
import Remove from './Remove'
|
||||||
MigrationStatus,
|
import Button from '../../../atoms/Button'
|
||||||
useMigrationStatus
|
|
||||||
} from '../../../../providers/Migration'
|
|
||||||
|
|
||||||
const REFETCH_INTERVAL = 5000
|
const REFETCH_INTERVAL = 5000
|
||||||
|
|
||||||
@ -86,11 +84,10 @@ export default function Pool(): ReactElement {
|
|||||||
const content = data.content.edges[0].node.childContentJson.pool
|
const content = data.content.edges[0].node.childContentJson.pool
|
||||||
|
|
||||||
const { accountId } = useWeb3()
|
const { accountId } = useWeb3()
|
||||||
const { status } = useMigrationStatus()
|
|
||||||
|
|
||||||
const [dtSymbol, setDtSymbol] = useState<string>()
|
const [dtSymbol, setDtSymbol] = useState<string>()
|
||||||
const [oceanSymbol, setOceanSymbol] = useState<string>()
|
const [oceanSymbol, setOceanSymbol] = useState<string>()
|
||||||
const { ddo, owner, price } = useAsset()
|
const { ddo, owner, price, isInPurgatory, isAssetNetwork } = useAsset()
|
||||||
|
|
||||||
const [poolTokens, setPoolTokens] = useState<string>()
|
const [poolTokens, setPoolTokens] = useState<string>()
|
||||||
const [totalPoolTokens, setTotalPoolTokens] = useState<string>()
|
const [totalPoolTokens, setTotalPoolTokens] = useState<string>()
|
||||||
@ -116,6 +113,13 @@ export default function Pool(): ReactElement {
|
|||||||
const [liquidityFetchInterval, setLiquidityFetchInterval] =
|
const [liquidityFetchInterval, setLiquidityFetchInterval] =
|
||||||
useState<NodeJS.Timeout>()
|
useState<NodeJS.Timeout>()
|
||||||
|
|
||||||
|
const [showRemove, setShowRemove] = useState(false)
|
||||||
|
const [isRemoveDisabled, setIsRemoveDisabled] = useState(false)
|
||||||
|
|
||||||
|
const [hasAddedLiquidity, setHasAddedLiquidity] = useState(false)
|
||||||
|
// the purpose of the value is just to trigger the effect
|
||||||
|
const [refreshPool, setRefreshPool] = useState(false)
|
||||||
|
|
||||||
async function getPoolLiquidity() {
|
async function getPoolLiquidity() {
|
||||||
const queryContext = getQueryContext(ddo.chainId)
|
const queryContext = getQueryContext(ddo.chainId)
|
||||||
const queryVariables = {
|
const queryVariables = {
|
||||||
@ -267,6 +271,10 @@ export default function Pool(): ReactElement {
|
|||||||
init()
|
init()
|
||||||
}, [dataLiquidity, ddo.dataToken, price.datatoken, price.ocean, price?.value])
|
}, [dataLiquidity, ddo.dataToken, price.datatoken, price.ocean, price?.value])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setIsRemoveDisabled(isInPurgatory && owner === accountId)
|
||||||
|
}, [isInPurgatory, owner, accountId])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!dataLiquidity) return
|
if (!dataLiquidity) return
|
||||||
const poolShare =
|
const poolShare =
|
||||||
@ -280,6 +288,7 @@ export default function Pool(): ReactElement {
|
|||||||
.toFixed(5)
|
.toFixed(5)
|
||||||
|
|
||||||
setPoolShare(poolShare)
|
setPoolShare(poolShare)
|
||||||
|
setHasAddedLiquidity(Number(poolShare) > 0)
|
||||||
|
|
||||||
const totalUserLiquidityInOcean =
|
const totalUserLiquidityInOcean =
|
||||||
isValidNumber(userLiquidity?.ocean) &&
|
isValidNumber(userLiquidity?.ocean) &&
|
||||||
@ -350,7 +359,23 @@ export default function Pool(): ReactElement {
|
|||||||
init()
|
init()
|
||||||
}, [accountId, price, ddo, owner, totalPoolTokens])
|
}, [accountId, price, ddo, owner, totalPoolTokens])
|
||||||
|
|
||||||
return (
|
const refreshInfo = async () => {
|
||||||
|
setRefreshPool(!refreshPool)
|
||||||
|
|
||||||
|
// need some form of replacement or something.
|
||||||
|
// await refreshPrice()
|
||||||
|
}
|
||||||
|
|
||||||
|
return showRemove ? (
|
||||||
|
<Remove
|
||||||
|
setShowRemove={setShowRemove}
|
||||||
|
refreshInfo={refreshInfo}
|
||||||
|
poolAddress={price.address}
|
||||||
|
poolTokens={poolTokens}
|
||||||
|
totalPoolTokens={totalPoolTokens}
|
||||||
|
dtSymbol={dtSymbol}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
<>
|
<>
|
||||||
<div className={styles.dataToken}>
|
<div className={styles.dataToken}>
|
||||||
<PriceUnit price="1" symbol={dtSymbol} /> ={' '}
|
<PriceUnit price="1" symbol={dtSymbol} /> ={' '}
|
||||||
@ -433,15 +458,16 @@ export default function Pool(): ReactElement {
|
|||||||
>
|
>
|
||||||
<Token symbol="% swap fee" balance={swapFee} noIcon />
|
<Token symbol="% swap fee" balance={swapFee} noIcon />
|
||||||
</TokenList>
|
</TokenList>
|
||||||
<Alert
|
|
||||||
title="Adding and removing liquidity is disabled"
|
<div className={stylesActions.actions}>
|
||||||
text={
|
<Button
|
||||||
status === MigrationStatus.ALLOWED
|
size="small"
|
||||||
? 'Pool Shares are currently being locked. Adding and removing liquidity is disabled while the pool shares are being locked.'
|
onClick={() => setShowRemove(true)}
|
||||||
: 'Adding and removing liquidity is currently disabled for all pools.'
|
disabled={!isAssetNetwork || !hasAddedLiquidity || isRemoveDisabled}
|
||||||
}
|
>
|
||||||
state="info"
|
Remove Liquidity
|
||||||
/>
|
</Button>
|
||||||
|
</div>
|
||||||
|
|
||||||
{accountId && (
|
{accountId && (
|
||||||
<AssetActionHistoryTable title="Your Pool Transactions">
|
<AssetActionHistoryTable title="Your Pool Transactions">
|
||||||
|
37
src/components/organisms/AssetActions/Pool/utils.ts
Normal file
37
src/components/organisms/AssetActions/Pool/utils.ts
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
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,
|
||||||
|
poolTokens: string
|
||||||
|
): Promise<string> {
|
||||||
|
const amountMaxOcean = await ocean.pool.getOceanMaxRemoveLiquidity(
|
||||||
|
poolAddress
|
||||||
|
)
|
||||||
|
|
||||||
|
const amountMaxPoolShares =
|
||||||
|
await ocean.pool.getPoolSharesRequiredToRemoveOcean(
|
||||||
|
poolAddress,
|
||||||
|
amountMaxOcean
|
||||||
|
)
|
||||||
|
|
||||||
|
let amountMaxPercent =
|
||||||
|
isValidNumber(amountMaxPoolShares) && isValidNumber(poolTokens)
|
||||||
|
? new Decimal(amountMaxPoolShares)
|
||||||
|
.dividedBy(new Decimal(poolTokens))
|
||||||
|
.mul(100)
|
||||||
|
.floor()
|
||||||
|
.toString()
|
||||||
|
: '0'
|
||||||
|
|
||||||
|
if (Number(amountMaxPercent) > 100) {
|
||||||
|
amountMaxPercent = '100'
|
||||||
|
}
|
||||||
|
|
||||||
|
return amountMaxPercent
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
.slippage {
|
||||||
|
font-size: var(--font-size-small);
|
||||||
|
border-top: 1px solid var(--border-color);
|
||||||
|
margin-left: -2rem;
|
||||||
|
margin-right: -2rem;
|
||||||
|
padding: calc(var(--spacer) / 4) var(--spacer);
|
||||||
|
color: var(--color-secondary);
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
gap: calc(var(--spacer) / 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.slippage strong {
|
||||||
|
font-weight: var(--font-weight-base);
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-family: var(--font-family-base);
|
||||||
|
font-weight: var(--font-weight-base);
|
||||||
|
font-size: var(--font-size-mini);
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: calc(var(--spacer) / 4);
|
||||||
|
color: var(--color-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.slippage select {
|
||||||
|
width: fit-content;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
@ -135,7 +135,6 @@ export default function AssetActions(): ReactElement {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{price?.type === 'pool' && <Migration />}
|
|
||||||
<Permission eventType="consume">
|
<Permission eventType="consume">
|
||||||
<Tabs items={tabs} className={styles.actions} />
|
<Tabs items={tabs} className={styles.actions} />
|
||||||
</Permission>
|
</Permission>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user