Skip to content

Commit

Permalink
use liquidity math to adjust display of second token based on range
Browse files Browse the repository at this point in the history
  • Loading branch information
eli-d committed Jun 27, 2024
1 parent 78976e0 commit 0701f4f
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 32 deletions.
49 changes: 29 additions & 20 deletions web/src/components/StakeForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import CurrentPrice from "@/assets/icons/legend/current-price.svg";
import LiquidityDistribution from "@/assets/icons/legend/liquidity-distribution.svg";
import { Button } from "@/components/ui/button";
import { cn } from "@/lib/utils";
import { MAX_TICK, getSqrtRatioAtTick, sqrtPriceX96ToPrice } from "@/lib/math";
import { MAX_TICK, calculateX, calculateY, getLiquidityForAmount0, getLiquidityForAmount1, getSqrtRatioAtTick, sqrtPriceX96ToPrice } from "@/lib/math";
import { ammAddress } from "@/lib/addresses";
import { createChartData } from "@/lib/chartData";
import { output as seawaterContract } from "@/lib/abi/ISeawaterAMM";
Expand Down Expand Up @@ -44,7 +44,7 @@ import { graphql, useFragment } from "@/gql";
import { useGraphqlGlobal, useGraphqlUser } from "@/hooks/useGraphql";
import { usdFormat } from "@/lib/usdFormat";
import { Token as TokenType, fUSDC, getTokenFromAddress } from "@/config/tokens";
import { getFormattedPriceFromAmount, getTokenAmountFromRawAmountAndPrice } from "@/lib/amounts";
import { getFormattedPriceFromAmount } from "@/lib/amounts";

