Skip to content

Commit

Permalink
Merge pull request #41 from invariant-labs/add-liquidity-receive-amou…
Browse files Browse the repository at this point in the history
…nt-functionality

add receive amount calculations in add liquidity tab
  • Loading branch information
zielvna authored Aug 21, 2024
2 parents 6073916 + bfb5e84 commit 1ed4946
Show file tree
Hide file tree
Showing 10 changed files with 168 additions and 31 deletions.
8 changes: 4 additions & 4 deletions frontend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"dependencies": {
"@emotion/react": "^11.13.0",
"@emotion/styled": "^11.13.0",
"@invariant-labs/eclipse-link-sdk": "^0.1.1",
"@invariant-labs/eclipse-link-sdk": "^0.1.3",
"@invariant-labs/sdk-eclipse": "^0.0.17",
"@mui/icons-material": "^5.16.7",
"@mui/material": "^5.16.7",
Expand Down
46 changes: 41 additions & 5 deletions frontend/src/components/Liquidity/Liquidity.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ import classNames from 'classnames'
import FeeSwitch from './FeeSwitch/FeeSwitch'
import Select from '@components/Inputs/Select/Select'
import SwapList from '@static/svg/swap-list.svg'
import { getMaxLiquidity, liquidityToLpTokenAmount } from '@invariant-labs/eclipse-link-sdk'
import { getMaxTick, getMinTick } from '@invariant-labs/sdk-eclipse/lib/utils'
import { Decimal } from '@invariant-labs/sdk-eclipse/lib/market'

export interface ILiquidity {
initialTokenFrom: string
Expand Down Expand Up @@ -67,6 +70,7 @@ export interface ILiquidity {
tokenBPriceData?: TokenPriceData
priceALoading?: boolean
priceBLoading?: boolean
sqrtPrice: Decimal
}

export const Liquidity: React.FC<ILiquidity> = ({
Expand All @@ -84,9 +88,9 @@ export const Liquidity: React.FC<ILiquidity> = ({
noConnectedBlockerProps,
progress,
// isXtoY,
// xDecimal,
// yDecimal,
// tickSpacing,
xDecimal,
yDecimal,
tickSpacing,
// isWaitingForNewPool,
poolIndex,
bestTiers,
Expand All @@ -102,7 +106,8 @@ export const Liquidity: React.FC<ILiquidity> = ({
tokenAPriceData,
tokenBPriceData,
priceALoading,
priceBLoading
priceBLoading,
sqrtPrice
}) => {
const { classes } = useStyles()
const navigate = useNavigate()
Expand Down Expand Up @@ -246,6 +251,37 @@ export const Liquidity: React.FC<ILiquidity> = ({
}
}, [poolIndex])

const LPTokenReceive = useMemo(() => {
if (
tokenAIndex !== null &&
tokenBIndex !== null &&
tokenADeposit !== null &&
tokenBDeposit !== null
) {
console.log('sqrt price', sqrtPrice.v.toString(), tickSpacing, getMaxTick(tickSpacing))

const maxLiquidity = getMaxLiquidity(
{ v: printBNtoBN(tokenADeposit, xDecimal) },
{ v: printBNtoBN(tokenBDeposit, yDecimal) },
getMinTick(tickSpacing),
getMaxTick(tickSpacing),
sqrtPrice,
true
)

const lpTokenAmount = liquidityToLpTokenAmount(
{ v: new BN(0) },
{ v: new BN(0) },
maxLiquidity.liquidity,
false
)

return printBN(lpTokenAmount.v.toString(), 6)
}

return '0'
}, [tokenADeposit, tokenBDeposit, poolIndex])

return (
<Grid container className={classes.wrapper} direction='column'>
{showNoConnected && <NoConnected {...noConnectedBlockerProps} />}
Expand Down Expand Up @@ -406,7 +442,7 @@ export const Liquidity: React.FC<ILiquidity> = ({
feeTierIndex={currentFeeIndex}
progress={progress}
LPTokenName={lpTokenName ?? ''}
LPTokenReceive={''}
LPTokenReceive={LPTokenReceive}
priceA={tokenAPriceData?.price}
priceB={tokenBPriceData?.price}
priceALoading={priceALoading}
Expand Down
43 changes: 31 additions & 12 deletions frontend/src/containers/LiquidityWrapper/LiquidityWrapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import {
getLiquidityByYInFullRange
} from '@invariant-labs/eclipse-link-sdk'
import { FEE_TIERS, feeToTickSpacing } from '@invariant-labs/sdk-eclipse/lib/utils'
import { poolsArraySortedByFees } from '@store/selectors/pools'
import { lpPoolsArraySortedByFees, poolsArraySortedByFees } from '@store/selectors/pools'
import { Pair } from '@invariant-labs/sdk-eclipse'

export interface IProps {
Expand All @@ -42,6 +42,7 @@ export const LiquidityWrapper: React.FC<IProps> = ({

const canUserCreateNewPool = useSelector(canCreateNewPool(currentNetwork))
const [poolIndex, setPoolIndex] = useState<number | null>(null)
const [lpPoolIndex, setLpPoolIndex] = useState<number | null>(null)

// const [progress, setProgress] = useState<ProgressState>('none')
const [feeIndex, setFeeIndex] = useState(0)
Expand Down Expand Up @@ -148,6 +149,7 @@ export const LiquidityWrapper: React.FC<IProps> = ({
localStorage.getItem('HIDE_UNKNOWN_TOKENS') === null

const allPools = useSelector(poolsArraySortedByFees)
const allLpPools = useSelector(lpPoolsArraySortedByFees)
const liquidityRef = useRef<any>({ v: new BN(0) })
const isMountedRef = useRef(false)

Expand All @@ -171,11 +173,13 @@ export const LiquidityWrapper: React.FC<IProps> = ({

useEffect(() => {
if (tokenAIndex !== null && tokenBIndex !== null) {
dispatch(
poolsActions.getPoolData(
new Pair(tokens[tokenAIndex].address, tokens[tokenBIndex].address, FEE_TIERS[feeIndex])
)
const pair = new Pair(
tokens[tokenAIndex].address,
tokens[tokenBIndex].address,
FEE_TIERS[feeIndex]
)
dispatch(poolsActions.getPoolData(pair))
dispatch(poolsActions.getLpPoolData(pair))
}
}, [tokenAIndex, tokenBIndex, feeIndex])

Expand All @@ -194,6 +198,23 @@ export const LiquidityWrapper: React.FC<IProps> = ({
}
}, [allPools])

useEffect(() => {
if (tokenAIndex !== null && tokenBIndex !== null) {
const index = allLpPools.findIndex(
pool =>
pool.fee.v.eq(fee) &&
((pool.tokenX.equals(tokens[tokenAIndex].assetAddress) &&
pool.tokenY.equals(tokens[tokenBIndex].assetAddress)) ||
(pool.tokenX.equals(tokens[tokenBIndex].assetAddress) &&
pool.tokenY.equals(tokens[tokenAIndex].assetAddress)))
)

setLpPoolIndex(index !== -1 ? index : null)
}
}, [allLpPools])

console.log(lpPoolIndex)

useEffect(() => {
isMountedRef.current = true
return () => {
Expand All @@ -211,13 +232,10 @@ export const LiquidityWrapper: React.FC<IProps> = ({
midPrice={10}
setMidPrice={() => {}}
addLiquidityHandler={() => {}}
removeLiquidityHandler={(xAmount, yAmount) => {
console.log(xAmount, yAmount)
}}
removeLiquidityHandler={() => {}}
onChangePositionTokens={(tokenA, tokenB, feeTierIndex) => {
setTokenAIndex(tokenA)
setTokenBIndex(tokenB)
console.log(tokenA, tokenB)
setFeeIndex(feeTierIndex)
}}
calcAmount={calcAmount}
Expand All @@ -232,9 +250,9 @@ export const LiquidityWrapper: React.FC<IProps> = ({
}}
progress={'none'}
isXtoY={true}
xDecimal={12}
yDecimal={10}
tickSpacing={1}
xDecimal={tokenAIndex !== null ? tokens[tokenAIndex]?.decimals : 0}
yDecimal={tokenBIndex !== null ? tokens[tokenBIndex]?.decimals : 0}
tickSpacing={tickSpacing}
isWaitingForNewPool={false}
poolIndex={poolIndex}
bestTiers={bestTiers[currentNetwork]}
Expand All @@ -251,6 +269,7 @@ export const LiquidityWrapper: React.FC<IProps> = ({
tokenBPriceData={{ price: 1 }}
priceALoading={false}
priceBLoading={false}
sqrtPrice={poolIndex !== null ? allPools[poolIndex].sqrtPrice : { v: new BN(0) }}
/>
)
}
Expand Down
24 changes: 24 additions & 0 deletions frontend/src/store/reducers/pools.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { LpPoolStructure } from '@invariant-labs/eclipse-link-sdk/dist/types'
import { Pair } from '@invariant-labs/sdk-eclipse'
import { PoolStructure } from '@invariant-labs/sdk-eclipse/lib/market'
import { createSlice, PayloadAction } from '@reduxjs/toolkit'
Expand All @@ -10,9 +11,14 @@ export interface PoolWithAddress extends PoolStructure {
address: PublicKey
}

export interface LpPoolWithAddress extends LpPoolStructure {
address: PublicKey
}

export interface IPoolsStore {
tokens: Record<string, Token>
pools: { [key in string]: PoolWithAddress }
lpPools: { [key in string]: LpPoolWithAddress }
// poolTicks: { [key in string]: Tick[] }
// nearestPoolTicksForPair: { [key in string]: Tick[] }
isLoadingLatestPoolsForTransaction: boolean
Expand Down Expand Up @@ -56,6 +62,7 @@ export interface FetchTicksAndTickMaps {
export const defaultState: IPoolsStore = {
tokens: {},
pools: {},
lpPools: {},
// poolTicks: {},
// nearestPoolTicksForPair: {},
isLoadingLatestPoolsForTransaction: false
Expand Down Expand Up @@ -115,6 +122,23 @@ const poolsSlice = createSlice({
getAllPoolsForPairData(state, _action: PayloadAction<PairTokens>) {
state.isLoadingLatestPoolsForTransaction = true

return state
},
getLpPoolData(state, _action: PayloadAction<Pair>) {
state.isLoadingLatestPoolsForTransaction = true

return state
},
addLpPools(state, action: PayloadAction<LpPoolWithAddress[]>) {
const newData = action.payload.reduce(
(acc, pool) => ({
...acc,
[pool.address.toString()]: pool
}),
{}
)
state.lpPools = R.merge(state.lpPools, newData)
state.isLoadingLatestPoolsForTransaction = false
return state
}
}
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/store/reducers/swap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { PayloadType } from './types'

//TODO replace mock fromFee
export const fromFee = (fee: BN) => {
console.log(fee)
return fee
}

//TODO replace mock Decimal
Expand Down
31 changes: 30 additions & 1 deletion frontend/src/store/sagas/pools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { getMarketProgram } from '@web3/programs/amm'
import { getPools } from '@store/consts/utils'
import { Pair } from '@invariant-labs/sdk-eclipse'
import { FEE_TIERS } from '@invariant-labs/sdk-eclipse/lib/utils'
import { getProtocolProgram } from '@web3/programs/protocol'

export interface iTick {
index: iTick[]
Expand Down Expand Up @@ -45,6 +46,30 @@ export function* fetchAllPoolsForPairData(action: PayloadAction<PairTokens>) {
yield* put(actions.addPools(pools))
}

export function* fetchLpPoolData(action: PayloadAction<Pair>) {
const networkType = yield* select(network)
const rpc = yield* select(rpcAddress)
const protocolProgram = yield* call(getProtocolProgram, networkType, rpc)
try {
const poolData = yield* call([protocolProgram, protocolProgram.getLpPool], action.payload)
const address = yield* call(
[action.payload, action.payload.getAddress],
protocolProgram.program.programId
)

yield* put(
actions.addLpPools([
{
...poolData,
address
}
])
)
} catch (error) {
yield* put(actions.addLpPools([]))
}
}

export function* getPoolDataHandler(): Generator {
yield* takeLatest(actions.getPoolData, fetchPoolData)
}
Expand All @@ -53,6 +78,10 @@ export function* getAllPoolsForPairDataHandler(): Generator {
yield* takeLatest(actions.getAllPoolsForPairData, fetchAllPoolsForPairData)
}

export function* getLpPoolDataHandler(): Generator {
yield* takeLatest(actions.getLpPoolData, fetchLpPoolData)
}

export function* poolsSaga(): Generator {
yield all([getPoolDataHandler, getAllPoolsForPairDataHandler].map(spawn))
yield all([getPoolDataHandler, getAllPoolsForPairDataHandler, getLpPoolDataHandler].map(spawn))
}
7 changes: 6 additions & 1 deletion frontend/src/store/selectors/pools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,21 @@ import { keySelectors, AnyProps } from './helpers'

const store = (s: AnyProps) => s[poolsSliceName] as IPoolsStore

export const { tokens, pools, isLoadingLatestPoolsForTransaction } = keySelectors(store, [
export const { tokens, pools, lpPools, isLoadingLatestPoolsForTransaction } = keySelectors(store, [
'tokens',
'pools',
'lpPools',
'isLoadingLatestPoolsForTransaction'
])

export const poolsArraySortedByFees = createSelector(pools, allPools =>
Object.values(allPools).sort((a, b) => a.fee.v.sub(b.fee.v).toNumber())
)

export const lpPoolsArraySortedByFees = createSelector(lpPools, allLpPools =>
Object.values(allLpPools).sort((a, b) => a.fee.v.sub(b.fee.v).toNumber())
)

export const hasTokens = createSelector(tokens, allTokens => !!Object.values(allTokens).length)

export const poolsSelectors = {
Expand Down
7 changes: 1 addition & 6 deletions frontend/src/utils/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,7 @@ export const printBN = (amount: BN, decimals: number): string => {
}

export const printBNtoBN = (amount: string, decimals: number): BN => {
console.log(amount)
const balanceString = amount.split('.')
console.log(balanceString)
if (balanceString.length !== 2) {
return new BN(balanceString[0] + '0'.repeat(decimals))
}
Expand Down Expand Up @@ -112,9 +110,7 @@ export const parseFeeToPathFee = (fee: BN): string => {
}

export const trimLeadingZeros = (amount: string): string => {
console.log(amount)
const amountParts = amount.split('.')
console.log(amountParts)

if (!amountParts.length) {
return '0'
Expand Down Expand Up @@ -144,8 +140,7 @@ export enum PositionTokenBlock {

//TODO replace mock calculatePriceSqrt
export const calculatePriceSqrt = (tick: number): BN => {
console.log(tick)
return new BN(1)
return new BN(tick)
}

export const determinePositionTokenBlock = (
Expand Down
Loading

0 comments on commit 1ed4946

Please sign in to comment.