mirror of
https://github.com/luxfi/uma.git
synced 2026-10-30 15:14:44 +00:00
627 lines
27 KiB
Solidity
627 lines
27 KiB
Solidity
pragma solidity ^0.8.0;
|
||
|
||
import "@uniswap/lib/contracts/libraries/TransferHelper.sol";
|
||
|
||
import "@uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol";
|
||
|
||
import "@uniswap/v3-periphery/contracts/interfaces/ISwapRouter.sol";
|
||
|
||
import "@uniswap/v3-core/contracts/libraries/LowGasSafeMath.sol";
|
||
import "@uniswap/v3-core/contracts/libraries/LiquidityMath.sol";
|
||
import "@uniswap/v3-core/contracts/libraries/BitMath.sol";
|
||
import "@uniswap/v3-core/contracts/libraries/UnsafeMath.sol";
|
||
import "@uniswap/v3-core/contracts/libraries/SafeCast.sol";
|
||
|
||
/**
|
||
* @title UniswapV3Broker
|
||
* @notice Trading contract used to arb uniswapV3 pairs to a desired "true" price. Intended use is to arb UMA perpetual
|
||
* synthetics that trade off peg. This implementation can ber used in conjunction with a DSProxy contract to atomically
|
||
* swap and move a uniswap market.
|
||
*/
|
||
|
||
contract UniswapV3Broker {
|
||
using SafeCast for uint256;
|
||
using LowGasSafeMath for uint256;
|
||
using LowGasSafeMath for int256;
|
||
|
||
struct SwapState {
|
||
uint160 sqrtPriceX96;
|
||
int24 tick;
|
||
uint128 liquidity;
|
||
uint256 requiredInputAmount;
|
||
}
|
||
|
||
struct StepComputations {
|
||
uint160 sqrtPriceStartX96;
|
||
int24 tickNext;
|
||
bool initialized;
|
||
uint160 sqrtPriceNextX96;
|
||
}
|
||
|
||
/**
|
||
* @notice Swaps an amount of either pool tokens such that the trade results in the uniswap pair's price equaling a
|
||
* desired price.
|
||
* @dev The desired price is represented as sqrtRatioTargetX96. This is the Price^(1/2) * 96^2.
|
||
* @dev The caller must approve this contract to spend whichever token is intended to be swapped.
|
||
* @param tradingAsEOA bool to indicate if the UniswapBroker is being called by a DSProxy or an EOA.
|
||
* @param uniswapPool address of the pool to uniswap v3 trade against.
|
||
* @param uniswapRouter address of the uniswap v3 router to route the trade.
|
||
* @param sqrtRatioTargetX96 target, encoded price.
|
||
* @param recipient address that the output tokens should be sent to.
|
||
* @param deadline to limit when the trade can execute. If the tx is mined after this timestamp then revert.
|
||
*/
|
||
function swapToPrice(
|
||
bool tradingAsEOA,
|
||
address uniswapPool,
|
||
address uniswapRouter,
|
||
uint160 sqrtRatioTargetX96,
|
||
address recipient,
|
||
uint256 deadline
|
||
) external returns (uint256) {
|
||
// Create an instance of the pool and load in the current token price and the active tick.
|
||
IUniswapV3Pool pool = IUniswapV3Pool(uniswapPool);
|
||
(uint160 sqrtPriceX96, int24 tick, , , , , ) = pool.slot0();
|
||
|
||
// Work out the direction we need to trade. If the current price is more than the target price then we are
|
||
// trading token0 for token1. Else, we are trading token1 for token0.
|
||
bool zeroForOne = sqrtPriceX96 >= sqrtRatioTargetX96;
|
||
|
||
// Build a state object to store this information which can be re-used during.
|
||
SwapState memory state =
|
||
SwapState({ sqrtPriceX96: sqrtPriceX96, tick: tick, liquidity: pool.liquidity(), requiredInputAmount: 0 });
|
||
|
||
// Iterate in a while loop that breaks when we hit the target price.
|
||
while (true) {
|
||
// Compute the next initialized tick. We only need to traverse initialized ticks as uninitialized ticks
|
||
// have the same liquidity as the previous tick.
|
||
StepComputations memory step;
|
||
step.sqrtPriceStartX96 = state.sqrtPriceX96;
|
||
(step.tickNext, step.initialized) = TickBitmap.nextInitializedTickWithinOneWord(
|
||
pool,
|
||
state.tick,
|
||
pool.tickSpacing(),
|
||
zeroForOne
|
||
);
|
||
|
||
// Double check we are not over or underflow the ticks.
|
||
if (step.tickNext < TickMath.MIN_TICK) step.tickNext = TickMath.MIN_TICK;
|
||
else if (step.tickNext > TickMath.MAX_TICK) step.tickNext = TickMath.MAX_TICK;
|
||
|
||
// Find the price at the next tick. Between the current state.sqrtPriceX96 and the nextTickPriceX96 we
|
||
// can find how much of the sold token is needed to sufficiently move the market over the interval.
|
||
|
||
uint160 nextTickPriceX96 = TickMath.getSqrtRatioAtTick(step.tickNext);
|
||
uint256 inputAmountForStep;
|
||
|
||
// If zeroForOne is true, then we are moving the price UP. In this case we need to ensure that if the next
|
||
// tick price is more than the target price, we set the set the the next step price to the target price. This
|
||
// ensures that the price does not undershoot when the next tick is the last tick. Else, traverse the whole tick.
|
||
if (zeroForOne) {
|
||
step.sqrtPriceNextX96 = nextTickPriceX96 > sqrtRatioTargetX96 ? sqrtRatioTargetX96 : nextTickPriceX96;
|
||
inputAmountForStep = SqrtPriceMath.getAmount0Delta( // As we are trading token0 for token1, calculate the token0 input.
|
||
step.sqrtPriceStartX96,
|
||
step.sqrtPriceNextX96,
|
||
state.liquidity,
|
||
false
|
||
);
|
||
// Else, if zeroForOne is false, then we are moving the price DOWN. In this case we need to ensure that we
|
||
// don't overshoot the price on the next step.
|
||
} else {
|
||
step.sqrtPriceNextX96 = nextTickPriceX96 > sqrtRatioTargetX96 ? nextTickPriceX96 : sqrtRatioTargetX96;
|
||
inputAmountForStep = SqrtPriceMath.getAmount1Delta( // As we are trading token1 for token0, calculate the token1 input.
|
||
step.sqrtPriceStartX96,
|
||
step.sqrtPriceNextX96,
|
||
state.liquidity,
|
||
false
|
||
);
|
||
}
|
||
|
||
// Add amount for this step to the total required input.
|
||
state.requiredInputAmount = state.requiredInputAmount.add(inputAmountForStep);
|
||
|
||
// If we have hit(or exceeded) our target price in the associate direction, then stop.
|
||
if (zeroForOne && state.sqrtPriceX96 <= sqrtRatioTargetX96) break;
|
||
if (!zeroForOne && state.sqrtPriceX96 >= sqrtRatioTargetX96) break;
|
||
|
||
// If the next step is is initialized then we will need to update the liquidity for the current step.
|
||
if (step.initialized) {
|
||
// Fetch the net liquidity. this could be positive or negative depending on if a LP is turning on or off at this price.
|
||
(, int128 liquidityNet, , , , , , ) = pool.ticks(step.tickNext);
|
||
state.liquidity = LiquidityMath.addDelta(state.liquidity, zeroForOne ? liquidityNet : -liquidityNet);
|
||
}
|
||
|
||
// Finally, set the state price to the next price for the next iteration.
|
||
state.sqrtPriceX96 = step.sqrtPriceNextX96;
|
||
state.tick = step.tickNext;
|
||
}
|
||
|
||
// Based on the direction we are moving, set the input and output tokens.
|
||
(address tokenIn, address tokenOut) =
|
||
zeroForOne ? (pool.token0(), pool.token1()) : (pool.token1(), pool.token0());
|
||
|
||
// If trading from an EOA pull tokens into this contract. If trading from a DSProxy this is redundant.
|
||
if (tradingAsEOA)
|
||
TransferHelper.safeTransferFrom(tokenIn, msg.sender, address(this), state.requiredInputAmount);
|
||
|
||
// Approve the router and execute the swap.
|
||
TransferHelper.safeApprove(tokenIn, address(uniswapRouter), state.requiredInputAmount);
|
||
ISwapRouter(uniswapRouter).exactInputSingle(
|
||
ISwapRouter.ExactInputSingleParams({
|
||
tokenIn: tokenIn,
|
||
tokenOut: tokenOut,
|
||
fee: pool.fee(),
|
||
recipient: recipient,
|
||
deadline: deadline,
|
||
amountIn: state.requiredInputAmount,
|
||
amountOutMinimum: 0,
|
||
sqrtPriceLimitX96: sqrtRatioTargetX96
|
||
})
|
||
);
|
||
|
||
return state.requiredInputAmount;
|
||
}
|
||
}
|
||
|
||
// The code below are taken almost verbatim from https://github.com/Uniswap/uniswap-v3-core/blob/main/contracts/libraries/TickBitmap.sol.
|
||
// They was modified slightly to enable the them to be called on an external pool by passing in a pool address and
|
||
// to accommodate solidity 0.8.
|
||
|
||
library TickBitmap {
|
||
function nextInitializedTickWithinOneWord(
|
||
IUniswapV3Pool pool,
|
||
int24 tick,
|
||
int24 tickSpacing,
|
||
bool lte
|
||
) internal view returns (int24 next, bool initialized) {
|
||
int24 compressed = tick / tickSpacing;
|
||
if (tick < 0 && tick % tickSpacing != 0) compressed--; // round towards negative infinity
|
||
|
||
if (lte) {
|
||
(int16 wordPos, uint8 bitPos) = position(compressed);
|
||
// all the 1s at or to the right of the current bitPos
|
||
uint256 mask = (1 << bitPos) - 1 + (1 << bitPos);
|
||
uint256 masked = pool.tickBitmap(wordPos) & mask;
|
||
|
||
// if there are no initialized ticks to the right of or at the current tick, return rightmost in the word
|
||
initialized = masked != 0;
|
||
// overflow/underflow is possible, but prevented externally by limiting both tickSpacing and tick
|
||
next = initialized
|
||
? (compressed - int24(int24(uint24(bitPos)) - int24(uint24(BitMath.mostSignificantBit(masked))))) *
|
||
tickSpacing
|
||
: (compressed - int24(uint24(bitPos))) * tickSpacing;
|
||
} else {
|
||
// start from the word of the next tick, since the current tick state doesn't matter
|
||
(int16 wordPos, uint8 bitPos) = position(compressed + 1);
|
||
// all the 1s at or to the left of the bitPos
|
||
uint256 mask = ~((1 << bitPos) - 1);
|
||
uint256 masked = pool.tickBitmap(wordPos) & mask;
|
||
|
||
// if there are no initialized ticks to the left of the current tick, return leftmost in the word
|
||
initialized = masked != 0;
|
||
// overflow/underflow is possible, but prevented externally by limiting both tickSpacing and tick
|
||
next = initialized
|
||
? (compressed + 1 + int24(BitMath.leastSignificantBit(masked) - uint24(bitPos))) * tickSpacing
|
||
: (compressed + 1 + int24(type(uint8).max - uint24(bitPos))) * tickSpacing;
|
||
}
|
||
}
|
||
|
||
function position(int24 tick) private pure returns (int16 wordPos, uint8 bitPos) {
|
||
wordPos = int16(tick >> 8);
|
||
bitPos = uint8(int8(tick % 256));
|
||
}
|
||
|
||
function flipTick(
|
||
mapping(int16 => uint256) storage self,
|
||
int24 tick,
|
||
int24 tickSpacing
|
||
) internal {
|
||
require(tick % tickSpacing == 0); // ensure that the tick is spaced
|
||
(int16 wordPos, uint8 bitPos) = position(tick / tickSpacing);
|
||
uint256 mask = 1 << bitPos;
|
||
self[wordPos] ^= mask;
|
||
}
|
||
}
|
||
|
||
// Taken from https://github.com/Uniswap/uniswap-v3-core/blob/main/contracts/libraries/TickMath.sol and update
|
||
// to work with solidity 0.8.
|
||
library TickMath {
|
||
/// @dev The minimum tick that may be passed to #getSqrtRatioAtTick computed from log base 1.0001 of 2**-128
|
||
int24 internal constant MIN_TICK = -887272;
|
||
/// @dev The maximum tick that may be passed to #getSqrtRatioAtTick computed from log base 1.0001 of 2**128
|
||
int24 internal constant MAX_TICK = -MIN_TICK;
|
||
|
||
/// @dev The minimum value that can be returned from #getSqrtRatioAtTick. Equivalent to getSqrtRatioAtTick(MIN_TICK)
|
||
uint160 internal constant MIN_SQRT_RATIO = 4295128739;
|
||
/// @dev The maximum value that can be returned from #getSqrtRatioAtTick. Equivalent to getSqrtRatioAtTick(MAX_TICK)
|
||
uint160 internal constant MAX_SQRT_RATIO = 1461446703485210103287273052203988822378723970342;
|
||
|
||
/// @notice Calculates sqrt(1.0001^tick) * 2^96
|
||
/// @dev Throws if |tick| > max tick
|
||
/// @param tick The input tick for the above formula
|
||
/// @return sqrtPriceX96 A Fixed point Q64.96 number representing the sqrt of the ratio of the two assets (token1/token0)
|
||
/// at the given tick
|
||
function getSqrtRatioAtTick(int24 tick) internal pure returns (uint160 sqrtPriceX96) {
|
||
uint256 absTick = tick < 0 ? uint256(-int256(tick)) : uint256(int256(tick));
|
||
require(absTick <= uint256(int256(MAX_TICK)), "T");
|
||
|
||
uint256 ratio = absTick & 0x1 != 0 ? 0xfffcb933bd6fad37aa2d162d1a594001 : 0x100000000000000000000000000000000;
|
||
if (absTick & 0x2 != 0) ratio = (ratio * 0xfff97272373d413259a46990580e213a) >> 128;
|
||
if (absTick & 0x4 != 0) ratio = (ratio * 0xfff2e50f5f656932ef12357cf3c7fdcc) >> 128;
|
||
if (absTick & 0x8 != 0) ratio = (ratio * 0xffe5caca7e10e4e61c3624eaa0941cd0) >> 128;
|
||
if (absTick & 0x10 != 0) ratio = (ratio * 0xffcb9843d60f6159c9db58835c926644) >> 128;
|
||
if (absTick & 0x20 != 0) ratio = (ratio * 0xff973b41fa98c081472e6896dfb254c0) >> 128;
|
||
if (absTick & 0x40 != 0) ratio = (ratio * 0xff2ea16466c96a3843ec78b326b52861) >> 128;
|
||
if (absTick & 0x80 != 0) ratio = (ratio * 0xfe5dee046a99a2a811c461f1969c3053) >> 128;
|
||
if (absTick & 0x100 != 0) ratio = (ratio * 0xfcbe86c7900a88aedcffc83b479aa3a4) >> 128;
|
||
if (absTick & 0x200 != 0) ratio = (ratio * 0xf987a7253ac413176f2b074cf7815e54) >> 128;
|
||
if (absTick & 0x400 != 0) ratio = (ratio * 0xf3392b0822b70005940c7a398e4b70f3) >> 128;
|
||
if (absTick & 0x800 != 0) ratio = (ratio * 0xe7159475a2c29b7443b29c7fa6e889d9) >> 128;
|
||
if (absTick & 0x1000 != 0) ratio = (ratio * 0xd097f3bdfd2022b8845ad8f792aa5825) >> 128;
|
||
if (absTick & 0x2000 != 0) ratio = (ratio * 0xa9f746462d870fdf8a65dc1f90e061e5) >> 128;
|
||
if (absTick & 0x4000 != 0) ratio = (ratio * 0x70d869a156d2a1b890bb3df62baf32f7) >> 128;
|
||
if (absTick & 0x8000 != 0) ratio = (ratio * 0x31be135f97d08fd981231505542fcfa6) >> 128;
|
||
if (absTick & 0x10000 != 0) ratio = (ratio * 0x9aa508b5b7a84e1c677de54f3e99bc9) >> 128;
|
||
if (absTick & 0x20000 != 0) ratio = (ratio * 0x5d6af8dedb81196699c329225ee604) >> 128;
|
||
if (absTick & 0x40000 != 0) ratio = (ratio * 0x2216e584f5fa1ea926041bedfe98) >> 128;
|
||
if (absTick & 0x80000 != 0) ratio = (ratio * 0x48a170391f7dc42444e8fa2) >> 128;
|
||
|
||
if (tick > 0) ratio = type(uint256).max / ratio;
|
||
|
||
// this divides by 1<<32 rounding up to go from a Q128.128 to a Q128.96.
|
||
// we then downcast because we know the result always fits within 160 bits due to our tick input constraint
|
||
// we round up in the division so getTickAtSqrtRatio of the output price is always consistent
|
||
sqrtPriceX96 = uint160((ratio >> 32) + (ratio % (1 << 32) == 0 ? 0 : 1));
|
||
}
|
||
|
||
function getTickAtSqrtRatio(uint160 sqrtPriceX96) internal pure returns (int24 tick) {
|
||
// second inequality must be < because the price can never reach the price at the max tick
|
||
require(sqrtPriceX96 >= MIN_SQRT_RATIO && sqrtPriceX96 < MAX_SQRT_RATIO, "R");
|
||
uint256 ratio = uint256(sqrtPriceX96) << 32;
|
||
|
||
uint256 r = ratio;
|
||
uint256 msb = 0;
|
||
|
||
assembly {
|
||
let f := shl(7, gt(r, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF))
|
||
msb := or(msb, f)
|
||
r := shr(f, r)
|
||
}
|
||
assembly {
|
||
let f := shl(6, gt(r, 0xFFFFFFFFFFFFFFFF))
|
||
msb := or(msb, f)
|
||
r := shr(f, r)
|
||
}
|
||
assembly {
|
||
let f := shl(5, gt(r, 0xFFFFFFFF))
|
||
msb := or(msb, f)
|
||
r := shr(f, r)
|
||
}
|
||
assembly {
|
||
let f := shl(4, gt(r, 0xFFFF))
|
||
msb := or(msb, f)
|
||
r := shr(f, r)
|
||
}
|
||
assembly {
|
||
let f := shl(3, gt(r, 0xFF))
|
||
msb := or(msb, f)
|
||
r := shr(f, r)
|
||
}
|
||
assembly {
|
||
let f := shl(2, gt(r, 0xF))
|
||
msb := or(msb, f)
|
||
r := shr(f, r)
|
||
}
|
||
assembly {
|
||
let f := shl(1, gt(r, 0x3))
|
||
msb := or(msb, f)
|
||
r := shr(f, r)
|
||
}
|
||
assembly {
|
||
let f := gt(r, 0x1)
|
||
msb := or(msb, f)
|
||
}
|
||
|
||
if (msb >= 128) r = ratio >> (msb - 127);
|
||
else r = ratio << (127 - msb);
|
||
|
||
int256 log_2 = (int256(msb) - 128) << 64;
|
||
|
||
assembly {
|
||
r := shr(127, mul(r, r))
|
||
let f := shr(128, r)
|
||
log_2 := or(log_2, shl(63, f))
|
||
r := shr(f, r)
|
||
}
|
||
assembly {
|
||
r := shr(127, mul(r, r))
|
||
let f := shr(128, r)
|
||
log_2 := or(log_2, shl(62, f))
|
||
r := shr(f, r)
|
||
}
|
||
assembly {
|
||
r := shr(127, mul(r, r))
|
||
let f := shr(128, r)
|
||
log_2 := or(log_2, shl(61, f))
|
||
r := shr(f, r)
|
||
}
|
||
assembly {
|
||
r := shr(127, mul(r, r))
|
||
let f := shr(128, r)
|
||
log_2 := or(log_2, shl(60, f))
|
||
r := shr(f, r)
|
||
}
|
||
assembly {
|
||
r := shr(127, mul(r, r))
|
||
let f := shr(128, r)
|
||
log_2 := or(log_2, shl(59, f))
|
||
r := shr(f, r)
|
||
}
|
||
assembly {
|
||
r := shr(127, mul(r, r))
|
||
let f := shr(128, r)
|
||
log_2 := or(log_2, shl(58, f))
|
||
r := shr(f, r)
|
||
}
|
||
assembly {
|
||
r := shr(127, mul(r, r))
|
||
let f := shr(128, r)
|
||
log_2 := or(log_2, shl(57, f))
|
||
r := shr(f, r)
|
||
}
|
||
assembly {
|
||
r := shr(127, mul(r, r))
|
||
let f := shr(128, r)
|
||
log_2 := or(log_2, shl(56, f))
|
||
r := shr(f, r)
|
||
}
|
||
assembly {
|
||
r := shr(127, mul(r, r))
|
||
let f := shr(128, r)
|
||
log_2 := or(log_2, shl(55, f))
|
||
r := shr(f, r)
|
||
}
|
||
assembly {
|
||
r := shr(127, mul(r, r))
|
||
let f := shr(128, r)
|
||
log_2 := or(log_2, shl(54, f))
|
||
r := shr(f, r)
|
||
}
|
||
assembly {
|
||
r := shr(127, mul(r, r))
|
||
let f := shr(128, r)
|
||
log_2 := or(log_2, shl(53, f))
|
||
r := shr(f, r)
|
||
}
|
||
assembly {
|
||
r := shr(127, mul(r, r))
|
||
let f := shr(128, r)
|
||
log_2 := or(log_2, shl(52, f))
|
||
r := shr(f, r)
|
||
}
|
||
assembly {
|
||
r := shr(127, mul(r, r))
|
||
let f := shr(128, r)
|
||
log_2 := or(log_2, shl(51, f))
|
||
r := shr(f, r)
|
||
}
|
||
assembly {
|
||
r := shr(127, mul(r, r))
|
||
let f := shr(128, r)
|
||
log_2 := or(log_2, shl(50, f))
|
||
}
|
||
|
||
int256 log_sqrt10001 = log_2 * 255738958999603826347141; // 128.128 number
|
||
|
||
int24 tickLow = int24((log_sqrt10001 - 3402992956809132418596140100660247210) >> 128);
|
||
int24 tickHi = int24((log_sqrt10001 + 291339464771989622907027621153398088495) >> 128);
|
||
|
||
tick = tickLow == tickHi ? tickLow : getSqrtRatioAtTick(tickHi) <= sqrtPriceX96 ? tickHi : tickLow;
|
||
}
|
||
}
|
||
|
||
library SqrtPriceMath {
|
||
using SafeCast for uint256;
|
||
|
||
function getAmount0Delta(
|
||
uint160 sqrtRatioAX96,
|
||
uint160 sqrtRatioBX96,
|
||
uint128 liquidity,
|
||
bool roundUp
|
||
) internal pure returns (uint256 amount0) {
|
||
if (sqrtRatioAX96 > sqrtRatioBX96) (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96);
|
||
|
||
uint256 numerator1 = uint256(liquidity) << FixedPoint96.RESOLUTION;
|
||
uint256 numerator2 = sqrtRatioBX96 - sqrtRatioAX96;
|
||
|
||
require(sqrtRatioAX96 > 0);
|
||
|
||
return
|
||
roundUp
|
||
? UnsafeMath.divRoundingUp(
|
||
FullMath.mulDivRoundingUp(numerator1, numerator2, sqrtRatioBX96),
|
||
sqrtRatioAX96
|
||
)
|
||
: FullMath.mulDiv(numerator1, numerator2, sqrtRatioBX96) / sqrtRatioAX96;
|
||
}
|
||
|
||
/// @notice Gets the amount1 delta between two prices
|
||
/// @dev Calculates liquidity * (sqrt(upper) - sqrt(lower))
|
||
/// @param sqrtRatioAX96 A sqrt price
|
||
/// @param sqrtRatioBX96 Another sqrt price
|
||
/// @param liquidity The amount of usable liquidity
|
||
/// @param roundUp Whether to round the amount up, or down
|
||
/// @return amount1 Amount of token1 required to cover a position of size liquidity between the two passed prices
|
||
function getAmount1Delta(
|
||
uint160 sqrtRatioAX96,
|
||
uint160 sqrtRatioBX96,
|
||
uint128 liquidity,
|
||
bool roundUp
|
||
) internal pure returns (uint256 amount1) {
|
||
if (sqrtRatioAX96 > sqrtRatioBX96) (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96);
|
||
|
||
return
|
||
roundUp
|
||
? FullMath.mulDivRoundingUp(liquidity, sqrtRatioBX96 - sqrtRatioAX96, FixedPoint96.Q96)
|
||
: FullMath.mulDiv(liquidity, sqrtRatioBX96 - sqrtRatioAX96, FixedPoint96.Q96);
|
||
}
|
||
|
||
/// @notice Helper that gets signed token0 delta
|
||
/// @param sqrtRatioAX96 A sqrt price
|
||
/// @param sqrtRatioBX96 Another sqrt price
|
||
/// @param liquidity The change in liquidity for which to compute the amount0 delta
|
||
/// @return amount0 Amount of token0 corresponding to the passed liquidityDelta between the two prices
|
||
function getAmount0Delta(
|
||
uint160 sqrtRatioAX96,
|
||
uint160 sqrtRatioBX96,
|
||
int128 liquidity
|
||
) internal pure returns (int256 amount0) {
|
||
return
|
||
liquidity < 0
|
||
? -getAmount0Delta(sqrtRatioAX96, sqrtRatioBX96, uint128(-liquidity), false).toInt256()
|
||
: getAmount0Delta(sqrtRatioAX96, sqrtRatioBX96, uint128(liquidity), true).toInt256();
|
||
}
|
||
|
||
/// @notice Helper that gets signed token1 delta
|
||
/// @param sqrtRatioAX96 A sqrt price
|
||
/// @param sqrtRatioBX96 Another sqrt price
|
||
/// @param liquidity The change in liquidity for which to compute the amount1 delta
|
||
/// @return amount1 Amount of token1 corresponding to the passed liquidityDelta between the two prices
|
||
function getAmount1Delta(
|
||
uint160 sqrtRatioAX96,
|
||
uint160 sqrtRatioBX96,
|
||
int128 liquidity
|
||
) internal pure returns (int256 amount1) {
|
||
return
|
||
liquidity < 0
|
||
? -getAmount1Delta(sqrtRatioAX96, sqrtRatioBX96, uint128(-liquidity), false).toInt256()
|
||
: getAmount1Delta(sqrtRatioAX96, sqrtRatioBX96, uint128(liquidity), true).toInt256();
|
||
}
|
||
}
|
||
|
||
library FullMath {
|
||
/// @notice Calculates floor(a×b÷denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
|
||
/// @param a The multiplicand
|
||
/// @param b The multiplier
|
||
/// @param denominator The divisor
|
||
/// @return result The 256-bit result
|
||
/// @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv
|
||
function mulDiv(
|
||
uint256 a,
|
||
uint256 b,
|
||
uint256 denominator
|
||
) internal pure returns (uint256 result) {
|
||
// 512-bit multiply [prod1 prod0] = a * b
|
||
// Compute the product mod 2**256 and mod 2**256 - 1
|
||
// then use the Chinese Remainder Theorem to reconstruct
|
||
// the 512 bit result. The result is stored in two 256
|
||
// variables such that product = prod1 * 2**256 + prod0
|
||
uint256 prod0; // Least significant 256 bits of the product
|
||
uint256 prod1; // Most significant 256 bits of the product
|
||
assembly {
|
||
let mm := mulmod(a, b, not(0))
|
||
prod0 := mul(a, b)
|
||
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
|
||
}
|
||
|
||
// Handle non-overflow cases, 256 by 256 division
|
||
if (prod1 == 0) {
|
||
require(denominator > 0);
|
||
assembly {
|
||
result := div(prod0, denominator)
|
||
}
|
||
return result;
|
||
}
|
||
|
||
// Make sure the result is less than 2**256.
|
||
// Also prevents denominator == 0
|
||
require(denominator > prod1);
|
||
|
||
///////////////////////////////////////////////
|
||
// 512 by 256 division.
|
||
///////////////////////////////////////////////
|
||
|
||
// Make division exact by subtracting the remainder from [prod1 prod0]
|
||
// Compute remainder using mulmod
|
||
uint256 remainder;
|
||
assembly {
|
||
remainder := mulmod(a, b, denominator)
|
||
}
|
||
// Subtract 256 bit number from 512 bit number
|
||
assembly {
|
||
prod1 := sub(prod1, gt(remainder, prod0))
|
||
prod0 := sub(prod0, remainder)
|
||
}
|
||
|
||
// Factor powers of two out of denominator
|
||
// Compute largest power of two divisor of denominator.
|
||
// Always >= 1.
|
||
// NOTE: this is modified from the original Full math implementation to work with solidity 8
|
||
uint256 twos = (type(uint256).max - denominator + 1) & denominator;
|
||
// Divide denominator by power of two
|
||
assembly {
|
||
denominator := div(denominator, twos)
|
||
}
|
||
|
||
// Divide [prod1 prod0] by the factors of two
|
||
assembly {
|
||
prod0 := div(prod0, twos)
|
||
}
|
||
// Shift in bits from prod1 into prod0. For this we need
|
||
// to flip `twos` such that it is 2**256 / twos.
|
||
// If twos is zero, then it becomes one
|
||
assembly {
|
||
twos := add(div(sub(0, twos), twos), 1)
|
||
}
|
||
unchecked {
|
||
prod0 |= prod1 * twos;
|
||
|
||
// Invert denominator mod 2**256
|
||
// Now that denominator is an odd number, it has an inverse
|
||
// modulo 2**256 such that denominator * inv = 1 mod 2**256.
|
||
// Compute the inverse by starting with a seed that is correct
|
||
// correct for four bits. That is, denominator * inv = 1 mod 2**4
|
||
uint256 inv = (3 * denominator) ^ 2;
|
||
// Now use Newton-Raphson iteration to improve the precision.
|
||
// Thanks to Hensel's lifting lemma, this also works in modular
|
||
// arithmetic, doubling the correct bits in each step.
|
||
// NOTE: this is modified from the original Full math implementation to work with solidity 8 with the unchecked syntax.
|
||
inv *= 2 - denominator * inv; // inverse mod 2**8
|
||
inv *= 2 - denominator * inv; // inverse mod 2**16
|
||
inv *= 2 - denominator * inv; // inverse mod 2**32
|
||
inv *= 2 - denominator * inv; // inverse mod 2**64
|
||
inv *= 2 - denominator * inv; // inverse mod 2**128
|
||
inv *= 2 - denominator * inv; // inverse mod 2**256
|
||
// Because the division is now exact we can divide by multiplying
|
||
// with the modular inverse of denominator. This will give us the
|
||
// correct result modulo 2**256. Since the precoditions guarantee
|
||
// that the outcome is less than 2**256, this is the final result.
|
||
// We don't need to compute the high bits of the result and prod1
|
||
// is no longer required.
|
||
result = prod0 * inv;
|
||
}
|
||
return result;
|
||
}
|
||
|
||
/// @notice Calculates ceil(a×b÷denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
|
||
/// @param a The multiplicand
|
||
/// @param b The multiplier
|
||
/// @param denominator The divisor
|
||
/// @return result The 256-bit result
|
||
function mulDivRoundingUp(
|
||
uint256 a,
|
||
uint256 b,
|
||
uint256 denominator
|
||
) internal pure returns (uint256 result) {
|
||
result = mulDiv(a, b, denominator);
|
||
if (mulmod(a, b, denominator) > 0) {
|
||
require(result < type(uint256).max);
|
||
result++;
|
||
}
|
||
}
|
||
}
|
||
|
||
library FixedPoint96 {
|
||
uint8 internal constant RESOLUTION = 96;
|
||
uint256 internal constant Q96 = 0x1000000000000000000000000;
|
||
}
|