Skip to content

Commit

Permalink
symmetry
Browse files Browse the repository at this point in the history
  • Loading branch information
Darya Kaviani authored and Darya Kaviani committed Aug 25, 2022
1 parent 7b0df43 commit ebb115f
Showing 1 changed file with 149 additions and 43 deletions.
192 changes: 149 additions & 43 deletions packages/frontend/src/state/lp/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,13 @@ import { useAtomValue } from 'jotai'
import { addressesAtom, isWethToken0Atom } from '../positions/atoms'
import BigNumber from 'bignumber.js'
import { INDEX_SCALE, OSQUEETH_DECIMALS, WETH_DECIMALS } from '@constants/index'
import { controllerContractAtom, controllerHelperHelperContractAtom, nftManagerContractAtom, quoterContractAtom, squeethPoolContractAtom } from '../contracts/atoms'
import {
controllerContractAtom,
controllerHelperHelperContractAtom,
nftManagerContractAtom,
quoterContractAtom,
squeethPoolContractAtom,
} from '../contracts/atoms'
import useAppCallback from '@hooks/useAppCallback'
import { addressAtom } from '../wallet/atoms'
import { Contract } from 'web3-eth-contract'
Expand Down Expand Up @@ -35,39 +41,37 @@ export const useOpenPositionDeposit = () => {
const index = useAtomValue(indexAtom)
const normFactor = useAtomValue(normFactorAtom)
const getVault = useGetVault()
const getCollateralToLP = useGetCollateralToLP()
const openPositionDeposit = useAppCallback(
async (squeethToMint: BigNumber, lowerTickInput: number, upperTickInput: number, vaultId: number, collatRatio: number, slippage: number, withdrawAmount: number, onTxConfirmed?: () => void) => {
async (
squeethToMint: BigNumber,
lowerTickInput: number,
upperTickInput: number,
vaultId: number,
collatRatio: number,
slippage: number,
withdrawAmount: number,
onTxConfirmed?: () => void,
) => {
const vaultBefore = await getVault(vaultId)
if (!contract || !address || !squeethPoolContract || !vaultBefore || !vaultBefore.shortAmount || !vaultBefore.collateralAmount) return null

const mintWSqueethAmount = fromTokenAmount(squeethToMint, OSQUEETH_DECIMALS)
if (
!contract ||
!address ||
!squeethPoolContract ||
!vaultBefore ||
!vaultBefore.shortAmount ||
!vaultBefore.collateralAmount
)
return null

// Calculate prices from ticks
const mintWSqueethAmount = fromTokenAmount(squeethToMint, OSQUEETH_DECIMALS)
const { tick, tickSpacing } = await getPoolState(squeethPoolContract)
const lowerTick = nearestUsableTick(lowerTickInput, Number(tickSpacing))
const upperTick = nearestUsableTick(upperTickInput, Number(tickSpacing))
const sqrtLowerPrice = isWethToken0 ? new BigNumber(1).div(new BigNumber(TickMath.getSqrtRatioAtTick(Number(lowerTick)).toString()).div(x96))
: new BigNumber(TickMath.getSqrtRatioAtTick(Number(lowerTick)).toString()).div(x96)
const sqrtUpperPrice = isWethToken0 ? new BigNumber(1).div(new BigNumber(TickMath.getSqrtRatioAtTick(Number(upperTick)).toString()).div(x96))
: new BigNumber(TickMath.getSqrtRatioAtTick(Number(upperTick)).toString()).div(x96)
const sqrtSqueethPrice = isWethToken0 ? new BigNumber(1).div(new BigNumber(TickMath.getSqrtRatioAtTick(Number(tick)).toString()).div(x96))
: new BigNumber(TickMath.getSqrtRatioAtTick(Number(tick)).toString()).div(x96)

let collateralToLp
if (sqrtUpperPrice.lt(sqrtSqueethPrice)) {
// All weth position
console.log("LPing an all WETH position is not enabled, but you can rebalance to this position.")
return
} else if (sqrtSqueethPrice.lt(sqrtLowerPrice)) {
// All squeeth position
collateralToLp = new BigNumber(0)
} else {
// Lx = x * (sqrtSqueethPrice * sqrtUpperPrice) / (sqrtUpperPrice - sqrtSqueethPrice)
// y = Lx * (sqrtSqueethPrice - sqrtLowerPrice)
const liquidity = mintWSqueethAmount.times(sqrtSqueethPrice.times(sqrtUpperPrice)).div(sqrtUpperPrice.minus(sqrtSqueethPrice))
collateralToLp = liquidity.times(sqrtSqueethPrice.minus(sqrtLowerPrice))
}


const collateralToLp = await getCollateralToLP(mintWSqueethAmount, lowerTick, upperTick, tick)
if (!collateralToLp) return

const amount0New = isWethToken0 ? collateralToLp : mintWSqueethAmount
const amount1New = isWethToken0 ? mintWSqueethAmount : collateralToLp
const amount0Min = amount0New.times(new BigNumber(1).minus(slippage)).toFixed(0)
Expand All @@ -77,13 +81,18 @@ export const useOpenPositionDeposit = () => {
const ethIndexPrice = toTokenAmount(index, 18).sqrt()
const vaultShortAmt = fromTokenAmount(vaultBefore.shortAmount, OSQUEETH_DECIMALS)
const vaultCollateralAmt = fromTokenAmount(vaultBefore.collateralAmount, WETH_DECIMALS)

// Calculate collateralToMint
const oSQTHInETH = mintWSqueethAmount.times(ethIndexPrice.div(INDEX_SCALE)).times(normFactor)
const collateralToMint = (new BigNumber(collatRatio).times((vaultShortAmt.plus(mintWSqueethAmount)).times(normFactor).times(ethIndexPrice).div(INDEX_SCALE)))
.minus((vaultCollateralAmt.minus(collateralToWithdraw).plus(collateralToLp).plus(oSQTHInETH)))
const flashLoanAmount = (new BigNumber(COLLAT_RATIO_FLASHLOAN + FLASHLOAN_BUFFER).times(vaultShortAmt.plus(mintWSqueethAmount)).times(normFactor).times(ethIndexPrice).div(INDEX_SCALE))
.minus(vaultCollateralAmt.plus(collateralToMint).minus(collateralToWithdraw))
const collateralToMint = new BigNumber(collatRatio)
.times(vaultShortAmt.plus(mintWSqueethAmount).times(normFactor).times(ethIndexPrice).div(INDEX_SCALE))
.minus(vaultCollateralAmt.minus(collateralToWithdraw).plus(collateralToLp).plus(oSQTHInETH))
const flashLoanAmount = new BigNumber(COLLAT_RATIO_FLASHLOAN + FLASHLOAN_BUFFER)
.times(vaultShortAmt.plus(mintWSqueethAmount))
.times(normFactor)
.times(ethIndexPrice)
.div(INDEX_SCALE)
.minus(vaultCollateralAmt.plus(collateralToMint).minus(collateralToWithdraw))
const collateralToMintPos = BigNumber.max(collateralToMint, 0)
const flashLoanAmountPos = BigNumber.max(flashLoanAmount, 0)

Expand All @@ -109,7 +118,18 @@ export const useOpenPositionDeposit = () => {
onTxConfirmed,
)
},
[address, squeethPool, contract, handleTransaction, getDebtAmount, squeethPoolContract, isWethToken0, index, normFactor, getVault],
[
address,
squeethPool,
contract,
handleTransaction,
getDebtAmount,
squeethPoolContract,
isWethToken0,
index,
normFactor,
getVault,
],
)

return openPositionDeposit
Expand All @@ -124,7 +144,20 @@ export const useGetPosition = () => {
async (uniTokenId: number) => {
if (!contract) return null
const position = await contract.methods.positions(uniTokenId).call()
const { nonce, operator, token0, token1, fee, tickLower, tickUpper, liquidity, feeGrowthInside0LastX128, feeGrowthInside1LastX128, tokensOwed0, tokensOwed1 } = position
const {
nonce,
operator,
token0,
token1,
fee,
tickLower,
tickUpper,
liquidity,
feeGrowthInside0LastX128,
feeGrowthInside1LastX128,
tokensOwed0,
tokensOwed1,
} = position
return {
nonce,
operator,
Expand All @@ -137,7 +170,7 @@ export const useGetPosition = () => {
feeGrowthInside0LastX128,
feeGrowthInside1LastX128,
tokensOwed0,
tokensOwed1
tokensOwed1,
}
},
[contract],
Expand All @@ -146,6 +179,79 @@ export const useGetPosition = () => {
return getPosition
}

export const useGetLiquidity = () => {
const isWethToken0 = useAtomValue(isWethToken0Atom)

const getLiquidity = useCallback(
async (
squeethAmount: BigNumber,
sqrtLowerPrice: BigNumber,
sqrtUpperPrice: BigNumber,
sqrtSqueethPrice: BigNumber,
) => {
if (isWethToken0) {
// Ly = y / (sqrtSqueethPrice - sqrtLowerPrice)
return squeethAmount.div(sqrtSqueethPrice.minus(sqrtLowerPrice))
} else {
// Lx = x * (sqrtSqueethPrice * sqrtUpperPrice) / (sqrtUpperPrice - sqrtSqueethPrice)
return squeethAmount.times(sqrtSqueethPrice.times(sqrtUpperPrice)).div(sqrtUpperPrice.minus(sqrtSqueethPrice))
}
},
[isWethToken0],
)

return getLiquidity
}

export const useGetCollateralToLP = () => {
const isWethToken0 = useAtomValue(isWethToken0Atom)
const getLiquidity = useGetLiquidity()
const getTickPrices = useGetTickPrices()

const getCollateralToLP = useCallback(
async (squeethAmount: BigNumber, lowerTick: Number, upperTick: Number, tick: number) => {
const { sqrtLowerPrice, sqrtUpperPrice, sqrtSqueethPrice } = await getTickPrices(lowerTick, upperTick, tick)

if (
(sqrtUpperPrice.lt(sqrtSqueethPrice) && !isWethToken0) ||
(sqrtLowerPrice.gt(sqrtSqueethPrice) && isWethToken0)
) {
// All weth position
console.log('LPing an all WETH position is not enabled, but you can rebalance to this position.')
return
} else if (
(sqrtLowerPrice.gt(sqrtSqueethPrice) && !isWethToken0) ||
(sqrtUpperPrice.lt(sqrtSqueethPrice) && isWethToken0)
) {
// All squeeth position
return new BigNumber(0)
} else {
// isWethToken0 -> x = Ly * (sqrtUpperPrice - sqrtSqueethPrice)/(sqrtSqueethPrice * sqrtUpperPrice)
// !isWethToken0 -> y = Lx * (sqrtSqueethPrice - sqrtLowerPrice)

const liquidity = await getLiquidity(squeethAmount, sqrtLowerPrice, sqrtUpperPrice, sqrtSqueethPrice)
return isWethToken0
? liquidity.times(sqrtUpperPrice.minus(sqrtSqueethPrice)).div(sqrtSqueethPrice.times(sqrtUpperPrice))
: liquidity.times(sqrtSqueethPrice.minus(sqrtLowerPrice))
}
},
[isWethToken0, getLiquidity],
)

return getCollateralToLP
}

export const useGetTickPrices = () => {
const getTickPrices = useCallback(async (lowerTick: Number, upperTick: Number, currentTick: number) => {
const sqrtLowerPrice = new BigNumber(TickMath.getSqrtRatioAtTick(Number(lowerTick)).toString()).div(x96)
const sqrtUpperPrice = new BigNumber(TickMath.getSqrtRatioAtTick(Number(upperTick)).toString()).div(x96)
const sqrtSqueethPrice = new BigNumber(TickMath.getSqrtRatioAtTick(Number(currentTick)).toString()).div(x96)
return { sqrtLowerPrice, sqrtUpperPrice, sqrtSqueethPrice }
}, [])

return getTickPrices
}

export const useGetDecreaseLiquidity = () => {
const contract = useAtomValue(nftManagerContractAtom)

Expand All @@ -172,7 +278,7 @@ export const useGetDecreaseLiquidity = () => {

export const useGetExactIn = () => {
const contract = useAtomValue(quoterContractAtom)
const {weth, oSqueeth} = useAtomValue(addressesAtom)
const { weth, oSqueeth } = useAtomValue(addressesAtom)

const getExactIn = useCallback(
async (amount: BigNumber, squeethIn: boolean) => {
Expand All @@ -183,7 +289,7 @@ export const useGetExactIn = () => {
tokenOut: squeethIn ? weth : oSqueeth,
amountIn: amount.toFixed(0),
fee: POOL_FEE,
sqrtPriceLimitX96: 0
sqrtPriceLimitX96: 0,
}

const quote = await contract.methods.quoteExactInputSingle(QuoteExactInputSingleParams).call()
Expand All @@ -197,7 +303,7 @@ export const useGetExactIn = () => {

export const useGetExactOut = () => {
const contract = useAtomValue(quoterContractAtom)
const {weth, oSqueeth} = useAtomValue(addressesAtom)
const { weth, oSqueeth } = useAtomValue(addressesAtom)

const getExactOut = useCallback(
async (amount: BigNumber, squeethOut: boolean) => {
Expand All @@ -208,7 +314,7 @@ export const useGetExactOut = () => {
tokenOut: squeethOut ? oSqueeth : weth,
amount: amount.toFixed(0),
fee: POOL_FEE,
sqrtPriceLimitX96: 0
sqrtPriceLimitX96: 0,
}

const quote = await contract.methods.quoteExactOutputSingle(QuoteExactOutputSingleParams).call()
Expand All @@ -224,7 +330,7 @@ async function getPoolState(poolContract: Contract) {
const [slot, liquidity, tickSpacing] = await Promise.all([
poolContract?.methods.slot0().call(),
poolContract?.methods.liquidity().call(),
poolContract.methods.tickSpacing().call()
poolContract.methods.tickSpacing().call(),
])

const PoolState = {
Expand All @@ -236,8 +342,8 @@ async function getPoolState(poolContract: Contract) {
observationCardinalityNext: slot[4],
feeProtocol: slot[5],
unlocked: slot[6],
tickSpacing
tickSpacing,
}

return PoolState
}
}

0 comments on commit ebb115f

Please sign in to comment.