Skip to content

Commit

Permalink
Merge pull request #54 from terminal-fi/univ3fix2
Browse files Browse the repository at this point in the history
uniswapv3 major rewrite and fixes for the pair
  • Loading branch information
zviadm authored Jul 19, 2023
2 parents 13a2213 + c14e1bc commit fc76d84
Show file tree
Hide file tree
Showing 48 changed files with 578 additions and 1,349 deletions.
66 changes: 66 additions & 0 deletions contracts/interfaces/uniswap/IQuoterV2.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.6.8;
pragma experimental ABIEncoderV2;

/// @title QuoterV2 Interface
/// @notice Supports quoting the calculated amounts from exact input or exact output swaps.
/// @notice For each pool also tells you the number of initialized ticks crossed and the sqrt price of the pool after the swap.
/// @dev These functions are not marked view because they rely on calling non-view functions and reverting
/// to compute the result. They are also not gas efficient and should not be called on-chain.
interface IQuoterV2 {
struct QuoteExactInputSingleParams {
address tokenIn;
address tokenOut;
uint256 amountIn;
uint24 fee;
uint160 sqrtPriceLimitX96;
}

/// @notice Returns the amount out received for a given exact input but for a swap of a single pool
/// @param params The params for the quote, encoded as `QuoteExactInputSingleParams`
/// tokenIn The token being swapped in
/// tokenOut The token being swapped out
/// fee The fee of the token pool to consider for the pair
/// amountIn The desired input amount
/// sqrtPriceLimitX96 The price limit of the pool that cannot be exceeded by the swap
/// @return amountOut The amount of `tokenOut` that would be received
/// @return sqrtPriceX96After The sqrt price of the pool after the swap
/// @return initializedTicksCrossed The number of initialized ticks that the swap crossed
/// @return gasEstimate The estimate of the gas that the swap consumes
function quoteExactInputSingle(QuoteExactInputSingleParams calldata params)
external
returns (
uint256 amountOut,
uint160 sqrtPriceX96After,
uint32 initializedTicksCrossed,
uint256 gasEstimate
);

struct QuoteExactOutputSingleParams {
address tokenIn;
address tokenOut;
uint256 amount;
uint24 fee;
uint160 sqrtPriceLimitX96;
}

/// @notice Returns the amount in required to receive the given exact output amount but for a swap of a single pool
/// @param params The params for the quote, encoded as `QuoteExactOutputSingleParams`
/// tokenIn The token being swapped in
/// tokenOut The token being swapped out
/// fee The fee of the token pool to consider for the pair
/// amountOut The desired output amount
/// sqrtPriceLimitX96 The price limit of the pool that cannot be exceeded by the swap
/// @return amountIn The amount required as the input for the swap in order to receive `amountOut`
/// @return sqrtPriceX96After The sqrt price of the pool after the swap
/// @return initializedTicksCrossed The number of initialized ticks that the swap crossed
/// @return gasEstimate The estimate of the gas that the swap consumes
function quoteExactOutputSingle(QuoteExactOutputSingleParams calldata params)
external
returns (
uint256 amountIn,
uint160 sqrtPriceX96After,
uint32 initializedTicksCrossed,
uint256 gasEstimate
);
}
199 changes: 0 additions & 199 deletions contracts/interfaces/uniswap/Quoter.sol

This file was deleted.

80 changes: 56 additions & 24 deletions contracts/interfaces/uniswap/TickLens.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,32 @@ pragma solidity >=0.4.0 <0.8.0;
pragma experimental ABIEncoderV2;

import "./IUniswapV3Pool.sol";
import "./TickMath.sol";

