import { BigNumber } from "ethers" ; import { UniswapV2Pair , SetToken , StakingRewards , StandardTokenMock , WETH9 , UniswapV2Router02 } from "../contracts" ; import { ZERO } from "../constants" ; import { ether , preciseMul } from "../index" ; import { preciseDiv } from "./mathUtils" ; import { Address } from "../types" ; const MINIMUM_LIQUIDITY = BigNumber . from ( 1000 ) ; export const calculateLPTokensIssued = async ( pool , amountOne , amountTwo ) : Promise < BigNumber > => { const reserves = await pool . getReserves ( ) ; const totalSupply = await pool . totalSupply ( ) ; let liquidity ; if ( totalSupply == ZERO ) { liquidity = sqrt ( amountOne . mul ( amountTwo ) ) . sub ( MINIMUM_LIQUIDITY ) ; } else { liquidity = min ( amountOne . mul ( totalSupply ) . div ( reserves . _reserve0 ) , amountTwo . mul ( totalSupply ) . div ( reserves . _reserve1 ) ) ; } return liquidity ; } ; export const calculateEngageQuantities = async ( setToken , assetOne , assetTwo , lpToken , stakingRewards , reservePercentage , extraAssetOne = ZERO , extraAssetTwo = ZERO ) : Promise < [ BigNumber , BigNumber ] > => { const [ reserveOne , reserveTwo ] = await calculateTokensInReserve ( setToken , assetOne , assetTwo , lpToken , stakingRewards ) ; const balanceOnTokenAssetOne = ( await assetOne . balanceOf ( setToken . address ) ) . add ( extraAssetOne ) ; const balanceOnTokenAssetTwo = ( await assetTwo . balanceOf ( setToken . address ) ) . add ( extraAssetTwo ) ; return [ preciseMul ( reserveOne , reservePercentage ) . sub ( preciseMul ( balanceOnTokenAssetOne , ether ( 1 ) . sub ( reservePercentage ) ) ) , preciseMul ( reserveTwo , reservePercentage ) . sub ( preciseMul ( balanceOnTokenAssetTwo , ether ( 1 ) . sub ( reservePercentage ) ) ) , ] ; } ; export const calculateRebalanceFlows = async ( setToken , router , sellTokenQuantity , assetOne , assetTwo , assetOneToTwoPrice , extraAssetOne = ZERO , extraAssetTwo = ZERO ) : Promise < BigNumber [ ] > => { const [ quantityToSell , assetToSell , assetToBuy ] = await calculateRebalanceQuantity ( sellTokenQuantity , setToken , assetOne , assetTwo , assetOneToTwoPrice , extraAssetOne , extraAssetTwo ) ; return await router . getAmountsOut ( quantityToSell , [ assetToSell , assetToBuy ] ) ; } ; export const calculateRebalanceQuantity = async ( sellTokenQuantity , setToken , assetOne , assetTwo , assetOneToTwoPrice , extraAssetOne = ZERO , extraAssetTwo = ZERO ) : Promise < [ BigNumber , Address , Address ] > => { const balanceAssetOne = ( await assetOne . balanceOf ( setToken . address ) ) . add ( extraAssetOne ) ; const balanceAssetTwo = ( await assetTwo . balanceOf ( setToken . address ) ) . add ( extraAssetTwo ) ; const valueAssetTwoDenomOne = preciseDiv ( balanceAssetTwo , assetOneToTwoPrice ) ; let quantityToSell ; let assetToSell ; let assetToBuy ; if ( balanceAssetOne . gt ( valueAssetTwoDenomOne ) ) { quantityToSell = balanceAssetOne . sub ( valueAssetTwoDenomOne ) . div ( 2 ) ; assetToSell = assetOne . address ; assetToBuy = assetTwo . address ; } else { quantityToSell = preciseMul ( valueAssetTwoDenomOne . sub ( balanceAssetOne ) . div ( 2 ) , assetOneToTwoPrice ) ; assetToSell = assetTwo . address ; assetToBuy = assetOne . address ; } if ( sellTokenQuantity > ZERO ) { quantityToSell = sellTokenQuantity ; } return [ quantityToSell , assetToSell , assetToBuy ] ; } ; export const calculateTokensInReserve = async ( setToken , assetOne , assetTwo , lpToken , stakingRewards ) : Promise < [ BigNumber , BigNumber ] > => { const [ reserveOne , reserveTwo ] = await getReservesSafe ( assetOne . address , assetTwo . address , lpToken ) ; const totalSupply = await lpToken . totalSupply ( ) ; const lpTokenBalance = await stakingRewards . balanceOf ( setToken . address ) ; return [ preciseMul ( preciseDiv ( reserveOne , totalSupply ) , lpTokenBalance ) , preciseMul ( preciseDiv ( reserveTwo , totalSupply ) , lpTokenBalance ) , ] ; } ; export const getReservesSafe = async ( assetOne , assetTwo , lpToken ) : Promise < [ BigNumber , BigNumber ] > => { const firstAsset = assetOne < assetTwo ? assetOne : assetTwo ; const reserves = await lpToken . getReserves ( ) ; return assetOne == firstAsset ? [ reserves . _reserve0 , reserves . _reserve1 ] : [ reserves . _reserve1 , reserves . _reserve0 ] ; } ; const sqrt = ( value ) : BigNumber => { let z = value ; if ( value > BigNumber . from ( 3 ) ) { let x = value . div ( 2 ) . add ( 1 ) ; while ( x < z ) { z = x ; x = value . div ( x ) . add ( x ) . div ( 2 ) ; } } else if ( value != ZERO ) { z = BigNumber . from ( 1 ) ; } return z ; } ; export const min = ( valueOne , valueTwo ) : BigNumber => { return valueOne < valueTwo ? valueOne : valueTwo ; } ;