Skip to content

Commit

Permalink
Merge pull request #667 from invariant-labs/fix-spamming-changing-fee…
Browse files Browse the repository at this point in the history
…-tier

fix crashing app when spamming on fee tier
  • Loading branch information
p6te authored Apr 16, 2024
2 parents b7b9ce5 + 630e68d commit 7fb37c8
Show file tree
Hide file tree
Showing 5 changed files with 127 additions and 71 deletions.
12 changes: 10 additions & 2 deletions src/components/FarmsList/StakeTile/StakeTile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,23 +46,31 @@ export const StakeTile: React.FC<IProps> = ({
const [progress, setProgress] = useState<ProgressState>('none')

useEffect(() => {
let timeout1: any
let timeout2: any

if (typeof stakeStatus === 'undefined') {
return
}

if (!stakeStatus.inProgress && progress === 'progress') {
setProgress(stakeStatus.success ? 'approvedWithSuccess' : 'approvedWithFail')

setTimeout(() => {
timeout1 = setTimeout(() => {
setProgress(stakeStatus.success ? 'success' : 'failed')
}, 1500)

setTimeout(() => {
timeout2 = setTimeout(() => {
setProgress('none')
}, 3000)
} else if (stakeStatus.inProgress && progress !== 'progress') {
setProgress('progress')
}

return () => {
clearTimeout(timeout1)
clearTimeout(timeout2)
}
}, [stakeStatus])

const data = xToY
Expand Down
19 changes: 14 additions & 5 deletions src/components/NewPosition/RangeSelector/RangeSelector.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Button, Grid, Tooltip, Typography } from '@material-ui/core'
import React, { useState, useEffect } from 'react'
import React, { useState, useEffect, useRef } from 'react'
import PriceRangePlot, { TickPlotPositionData } from '@components/PriceRangePlot/PriceRangePlot'
import RangeInput from '@components/Inputs/RangeInput/RangeInput'
import {
Expand Down Expand Up @@ -101,6 +101,15 @@ export const RangeSelector: React.FC<IRangeSelector> = ({

const [isPlotDiscrete, setIsPlotDiscrete] = useState(initialIsDiscreteValue)

const isMountedRef = useRef(false)

useEffect(() => {
isMountedRef.current = true
return () => {
isMountedRef.current = false
}
}, [])

const zoomMinus = () => {
const diff = plotMax - plotMin
const newMin = plotMin - diff / 4
Expand Down Expand Up @@ -230,13 +239,13 @@ export const RangeSelector: React.FC<IRangeSelector> = ({
}

useEffect(() => {
if (currentPairReversed !== null) {
if (currentPairReversed !== null && isMountedRef.current) {
reversePlot()
}
}, [currentPairReversed])

useEffect(() => {
if (ticksLoading) {
if (ticksLoading && isMountedRef.current) {
resetPlot()
}
}, [ticksLoading, midPrice])
Expand Down Expand Up @@ -285,7 +294,7 @@ export const RangeSelector: React.FC<IRangeSelector> = ({
}

useEffect(() => {
if (positionOpeningMethod === 'concentration') {
if (positionOpeningMethod === 'concentration' && isMountedRef.current) {
setConcentrationIndex(0)

const { leftRange, rightRange } = calculateConcentrationRange(
Expand All @@ -303,7 +312,7 @@ export const RangeSelector: React.FC<IRangeSelector> = ({
}, [positionOpeningMethod])

useEffect(() => {
if (positionOpeningMethod === 'concentration' && !ticksLoading) {
if (positionOpeningMethod === 'concentration' && !ticksLoading && isMountedRef.current) {
const index =
concentrationIndex > concentrationArray.length - 1
? concentrationArray.length - 1
Expand Down
12 changes: 10 additions & 2 deletions src/components/Swap/Swap.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -423,9 +423,17 @@ export const Swap: React.FC<ISwap> = ({
setDetailsOpen(!detailsOpen)
}

React.useEffect(() => {
useEffect(() => {
let timerId: any

if (lockAnimation) {
setTimeout(() => setLockAnimation(false), 500)
timerId = setTimeout(() => setLockAnimation(false), 500)
}

return () => {
if (timerId) {
clearTimeout(timerId)
}
}
}, [lockAnimation])

Expand Down
143 changes: 83 additions & 60 deletions src/containers/NewPositionWrapper/NewPositionWrapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import {
printBN
} from '@consts/utils'
import { Pair, calculatePriceSqrt, getMarketAddress } from '@invariant-labs/sdk'
import { Decimal } from '@invariant-labs/sdk/lib/market'
import { DECIMAL } from '@invariant-labs/sdk/lib/utils'
import { getLiquidityByX, getLiquidityByY } from '@invariant-labs/sdk/src/math'
import { feeToTickSpacing, getMaxTick } from '@invariant-labs/sdk/src/utils'
Expand All @@ -41,7 +40,7 @@ import { PublicKey } from '@solana/web3.js'
import { getCurrentSolanaConnection, networkTypetoProgramNetwork } from '@web3/connection'
import { openWalletSelectorModal } from '@web3/selector'
import { History } from 'history'
import React, { useEffect, useMemo, useState } from 'react'
import React, { useEffect, useMemo, useRef, useState } from 'react'
import { useDispatch, useSelector } from 'react-redux'

export interface IProps {
Expand Down Expand Up @@ -78,8 +77,6 @@ export const NewPositionWrapper: React.FC<IProps> = ({

const [poolIndex, setPoolIndex] = useState<number | null>(null)

const [liquidity, setLiquidity] = useState<Decimal>({ v: new BN(0) })

const [progress, setProgress] = useState<ProgressState>('none')

const [tokenAIndex, setTokenAIndex] = useState<number | null>(null)
Expand All @@ -89,11 +86,25 @@ export const NewPositionWrapper: React.FC<IProps> = ({

const [globalPrice, setGlobalPrice] = useState<number | undefined>(undefined)

const isMountedRef = useRef(false)

useEffect(() => {
isMountedRef.current = true
return () => {
isMountedRef.current = false
}
}, [])

const liquidityRef = useRef<any>({ v: new BN(0) })

useEffect(() => {
setProgress('none')
}, [poolIndex])

useEffect(() => {
let timerId1: any
let timerId2: any

if (!inProgress && progress === 'progress') {
setProgress(success ? 'approvedWithSuccess' : 'approvedWithFail')

Expand All @@ -109,14 +120,19 @@ export const NewPositionWrapper: React.FC<IProps> = ({
)
}

setTimeout(() => {
timerId1 = setTimeout(() => {
setProgress(success ? 'success' : 'failed')
}, 1500)

setTimeout(() => {
timerId2 = setTimeout(() => {
setProgress('none')
}, 3000)
}

return () => {
clearTimeout(timerId1)
clearTimeout(timerId2)
}
}, [success, inProgress])

const isXtoY = useMemo(() => {
Expand Down Expand Up @@ -436,6 +452,58 @@ export const NewPositionWrapper: React.FC<IProps> = ({
return poolAddress
}

const calcAmount = (amount: BN, left: number, right: number, tokenAddress: PublicKey) => {
if (tokenAIndex === null || tokenBIndex === null || isNaN(left) || isNaN(right)) {
return new BN(0)
}

const byX = tokenAddress.equals(
isXtoY ? tokens[tokenAIndex].assetAddress : tokens[tokenBIndex].assetAddress
)
const lowerTick = Math.min(left, right)
const upperTick = Math.max(left, right)

try {
if (byX) {
const result = getLiquidityByX(
amount,
lowerTick,
upperTick,
poolIndex !== null ? allPools[poolIndex].sqrtPrice : calculatePriceSqrt(midPrice.index),
true
)
if (isMountedRef.current) {
liquidityRef.current = result.liquidity
}
return result.y
}
const result = getLiquidityByY(
amount,
lowerTick,
upperTick,
poolIndex !== null ? allPools[poolIndex].sqrtPrice : calculatePriceSqrt(midPrice.index),
true
)
if (isMountedRef.current) {
liquidityRef.current = result.liquidity
}
return result.x
} catch (error) {
const result = (byX ? getLiquidityByY : getLiquidityByX)(
amount,
lowerTick,
upperTick,
poolIndex !== null ? allPools[poolIndex].sqrtPrice : calculatePriceSqrt(midPrice.index),
true
)
if (isMountedRef.current) {
liquidityRef.current = result.liquidity
}
}

return new BN(0)
}

return (
<NewPosition
initialTokenFrom={initialTokenFrom}
Expand Down Expand Up @@ -474,14 +542,18 @@ export const NewPositionWrapper: React.FC<IProps> = ({
fee.eq(ALL_FEE_TIERS_DATA[feeTierIndex].tier.fee)
)
) {
setPoolIndex(index !== -1 ? index : null)
setCurrentPairReversed(null)
if (isMountedRef.current) {
setPoolIndex(index !== -1 ? index : null)
setCurrentPairReversed(null)
}
} else if (
tokenAIndex === tokenB &&
tokenBIndex === tokenA &&
fee.eq(ALL_FEE_TIERS_DATA[feeTierIndex].tier.fee)
) {
setCurrentPairReversed(currentPairReversed === null ? true : !currentPairReversed)
if (isMountedRef.current) {
setCurrentPairReversed(currentPairReversed === null ? true : !currentPairReversed)
}
}

if (index !== -1 && index !== poolIndex) {
Expand Down Expand Up @@ -538,7 +610,7 @@ export const NewPositionWrapper: React.FC<IProps> = ({
fee,
lowerTick,
upperTick,
liquidityDelta: liquidity,
liquidityDelta: liquidityRef.current,
initPool: poolIndex === null,
initTick: poolIndex === null ? midPrice.index : undefined,
xAmount: Math.floor(xAmount),
Expand All @@ -553,56 +625,7 @@ export const NewPositionWrapper: React.FC<IProps> = ({
)
}}
isCurrentPoolExisting={poolIndex !== null}
calcAmount={(amount, left, right, tokenAddress) => {
if (tokenAIndex === null || tokenBIndex === null || isNaN(left) || isNaN(right)) {
return new BN(0)
}

const byX = tokenAddress.equals(
isXtoY ? tokens[tokenAIndex].assetAddress : tokens[tokenBIndex].assetAddress
)
const lowerTick = Math.min(left, right)
const upperTick = Math.max(left, right)

try {
if (byX) {
const result = getLiquidityByX(
amount,
lowerTick,
upperTick,
poolIndex !== null
? allPools[poolIndex].sqrtPrice
: calculatePriceSqrt(midPrice.index),
true
)
setLiquidity(result.liquidity)

return result.y
}

const result = getLiquidityByY(
amount,
lowerTick,
upperTick,
poolIndex !== null ? allPools[poolIndex].sqrtPrice : calculatePriceSqrt(midPrice.index),
true
)
setLiquidity(result.liquidity)

return result.x
} catch (error) {
const result = (byX ? getLiquidityByY : getLiquidityByX)(
amount,
lowerTick,
upperTick,
poolIndex !== null ? allPools[poolIndex].sqrtPrice : calculatePriceSqrt(midPrice.index),
true
)
setLiquidity(result.liquidity)
}

return new BN(0)
}}
calcAmount={calcAmount}
ticksLoading={ticksLoading}
showNoConnected={walletStatus !== Status.Initialized}
noConnectedBlockerProps={{
Expand Down
12 changes: 10 additions & 2 deletions src/containers/WrappedSwap/WrappedSwap.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,17 +48,25 @@ export const WrappedSwap = () => {
const [tokenTo, setTokenTo] = useState<PublicKey | null>(null)

useEffect(() => {
let timerId1: any
let timerId2: any

if (!inProgress && progress === 'progress') {
setProgress(success ? 'approvedWithSuccess' : 'approvedWithFail')

setTimeout(() => {
timerId1 = setTimeout(() => {
setProgress(success ? 'success' : 'failed')
}, 1500)

setTimeout(() => {
timerId2 = setTimeout(() => {
setProgress('none')
}, 3000)
}

return () => {
clearTimeout(timerId1)
clearTimeout(timerId2)
}
}, [success, inProgress])

useEffect(() => {
Expand Down

0 comments on commit 7fb37c8

Please sign in to comment.