const colorGradient = new echarts.graphic.LinearGradient(
0,
Expand Down Expand Up @@ -111,6 +111,8 @@ export const StakeForm = ({ mode, poolId, positionId }: StakeFormProps) => {
priceUpper,
setPriceLower,
setPriceUpper,
tickLower,
tickUpper,
setTickLower,
setTickUpper,
} = useStakeStore();
Expand Down Expand Up @@ -148,11 +150,16 @@ export const StakeForm = ({ mode, poolId, positionId }: StakeFormProps) => {
const positionData_ = useFragment(PositionsFragment, userData?.getWallet)
const positionData = positionData_?.positions.positions.find(p => p.positionId === positionId)

const { upper: upperTick, lower: lowerTick } = positionData || {
const { upper: upperTickPosition, lower: lowerTickPosition } = positionData || {
upper: 0,
lower: 0
};

useEffect(() => {
setTickLower(lowerTickPosition)
setTickUpper(upperTickPosition)
}, [positionData])

const showMockData = useFeatureFlag("ui show demo data");

const router = useRouter();
Expand Down Expand Up @@ -212,26 +219,26 @@ export const StakeForm = ({ mode, poolId, positionId }: StakeFormProps) => {
}

useEffect(() => {
if (!token0AmountRaw || !curTick || tickLower === undefined || tickUpper === undefined)
return
const lower = BigInt(tickLower)
const upper = BigInt(tickUpper)

const cur = curTick.result
const sqp = getSqrtRatioAtTick(cur)
const sqa = getSqrtRatioAtTick(lower)
const sqb = getSqrtRatioAtTick(upper)

if (quotedToken === 'token0') {
const newToken1Amount = getTokenAmountFromRawAmountAndPrice(
BigInt(token0AmountRaw),
tokenPrice,
BigInt(token0.decimals),
BigInt(token1.decimals),
'mul'
)
const liq = getLiquidityForAmount0(cur, upper, BigInt(token0AmountRaw))
const newToken1Amount = calculateY(liq, sqa, sqp)
if (token1Balance?.value && newToken1Amount > token1Balance.value)
return
setToken1AmountRaw(newToken1Amount.toString())
}
else {
const newToken0Amount = getTokenAmountFromRawAmountAndPrice(
BigInt(token1AmountRaw),
tokenPrice,
BigInt(token0.decimals),
BigInt(token1.decimals),
'div'
);
const liq = getLiquidityForAmount1(cur, lower, BigInt(token1AmountRaw))
const newToken0Amount = calculateX(liq, sqb, sqp)
if (token0Balance?.value && newToken0Amount > token0Balance.value)
return
setToken0AmountRaw(newToken0Amount.toString())
Expand All @@ -244,7 +251,9 @@ export const StakeForm = ({ mode, poolId, positionId }: StakeFormProps) => {
token0AmountRaw,
token1AmountRaw,
tokenPrice,
quotedToken
quotedToken,
tickUpper,
tickLower,
]);

const setMaxBalance = (token: TokenType) => {
Expand All @@ -271,8 +280,8 @@ export const StakeForm = ({ mode, poolId, positionId }: StakeFormProps) => {
// set the ticks to the existing ticks of the pool
if (mode === "existing") {
const scale = token0.decimals - fUSDC.decimals
const priceLower = (1.0001 ** lowerTick * 10 ** scale).toFixed(fUSDC.decimals)
const priceHigher = (1.0001 ** upperTick * 10 ** scale).toFixed(fUSDC.decimals)
const priceLower = (1.0001 ** (tickLower ?? 0) * 10 ** scale).toFixed(fUSDC.decimals)
const priceHigher = (1.0001 ** (tickUpper ?? 0) * 10 ** scale).toFixed(fUSDC.decimals)
setPriceLower(priceLower, token0.decimals)
setPriceUpper(priceHigher, token0.decimals)
return
Expand Down
12 changes: 0 additions & 12 deletions web/src/lib/amounts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,23 +100,11 @@ const getFormattedPriceFromTick = (tick: number, decimals0: number, decimals1: n
return formattedPrice.length > 20 ? '∞ ' : formattedPrice
}

// get the amount of token1Unscaled, given the price and amount of token0Unscaled.
// mul sets the operation to scale up token0Unscaled by tokenPrice18 (assumes token0Unscaled is the base token)
// div sets the operation to divide token0Unscaled by tokenPrice18 (assumes token0Unscaled is the other token)
const getTokenAmountFromRawAmountAndPrice = (token0Unscaled: bigint, tokenPrice18: bigint, dec0: bigint, dec1: bigint, op: 'mul' | 'div'): bigint => {
const num = token0Unscaled * 10n ** dec0;
const dec = dec1 <= dec0 ? (dec0 - dec1) + dec0 : dec0;
return op === 'mul' ?
num * tokenPrice18 / 10n ** (dec + dec1) :
num / tokenPrice18
}

export {
getFormattedStringFromTokenAmount,
snapAmountToDecimals,
getTokenAmountFromFormattedString,
getFormattedPriceFromAmount,
getFormattedPriceFromTick,
getTokenAmountFromRawAmountAndPrice,
}

20 changes: 20 additions & 0 deletions web/src/lib/math.ts
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,26 @@ export const getAmountsForLiquidity = (
}
};

export const calculateY = (liq: bigint, sqrtPriceAX96: bigint, sqrtPriceBX96: bigint) => {
let sqrtPrice0X96 = sqrtPriceAX96;
let sqrtPrice1X96 = sqrtPriceBX96;
if (sqrtPriceAX96 > sqrtPriceBX96) {
sqrtPrice0X96 = sqrtPriceBX96
sqrtPrice1X96 = sqrtPriceAX96
}
return liq * (sqrtPrice1X96 - sqrtPrice0X96) / Q96
}
export const calculateX = (liq: bigint, sqrtPriceAX96: bigint, sqrtPriceBX96: bigint) => {
let sqrtPrice0X96 = sqrtPriceAX96;
let sqrtPrice1X96 = sqrtPriceBX96;
if (sqrtPriceAX96 > sqrtPriceBX96) {
sqrtPrice0X96 = sqrtPriceBX96
sqrtPrice1X96 = sqrtPriceAX96
}
return liq * Q96 * (sqrtPrice1X96 - sqrtPrice0X96) / sqrtPrice0X96 / sqrtPrice1X96
}


const getTickAtSqrtPrice = (sqrtPriceX96: number) =>
Math.floor(Math.log((sqrtPriceX96 / Number(Q96)) ** 2) / Math.log(1.0001));

Expand Down

0 comments on commit 0701f4f

Please sign in to comment.