// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.7.6; import { Tick } from "./Tick.sol"; import { PerpMath } from "./PerpMath.sol"; import { OpenOrder } from "./OpenOrder.sol"; import { PerpSafeCast } from "./PerpSafeCast.sol"; import { PerpFixedPoint96 } from "./PerpFixedPoint96.sol"; import { TickMath } from "@uniswap/v3-core/contracts/libraries/TickMath.sol"; import { LiquidityAmounts } from "@uniswap/v3-periphery/contracts/libraries/LiquidityAmounts.sol"; import { SignedSafeMathUpgradeable } from "@openzeppelin/contracts-upgradeable/math/SignedSafeMathUpgradeable.sol"; library Funding { using PerpSafeCast for uint256; using PerpSafeCast for uint128; using SignedSafeMathUpgradeable for int256; // // STRUCT // /// @dev tw: time-weighted /// @param twPremiumX96 overflow inspection (as twPremiumX96 > twPremiumDivBySqrtPriceX96): // max = 2 ^ (255 - 96) = 2 ^ 159 = 7.307508187E47 // assume premium = 10000, time = 10 year = 60 * 60 * 24 * 365 * 10 -> twPremium = 3.1536E12 struct Growth { int256 twPremiumX96; int256 twPremiumDivBySqrtPriceX96; } // // CONSTANT // /// @dev block-based funding is calculated as: premium * timeFraction / 1 day, for 1 day as the default period int256 internal constant _DEFAULT_FUNDING_PERIOD = 1 days; // // INTERNAL PURE // function calcPendingFundingPaymentWithLiquidityCoefficient( int256 baseBalance, int256 twPremiumGrowthGlobalX96, Growth memory fundingGrowthGlobal, int256 liquidityCoefficientInFundingPayment ) internal pure returns (int256) { int256 balanceCoefficientInFundingPayment = PerpMath.mulDiv( baseBalance, fundingGrowthGlobal.twPremiumX96.sub(twPremiumGrowthGlobalX96), uint256(PerpFixedPoint96._IQ96) ); return liquidityCoefficientInFundingPayment.add(balanceCoefficientInFundingPayment).div(_DEFAULT_FUNDING_PERIOD); } /// @dev the funding payment of an order/liquidity is composed of /// 1. funding accrued inside the range 2. funding accrued below the range /// there is no funding when the price goes above the range, as liquidity is all swapped into quoteToken /// @return liquidityCoefficientInFundingPayment the funding payment of an order/liquidity function calcLiquidityCoefficientInFundingPaymentByOrder( OpenOrder.Info memory order, Tick.FundingGrowthRangeInfo memory fundingGrowthRangeInfo ) internal pure returns (int256) { uint160 sqrtPriceX96AtUpperTick = TickMath.getSqrtRatioAtTick(order.upperTick); // base amount below the range uint256 baseAmountBelow = LiquidityAmounts.getAmount0ForLiquidity( TickMath.getSqrtRatioAtTick(order.lowerTick), sqrtPriceX96AtUpperTick, order.liquidity ); // funding below the range int256 fundingBelowX96 = baseAmountBelow.toInt256().mul( fundingGrowthRangeInfo.twPremiumGrowthBelowX96.sub(order.lastTwPremiumGrowthBelowX96) ); // funding inside the range = // liquidity * (ΔtwPremiumDivBySqrtPriceGrowthInsideX96 - ΔtwPremiumGrowthInsideX96 / sqrtPriceAtUpperTick) int256 fundingInsideX96 = order.liquidity.toInt256().mul( // ΔtwPremiumDivBySqrtPriceGrowthInsideX96 fundingGrowthRangeInfo .twPremiumDivBySqrtPriceGrowthInsideX96 .sub(order.lastTwPremiumDivBySqrtPriceGrowthInsideX96) .sub( // ΔtwPremiumGrowthInsideX96 PerpMath.mulDiv( fundingGrowthRangeInfo.twPremiumGrowthInsideX96.sub(order.lastTwPremiumGrowthInsideX96), PerpFixedPoint96._IQ96, sqrtPriceX96AtUpperTick ) ) ); return fundingBelowX96.add(fundingInsideX96).div(PerpFixedPoint96._IQ96); } }