Skip to content

Commit

Permalink
Refactor QuoterRevert library
Browse files Browse the repository at this point in the history
  • Loading branch information
hensha256 committed Sep 18, 2024
1 parent 44d9c73 commit e84c8fc
Show file tree
Hide file tree
Showing 16 changed files with 38 additions and 39 deletions.
Original file line number Diff line number Diff line change
@@ -1 +1 @@
144101
144072
Original file line number Diff line number Diff line change
@@ -1 +1 @@
149552
149523
2 changes: 1 addition & 1 deletion .forge-snapshots/Quoter_exactOutputSingle_oneForZero.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
78628
78599
2 changes: 1 addition & 1 deletion .forge-snapshots/Quoter_exactOutputSingle_zeroForOne.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
83436
83407
Original file line number Diff line number Diff line change
@@ -1 +1 @@
120564
120493
Original file line number Diff line number Diff line change
@@ -1 +1 @@
145487
145416
Original file line number Diff line number Diff line change
@@ -1 +1 @@
79510
79439
2 changes: 1 addition & 1 deletion .forge-snapshots/Quoter_quoteExactInput_twoHops.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
201252
201179
Original file line number Diff line number Diff line change
@@ -1 +1 @@
119899
119828
Original file line number Diff line number Diff line change
@@ -1 +1 @@
150036
149965
Original file line number Diff line number Diff line change
@@ -1 +1 @@
119967
119896
Original file line number Diff line number Diff line change
@@ -1 +1 @@
96666
96595
2 changes: 1 addition & 1 deletion .forge-snapshots/Quoter_quoteExactOutput_twoHops.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
200747
200674
7 changes: 4 additions & 3 deletions src/base/BaseV4Quoter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ abstract contract BaseV4Quoter is SafeCallback {
using PoolIdLibrary for PoolId;

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

constructor(IPoolManager _poolManager) SafeCallback(_poolManager) {}

Expand All @@ -27,9 +27,10 @@ abstract contract BaseV4Quoter is SafeCallback {
}

function _unlockCallback(bytes calldata data) internal override returns (bytes memory) {
// Call this contract with the data in question. Each quote path
(bool success, bytes memory returnData) = address(this).call(data);
if (success) return returnData;
// 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();
}

Expand Down
12 changes: 8 additions & 4 deletions src/lens/Quoter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ contract Quoter is IQuoter, BaseV4Quoter {
try poolManager.unlock(abi.encodeCall(this._quoteExactInputSingle, (params))) {}
catch (bytes memory reason) {
gasEstimate = gasBefore - gasleft();
amountOut = reason.parseReturnData();
// Extract the quote from QuoteSwap error, or throw if the quote failed
amountOut = reason.parseQuoteAmount();
}
}

Expand All @@ -39,7 +40,8 @@ contract Quoter is IQuoter, BaseV4Quoter {
try poolManager.unlock(abi.encodeCall(this._quoteExactInput, (params))) {}
catch (bytes memory reason) {
gasEstimate = gasBefore - gasleft();
amountOut = reason.parseReturnData();
// Extract the quote from QuoteSwap error, or throw if the quote failed
amountOut = reason.parseQuoteAmount();
}
}

Expand All @@ -52,7 +54,8 @@ contract Quoter is IQuoter, BaseV4Quoter {
try poolManager.unlock(abi.encodeCall(this._quoteExactOutputSingle, (params))) {}
catch (bytes memory reason) {
gasEstimate = gasBefore - gasleft();
amountIn = reason.parseReturnData();
// Extract the quote from QuoteSwap error, or throw if the quote failed
amountIn = reason.parseQuoteAmount();
}
}

Expand All @@ -65,7 +68,8 @@ contract Quoter is IQuoter, BaseV4Quoter {
try poolManager.unlock(abi.encodeCall(this._quoteExactOutput, (params))) {}
catch (bytes memory reason) {
gasEstimate = gasBefore - gasleft();
amountIn = reason.parseReturnData();
// Extract the quote from QuoteSwap error, or throw if the quote failed
amountIn = reason.parseQuoteAmount();
}
}

Expand Down
32 changes: 13 additions & 19 deletions src/libraries/QuoterRevert.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,14 @@ library QuoterRevert {
error QuoteSwap(uint256 amount);

/// @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
function revertQuote(uint256 amountUnspecified) internal pure {
revert QuoteSwap(amountUnspecified);
/// @dev called when quoting, to record the quote amount in an error
/// @dev QuoteSwap is used to differentiate this error from other errors thrown when simulating the swap
function revertQuote(uint256 quoteAmount) internal pure {
revert QuoteSwap(quoteAmount);
}

/// @notice reverts, where the revert data is the provided bytes
/// @notice reverts using the revertData as the reason
/// @dev to bubble up both the valid QuoteSwap(amount) error, or an alternative error thrown during simulation
function bubbleReason(bytes memory revertData) internal pure {
// mload(revertData): the length of the revert data
// add(revertData, 0x20): a pointer to the start of the revert data
Expand All @@ -28,28 +30,20 @@ library QuoterRevert {
}
}

/// @notice check revert reasons are of the expected length; otherwise revert with different message
/// @dev called after a swap simulation reverts, to check if the revert was valid encoded quote information, or an internal issue
function validateRevertReason(bytes memory reason) internal pure {
/// @notice validates whether a revert reason is a valid swap quote or not
/// if valid, it decodes the quote to return. Otherwise it reverts.
function parseQuoteAmount(bytes memory reason) internal pure returns (uint256 quoteAmount) {
// If the error doesnt start with QuoteSwap, we know this isnt a valid quote to parse
// Instead it is another revert that was triggered somewhere in the simulation
if (reason.parseSelector() != QuoteSwap.selector) {
revert UnexpectedRevertBytes(reason);
}
}

/// @notice validates a received revert reason from a swap.
/// Then, if valid, decodes it into the information generated by a quote
function parseReturnData(bytes memory reason) internal pure returns (uint256) {
reason.validateRevertReason();
return reason.parseAmountUnspecified();
}

/// @notice extracts the amountUnspecified from an encoded QuoteSwap(amountUnspecified)
function parseAmountUnspecified(bytes memory reason) internal pure returns (uint256 amountUnspecified) {
// reason -> reason+0x1f is the length of the reason string
// reason+0x20 -> reason+0x23 is the selector of QuoteSwap
// reason+0x24 -> reason+0x43 is the amountUnspecified
// reason+0x24 -> reason+0x43 is the quoteAmount
assembly ("memory-safe") {
amountUnspecified := mload(add(reason, 0x24))
quoteAmount := mload(add(reason, 0x24))
}
}
}

0 comments on commit e84c8fc

Please sign in to comment.