Skip to content

Commit

Permalink
Quoter update (#349)
Browse files Browse the repository at this point in the history
* remove counting tick crossing

* add gas estimate return

* refactor into revert library

* remove cache struct

* cache path key

* Change return types

* remove sqrt price after logic

* Revert with custom error

* comments

* typo

* factor base contract

* move cache into transient storage

* Remove cache entirely

* PR comments

* Refactor QuoterRevert library

* remove sqrtPriceLimit
  • Loading branch information
hensha256 authored Sep 23, 2024
1 parent 0a67b2e commit 47e3c30
Show file tree
Hide file tree
Showing 20 changed files with 310 additions and 640 deletions.
Original file line number Diff line number Diff line change
@@ -1 +1 @@
159043
143930
Original file line number Diff line number Diff line change
@@ -1 +1 @@
166396
149382
2 changes: 1 addition & 1 deletion .forge-snapshots/Quoter_exactOutputSingle_oneForZero.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
93637
78203
2 changes: 1 addition & 1 deletion .forge-snapshots/Quoter_exactOutputSingle_zeroForOne.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
100303
82626
Original file line number Diff line number Diff line change
@@ -1 +1 @@
141321
120491
Original file line number Diff line number Diff line change
@@ -1 +1 @@
164528
145414
Original file line number Diff line number Diff line change
@@ -1 +1 @@
98641
79437
2 changes: 1 addition & 1 deletion .forge-snapshots/Quoter_quoteExactInput_twoHops.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
234806
201179
Original file line number Diff line number Diff line change
@@ -1 +1 @@
161346
119782
Original file line number Diff line number Diff line change
@@ -1 +1 @@
191453
149919
Original file line number Diff line number Diff line change
@@ -1 +1 @@
161661
119850
Original file line number Diff line number Diff line change
@@ -1 +1 @@
136430
96549
2 changes: 1 addition & 1 deletion .forge-snapshots/Quoter_quoteExactOutput_twoHops.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
275720
200630
2 changes: 1 addition & 1 deletion foundry.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[profile.default]
out = 'foundry-out'
solc_version = '0.8.26'
optimizer_runs = 1_000_000
optimizer_runs = 44444444
via_ir = true
ffi = true
fs_permissions = [{ access = "read-write", path = ".forge-snapshots/"}]
Expand Down
58 changes: 58 additions & 0 deletions src/base/BaseV4Quoter.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// SPDX-License-Identifier: UNLICENSED

import {IPoolManager} from "@uniswap/v4-core/src/interfaces/IPoolManager.sol";
import {BalanceDelta} from "@uniswap/v4-core/src/types/BalanceDelta.sol";
import {PoolKey} from "@uniswap/v4-core/src/types/PoolKey.sol";
import {QuoterRevert} from "../libraries/QuoterRevert.sol";
import {SafeCallback} from "../base/SafeCallback.sol";
import {PoolId, PoolIdLibrary} from "@uniswap/v4-core/src/types/PoolId.sol";
import {TickMath} from "@uniswap/v4-core/src/libraries/TickMath.sol";

abstract contract BaseV4Quoter is SafeCallback {
using QuoterRevert for *;
using PoolIdLibrary for PoolId;

error NotEnoughLiquidity(PoolId poolId);
error NotSelf();
error UnexpectedCallSuccess();

constructor(IPoolManager _poolManager) SafeCallback(_poolManager) {}

/// @dev Only this address may call this function. Used to mimic internal functions, using an
/// external call to catch and parse revert reasons
modifier selfOnly() {
if (msg.sender != address(this)) revert NotSelf();
_;
}

function _unlockCallback(bytes calldata data) internal override returns (bytes memory) {
(bool success, bytes memory returnData) = address(this).call(data);
// Every quote path gathers a quote, and then reverts either with QuoteSwap(quoteAmount) or alternative error
if (success) revert UnexpectedCallSuccess();
// Bubble the revert string, whether a valid quote or an alternative error
returnData.bubbleReason();
}

/// @dev Execute a swap and return the balance delta
/// @notice if amountSpecified < 0, the swap is exactInput, otherwise exactOutput
function _swap(PoolKey memory poolKey, bool zeroForOne, int256 amountSpecified, bytes calldata hookData)
internal
returns (BalanceDelta swapDelta)
{
swapDelta = poolManager.swap(
poolKey,
IPoolManager.SwapParams({
zeroForOne: zeroForOne,
amountSpecified: amountSpecified,
sqrtPriceLimitX96: zeroForOne ? TickMath.MIN_SQRT_PRICE + 1 : TickMath.MAX_SQRT_PRICE - 1
}),
hookData
);

// Check that the pool was not illiquid.
int128 amountSpecifiedActual = (zeroForOne == (amountSpecified < 0)) ? swapDelta.amount0() : swapDelta.amount1();
if (amountSpecifiedActual != amountSpecified) {
revert NotEnoughLiquidity(poolKey.toId());
}
}
}
53 changes: 13 additions & 40 deletions src/interfaces/IQuoter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,27 +7,14 @@ import {PathKey} from "../libraries/PathKey.sol";

/// @title Quoter Interface
/// @notice Supports quoting the delta amounts for exact input or exact output swaps.
/// @notice For each pool also tells you the number of initialized ticks loaded and the sqrt price of the pool after the swap.
/// @notice For each pool also tells you 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 IQuoter {
error InvalidLockCaller();
error InvalidQuoteBatchParams();
error InsufficientAmountOut();
error LockFailure();
error NotSelf();
error UnexpectedRevertBytes(bytes revertData);

struct PoolDeltas {
int128 currency0Delta;
int128 currency1Delta;
}

struct QuoteExactSingleParams {
PoolKey poolKey;
bool zeroForOne;
uint128 exactAmount;
uint160 sqrtPriceLimitX96;
bytes hookData;
}

Expand All @@ -42,58 +29,44 @@ interface IQuoter {
/// poolKey The key for identifying a V4 pool
/// zeroForOne If the swap is from currency0 to currency1
/// exactAmount The desired input amount
/// sqrtPriceLimitX96 The price limit of the pool that cannot be exceeded by the swap
/// hookData arbitrary hookData to pass into the associated hooks
/// @return deltaAmounts Delta amounts resulted from the swap
/// @return sqrtPriceX96After The sqrt price of the pool after the swap
/// @return initializedTicksLoaded The number of initialized ticks that the swap loaded
/// @return amountOut The output quote for the exactIn swap
/// @return gasEstimate Estimated gas units used for the swap
function quoteExactInputSingle(QuoteExactSingleParams memory params)
external
returns (int128[] memory deltaAmounts, uint160 sqrtPriceX96After, uint32 initializedTicksLoaded);
returns (uint256 amountOut, uint256 gasEstimate);

/// @notice Returns the delta amounts along the swap path for a given exact input swap
/// @param params the params for the quote, encoded as 'QuoteExactParams'
/// currencyIn The input currency of the swap
/// path The path of the swap encoded as PathKeys that contains currency, fee, tickSpacing, and hook info
/// exactAmount The desired input amount
/// @return deltaAmounts Delta amounts along the path resulted from the swap
/// @return sqrtPriceX96AfterList List of the sqrt price after the swap for each pool in the path
/// @return initializedTicksLoadedList List of the initialized ticks that the swap loaded for each pool in the path
/// @return amountOut The output quote for the exactIn swap
/// @return gasEstimate Estimated gas units used for the swap
function quoteExactInput(QuoteExactParams memory params)
external
returns (
int128[] memory deltaAmounts,
uint160[] memory sqrtPriceX96AfterList,
uint32[] memory initializedTicksLoadedList
);
returns (uint256 amountOut, uint256 gasEstimate);

/// @notice Returns the delta amounts for a given exact output swap of a single pool
/// @param params The params for the quote, encoded as `QuoteExactSingleParams`
/// poolKey The key for identifying a V4 pool
/// zeroForOne If the swap is from currency0 to currency1
/// exactAmount The desired output amount
/// sqrtPriceLimitX96 The price limit of the pool that cannot be exceeded by the swap
/// hookData arbitrary hookData to pass into the associated hooks
/// @return deltaAmounts Delta amounts resulted from the swap
/// @return sqrtPriceX96After The sqrt price of the pool after the swap
/// @return initializedTicksLoaded The number of initialized ticks that the swap loaded
/// @return amountIn The input quote for the exactOut swap
/// @return gasEstimate Estimated gas units used for the swap
function quoteExactOutputSingle(QuoteExactSingleParams memory params)
external
returns (int128[] memory deltaAmounts, uint160 sqrtPriceX96After, uint32 initializedTicksLoaded);
returns (uint256 amountIn, uint256 gasEstimate);

/// @notice Returns the delta amounts along the swap path for a given exact output swap
/// @param params the params for the quote, encoded as 'QuoteExactParams'
/// currencyOut The output currency of the swap
/// path The path of the swap encoded as PathKeys that contains currency, fee, tickSpacing, and hook info
/// exactAmount The desired output amount
/// @return deltaAmounts Delta amounts along the path resulted from the swap
/// @return sqrtPriceX96AfterList List of the sqrt price after the swap for each pool in the path
/// @return initializedTicksLoadedList List of the initialized ticks that the swap loaded for each pool in the path
/// @return amountIn The input quote for the exactOut swap
/// @return gasEstimate Estimated gas units used for the swap
function quoteExactOutput(QuoteExactParams memory params)
external
returns (
int128[] memory deltaAmounts,
uint160[] memory sqrtPriceX96AfterList,
uint32[] memory initializedTicksLoadedList
);
returns (uint256 amountIn, uint256 gasEstimate);
}
Loading

0 comments on commit 47e3c30

Please sign in to comment.