library TickLens {

struct PopulatedTick {
int24 tick;
int128 liquidityNet;
uint128 liquidityGross;
}

function getSpotTicks(IUniswapV3Pool pool)
// getPoolTicks returns populated ticks from the Uniswapv3 pool.
// To keep things reasonably performant it only tries to fetch 5 populated tick words.
// populatedTicks are not sorted, thus it is up to the user to sort them appropriately.
function getPoolTicks(IUniswapV3Pool pool, int16 maxLoopN)
internal
view
returns (
uint160 sqrtPriceX96,
int24 tick,
PopulatedTick[] memory populatedTicksTwiceAbove,
PopulatedTick[] memory populatedTicksAbove,
PopulatedTick[] memory populatedTicksSpot,
PopulatedTick[] memory populatedTicksBelow,
PopulatedTick[] memory populatedTicksTwiceBelow
uint128 liquidity,
PopulatedTick[] memory populatedTicks0,
PopulatedTick[] memory populatedTicks1,
PopulatedTick[] memory populatedTicks2,
PopulatedTick[] memory populatedTicks3,
PopulatedTick[] memory populatedTicks4
)
{
// get the populated ticks above and below the current spot tick
(
sqrtPriceX96,
tick,
Expand All @@ -35,6 +38,7 @@ library TickLens {
, // uint8 feeProtocol
// bool unlocked
) = pool.slot0();
liquidity = pool.liquidity();

int24 tickSpacing = pool.tickSpacing();
int24 compressed = tick / tickSpacing;
Expand All @@ -43,19 +47,49 @@ library TickLens {
// current word position within bitmap
int16 tickBitmapIndex = int16(compressed >> 8);

// get the populated ticks at, above, and below the current word
populatedTicksTwiceAbove = new PopulatedTick[](0);
populatedTicksSpot = getPopulatedTicksInWord(pool, tickBitmapIndex);
populatedTicksTwiceBelow = getPopulatedTicksInWord(
pool,
tickBitmapIndex - 2
);
populatedTicksAbove = getPopulatedTicksInWord(
pool,
tickBitmapIndex + 1
);
populatedTicksTwiceBelow = new PopulatedTick[](0);
// get the populated ticks near current tick.
int16 boundTickBitmapIndex = tickBitmapIndex + maxLoopN / 2;
int16 nextBitmapIndex = tickBitmapIndex;
(populatedTicks0, nextBitmapIndex) = nextPopulatedTick(pool, nextBitmapIndex, boundTickBitmapIndex);
(populatedTicks1, nextBitmapIndex) = nextPopulatedTick(pool, nextBitmapIndex, boundTickBitmapIndex);
(populatedTicks2, nextBitmapIndex) = nextPopulatedTick(pool, nextBitmapIndex, boundTickBitmapIndex);

boundTickBitmapIndex = tickBitmapIndex - maxLoopN / 2;
nextBitmapIndex = tickBitmapIndex - 1;
(populatedTicks3, nextBitmapIndex) = prevPopulatedTick(pool, nextBitmapIndex, boundTickBitmapIndex);
(populatedTicks4, nextBitmapIndex) = prevPopulatedTick(pool, nextBitmapIndex, boundTickBitmapIndex);
}

function nextPopulatedTick(
IUniswapV3Pool pool,
int16 tickBitmapIndex,
int16 maxTickBitmapIndex)
internal
view
returns (PopulatedTick[] memory populatedTicks, int16 nextBitmapIndex)
{
for (
nextBitmapIndex = tickBitmapIndex;
nextBitmapIndex <= maxTickBitmapIndex && populatedTicks.length == 0;
nextBitmapIndex += 1) {
populatedTicks = getPopulatedTicksInWord(pool, nextBitmapIndex);
}
}

function prevPopulatedTick(
IUniswapV3Pool pool,
int16 tickBitmapIndex,
int16 minTickBitmapIndex)
internal
view
returns (PopulatedTick[] memory populatedTicks, int16 nextBitmapIndex)
{
for (
nextBitmapIndex = tickBitmapIndex;
nextBitmapIndex >= minTickBitmapIndex && populatedTicks.length == 0;
nextBitmapIndex -= 1) {
populatedTicks = getPopulatedTicksInWord(pool, nextBitmapIndex);
}
}

function getPopulatedTicksInWord(IUniswapV3Pool pool, int16 tickBitmapIndex)
Expand All @@ -77,10 +111,8 @@ library TickLens {
populatedTicks = new PopulatedTick[](numberOfPopulatedTicks);
for (uint256 i = 0; i < 256; i++) {
if (bitmap & (1 << i) > 0) {
int24 populatedTick = ((int24(tickBitmapIndex) << 8) +
int24(i)) * tickSpacing;
(uint128 liquidityGross, int128 liquidityNet, , , , , , ) = pool
.ticks(populatedTick);
int24 populatedTick = ((int24(tickBitmapIndex) << 8) + int24(i)) * tickSpacing;
(uint128 liquidityGross, int128 liquidityNet, , , , , , ) = pool.ticks(populatedTick);
populatedTicks[--numberOfPopulatedTicks] = PopulatedTick({
tick: populatedTick,
liquidityNet: liquidityNet,
Expand Down
Loading

0 comments on commit fc76d84

Please sign in to comment.