Skip to content

Commit

Permalink
Change return types
Browse files Browse the repository at this point in the history
  • Loading branch information
hensha256 committed Sep 11, 2024
1 parent 251c104 commit 7b665b4
Show file tree
Hide file tree
Showing 17 changed files with 102 additions and 129 deletions.
Original file line number Diff line number Diff line change
@@ -1 +1 @@
149088
147574
Original file line number Diff line number Diff line change
@@ -1 +1 @@
154572
153033
2 changes: 1 addition & 1 deletion .forge-snapshots/Quoter_exactOutputSingle_oneForZero.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
83716
82272
2 changes: 1 addition & 1 deletion .forge-snapshots/Quoter_exactOutputSingle_zeroForOne.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
88524
87066
Original file line number Diff line number Diff line change
@@ -1 +1 @@
127764
125376
Original file line number Diff line number Diff line change
@@ -1 +1 @@
152656
150285
Original file line number Diff line number Diff line change
@@ -1 +1 @@
86679
84308
2 changes: 1 addition & 1 deletion .forge-snapshots/Quoter_quoteExactInput_twoHops.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
210976
207585
Original file line number Diff line number Diff line change
@@ -1 +1 @@
147458
145077
Original file line number Diff line number Diff line change
@@ -1 +1 @@
177595
175214
Original file line number Diff line number Diff line change
@@ -1 +1 @@
147526
145145
Original file line number Diff line number Diff line change
@@ -1 +1 @@
124225
121844
2 changes: 1 addition & 1 deletion .forge-snapshots/Quoter_quoteExactOutput_twoHops.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
251247
247853
16 changes: 8 additions & 8 deletions src/interfaces/IQuoter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -43,22 +43,22 @@ interface IQuoter {
/// 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 amountOut The output quote for the exactIn swap
/// @return sqrtPriceX96After The sqrt price of the pool after the swap
function quoteExactInputSingle(QuoteExactSingleParams memory params)
external
returns (int128[] memory deltaAmounts, uint160 sqrtPriceX96After, uint256 gasEstimate);
returns (uint256 amountOut, uint160 sqrtPriceX96After, 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 amountOut The output quote for the exactIn swap
/// @return sqrtPriceX96AfterList List of the sqrt price after the swap for each pool in the path
function quoteExactInput(QuoteExactParams memory params)
external
returns (int128[] memory deltaAmounts, uint160[] memory sqrtPriceX96AfterList, uint256 gasEstimate);
returns (uint256 amountOut, uint160[] memory sqrtPriceX96AfterList, 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`
Expand All @@ -67,20 +67,20 @@ interface IQuoter {
/// 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 amountIn The input quote for the exactOut swap
/// @return sqrtPriceX96After The sqrt price of the pool after the swap
function quoteExactOutputSingle(QuoteExactSingleParams memory params)
external
returns (int128[] memory deltaAmounts, uint160 sqrtPriceX96After, uint256 gasEstimate);
returns (uint256 amountIn, uint160 sqrtPriceX96After, 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 amountIn The input quote for the exactOut swap
/// @return sqrtPriceX96AfterList List of the sqrt price after the swap for each pool in the path
function quoteExactOutput(QuoteExactParams memory params)
external
returns (int128[] memory deltaAmounts, uint160[] memory sqrtPriceX96AfterList, uint256 gasEstimate);
returns (uint256 amountIn, uint160[] memory sqrtPriceX96AfterList, uint256 gasEstimate);
}
72 changes: 24 additions & 48 deletions src/lens/Quoter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,6 @@ contract Quoter is IQuoter, SafeCallback {
/// @dev cache used to check a safety condition in exact output swaps.
uint128 private amountOutCached;

struct QuoteResult {
int128[] deltaAmounts;
uint160[] sqrtPriceX96AfterList;
}

/// @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() {
Expand All @@ -39,53 +34,53 @@ contract Quoter is IQuoter, SafeCallback {
/// @inheritdoc IQuoter
function quoteExactInputSingle(QuoteExactSingleParams memory params)
external
returns (int128[] memory deltaAmounts, uint160 sqrtPriceX96After, uint256 gasEstimate)
returns (uint256 amountOut, uint160 sqrtPriceX96After, uint256 gasEstimate)
{
uint256 gasBefore = gasleft();
try poolManager.unlock(abi.encodeCall(this._quoteExactInputSingle, (params))) {}
catch (bytes memory reason) {
gasEstimate = gasBefore - gasleft();
(deltaAmounts, sqrtPriceX96After) = reason.parseReturnDataSingle();
(amountOut, sqrtPriceX96After) = reason.parseReturnDataSingle();
}
}

/// @inheritdoc IQuoter
function quoteExactInput(QuoteExactParams memory params)
external
returns (int128[] memory deltaAmounts, uint160[] memory sqrtPriceX96AfterList, uint256 gasEstimate)
returns (uint256 amountOut, uint160[] memory sqrtPriceX96AfterList, uint256 gasEstimate)
{
uint256 gasBefore = gasleft();
try poolManager.unlock(abi.encodeCall(this._quoteExactInput, (params))) {}
catch (bytes memory reason) {
gasEstimate = gasBefore - gasleft();
(deltaAmounts, sqrtPriceX96AfterList) = reason.parseReturnData();
(amountOut, sqrtPriceX96AfterList) = reason.parseReturnData();
}
}

/// @inheritdoc IQuoter
function quoteExactOutputSingle(QuoteExactSingleParams memory params)
external
returns (int128[] memory deltaAmounts, uint160 sqrtPriceX96After, uint256 gasEstimate)
returns (uint256 amountIn, uint160 sqrtPriceX96After, uint256 gasEstimate)
{
uint256 gasBefore = gasleft();
try poolManager.unlock(abi.encodeCall(this._quoteExactOutputSingle, (params))) {}
catch (bytes memory reason) {
gasEstimate = gasBefore - gasleft();
if (params.sqrtPriceLimitX96 == 0) delete amountOutCached;
(deltaAmounts, sqrtPriceX96After) = reason.parseReturnDataSingle();
(amountIn, sqrtPriceX96After) = reason.parseReturnDataSingle();
}
}

/// @inheritdoc IQuoter
function quoteExactOutput(QuoteExactParams memory params)
external
returns (int128[] memory deltaAmounts, uint160[] memory sqrtPriceX96AfterList, uint256 gasEstimate)
returns (uint256 amountIn, uint160[] memory sqrtPriceX96AfterList, uint256 gasEstimate)
{
uint256 gasBefore = gasleft();
try poolManager.unlock(abi.encodeCall(this._quoteExactOutput, (params))) {}
catch (bytes memory reason) {
gasEstimate = gasBefore - gasleft();
(deltaAmounts, sqrtPriceX96AfterList) = reason.parseReturnData();
(amountIn, sqrtPriceX96AfterList) = reason.parseReturnData();
}
}

Expand All @@ -101,8 +96,7 @@ contract Quoter is IQuoter, SafeCallback {
function _quoteExactInput(QuoteExactParams calldata params) external selfOnly returns (bytes memory) {
uint256 pathLength = params.path.length;

QuoteResult memory result =
QuoteResult({deltaAmounts: new int128[](pathLength + 1), sqrtPriceX96AfterList: new uint160[](pathLength)});
uint160[] memory sqrtPriceX96AfterList = new uint160[](pathLength);
BalanceDelta swapDelta;
uint128 amountIn = params.exactAmount;
Currency inputCurrency = params.exactCurrency;
Expand All @@ -112,21 +106,14 @@ contract Quoter is IQuoter, SafeCallback {
pathKey = params.path[i];
(PoolKey memory poolKey, bool zeroForOne) = pathKey.getPoolAndSwapDirection(inputCurrency);

(swapDelta, result.sqrtPriceX96AfterList[i]) =
(swapDelta, sqrtPriceX96AfterList[i]) =
_swap(poolKey, zeroForOne, -int256(int128(amountIn)), 0, pathKey.hookData);

if (zeroForOne) {
result.deltaAmounts[i] += -swapDelta.amount0();
result.deltaAmounts[i + 1] += -swapDelta.amount1();
amountIn = uint128(swapDelta.amount1());
} else {
result.deltaAmounts[i] += -swapDelta.amount1();
result.deltaAmounts[i + 1] += -swapDelta.amount0();
amountIn = uint128(swapDelta.amount0());
}
amountIn = zeroForOne ? uint128(swapDelta.amount1()) : uint128(swapDelta.amount0());
inputCurrency = pathKey.intermediateCurrency;
}
bytes memory encodedResult = abi.encode(result.deltaAmounts, result.sqrtPriceX96AfterList);
// amountIn after the loop actually holds the amountOut of the trade
bytes memory encodedResult = abi.encode(amountIn, sqrtPriceX96AfterList);
encodedResult.revertWith();
}

Expand All @@ -140,21 +127,18 @@ contract Quoter is IQuoter, SafeCallback {
params.hookData
);

int128[] memory deltaAmounts = new int128[](2);

deltaAmounts[0] = -deltas.amount0();
deltaAmounts[1] = -deltas.amount1();
// the output delta of a swap is positive
uint256 amountOut = params.zeroForOne ? uint128(deltas.amount1()) : uint128(deltas.amount0());

bytes memory encodedResult = abi.encode(deltaAmounts, sqrtPriceX96After);
bytes memory encodedResult = abi.encode(amountOut, sqrtPriceX96After);
encodedResult.revertWith();
}

/// @dev external function called within the _unlockCallback, to simulate an exact output swap, then revert with the result
function _quoteExactOutput(QuoteExactParams calldata params) external selfOnly returns (bytes memory) {
uint256 pathLength = params.path.length;

QuoteResult memory result =
QuoteResult({deltaAmounts: new int128[](pathLength + 1), sqrtPriceX96AfterList: new uint160[](pathLength)});
uint160[] memory sqrtPriceX96AfterList = new uint160[](pathLength);
BalanceDelta swapDelta;
uint128 amountOut = params.exactAmount;
Currency outputCurrency = params.exactCurrency;
Expand All @@ -166,25 +150,18 @@ contract Quoter is IQuoter, SafeCallback {

(PoolKey memory poolKey, bool oneForZero) = pathKey.getPoolAndSwapDirection(outputCurrency);

(swapDelta, result.sqrtPriceX96AfterList[i - 1]) =
(swapDelta, sqrtPriceX96AfterList[i - 1]) =
_swap(poolKey, !oneForZero, int256(uint256(amountOut)), 0, pathKey.hookData);

// always clear because sqrtPriceLimitX96 is set to 0 always
delete amountOutCached;

if (!oneForZero) {
result.deltaAmounts[i - 1] += -swapDelta.amount0();
result.deltaAmounts[i] += -swapDelta.amount1();
amountOut = uint128(-swapDelta.amount0());
} else {
result.deltaAmounts[i - 1] += -swapDelta.amount1();
result.deltaAmounts[i] += -swapDelta.amount0();
amountOut = uint128(-swapDelta.amount1());
}
amountOut = oneForZero ? uint128(-swapDelta.amount1()) : uint128(-swapDelta.amount0());

outputCurrency = pathKey.intermediateCurrency;
}
bytes memory encodedResult = abi.encode(result.deltaAmounts, result.sqrtPriceX96AfterList);
// amountOut after the loop exits actually holds the amountIn of the trade
bytes memory encodedResult = abi.encode(amountOut, sqrtPriceX96AfterList);
encodedResult.revertWith();
}

Expand All @@ -202,12 +179,11 @@ contract Quoter is IQuoter, SafeCallback {
);

if (amountOutCached != 0) delete amountOutCached;
int128[] memory deltaAmounts = new int128[](2);

deltaAmounts[0] = -deltas.amount0();
deltaAmounts[1] = -deltas.amount1();
// the input delta of a swap is negative so we must flip it
uint256 amountIn = params.zeroForOne ? uint128(-deltas.amount0()) : uint128(-deltas.amount1());

bytes memory encodedResult = abi.encode(deltaAmounts, sqrtPriceX96After);
bytes memory encodedResult = abi.encode(amountIn, sqrtPriceX96After);
encodedResult.revertWith();
}

Expand Down
15 changes: 7 additions & 8 deletions src/libraries/RevertBytes.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,9 @@ library RevertBytes {
/// @notice error thrown when invalid revert bytes are thrown by the quote
error UnexpectedRevertBytes(bytes revertData);

/// @dev min valid reason is 5-words long (160 bytes)
/// @dev int128[2] includes 32 bytes for offset, 32 bytes for length, and 32 bytes for each element
/// @dev Plus sqrtPriceX96After padded to 32 bytes
uint256 internal constant MINIMUM_VALID_RESPONSE_LENGTH = 160;
/// @dev min valid reason is 2-words long (64 bytes)
/// @dev amountUnspecified and sqrtPriceX96After
uint256 internal constant MINIMUM_VALID_RESPONSE_LENGTH = 64;

/// @notice reverts, where the revert data is the provided bytes
/// @dev called when quoting, at the end of simulating a swap, to revert with the swap information as the revert reason
Expand All @@ -32,15 +31,15 @@ library RevertBytes {

/// @notice validates a received revert reason from a single-hop swap.
/// Then, if valid, decodes it into the information generated by a quote
function parseReturnDataSingle(bytes memory reason) internal pure returns (int128[] memory, uint160) {
function parseReturnDataSingle(bytes memory reason) internal pure returns (uint256, uint160) {
reason.validateRevertReason();
return abi.decode(reason, (int128[], uint160));
return abi.decode(reason, (uint256, uint160));
}

/// @notice validates a received revert reason from a multi-hop swap.
/// Then, if valid, decodes it into the information generated by a quote
function parseReturnData(bytes memory reason) internal pure returns (int128[] memory, uint160[] memory) {
function parseReturnData(bytes memory reason) internal pure returns (uint256, uint160[] memory) {
reason.validateRevertReason();
return abi.decode(reason, (int128[], uint160[]));
return abi.decode(reason, (uint256, uint160[]));
}
}
Loading

0 comments on commit 7b665b4

Please sign in to comment.