Skip to content

Commit

Permalink
Feat/quoter mixed exact out non v4 (#13)
Browse files Browse the repository at this point in the history
* feat: Rename QuoteExactInputSingleV2Params

* feat: Rename QuoteExactInputSingleV3Params

* feat: Rename QuoteExactInputSingleStableParams

* feat: Rename QuoteMixedV4ExactInputSingleParams
  • Loading branch information
ChefSnoopy authored Aug 28, 2024
1 parent eec94f1 commit e0f042a
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 98 deletions.
48 changes: 19 additions & 29 deletions src/MixedQuoter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ contract MixedQuoter is IMixedQuoter, IPancakeV3SwapCallback {
}

/// @dev Fetch an exactIn quote for a V3 Pool on chain
function quoteExactInputSingleV3(QuoteExactInputSingleV3Params memory params)
function quoteExactInputSingleV3(QuoteExactSingleV3Params memory params)
public
override
returns (uint256 amountOut, uint160 sqrtPriceX96After, uint32 initializedTicksCrossed, uint256 gasEstimate)
Expand All @@ -135,7 +135,7 @@ contract MixedQuoter is IMixedQuoter, IPancakeV3SwapCallback {
try pool.swap(
address(this), // address(0) might cause issues with some tokens
zeroForOne,
params.amountIn.toInt256(),
params.exactAmount.toInt256(),
params.sqrtPriceLimitX96 == 0
? (zeroForOne ? TickMath.MIN_SQRT_RATIO + 1 : TickMath.MAX_SQRT_RATIO - 1)
: params.sqrtPriceLimitX96,
Expand All @@ -151,31 +151,31 @@ contract MixedQuoter is IMixedQuoter, IPancakeV3SwapCallback {
*/

/// @dev Fetch an exactIn quote for a V2 pair on chain
function quoteExactInputSingleV2(QuoteExactInputSingleV2Params memory params)
function quoteExactInputSingleV2(QuoteExactSingleV2Params memory params)
public
view
override
returns (uint256 amountOut)
{
(uint256 reserveIn, uint256 reserveOut) =
V3SmartRouterHelper.getReserves(factoryV2, params.tokenIn, params.tokenOut);
amountOut = V3SmartRouterHelper.getAmountOut(params.amountIn, reserveIn, reserveOut);
amountOut = V3SmartRouterHelper.getAmountOut(params.exactAmount, reserveIn, reserveOut);
}

/**
* Stable *************************************************
*/

/// @dev Fetch an exactIn quote for a Stable pair on chain
function quoteExactInputSingleStable(QuoteExactInputSingleStableParams memory params)
function quoteExactInputSingleStable(QuoteExactInputStableParams memory params)
public
view
override
returns (uint256 amountOut)
{
(uint256 i, uint256 j, address swapContract) =
V3SmartRouterHelper.getStableInfo(factoryStable, params.tokenIn, params.tokenOut, params.flag);
amountOut = IStableSwap(swapContract).get_dy(i, j, params.amountIn);
amountOut = IStableSwap(swapContract).get_dy(i, j, params.exactAmount);
}

/**
Expand All @@ -201,25 +201,25 @@ contract MixedQuoter is IMixedQuoter, IPancakeV3SwapCallback {
(tokenIn, tokenOut) = convertNativeToWETH(tokenIn, tokenOut);
// params[actionIndex] is zero bytes
amountIn = quoteExactInputSingleV2(
QuoteExactInputSingleV2Params({tokenIn: tokenIn, tokenOut: tokenOut, amountIn: amountIn})
QuoteExactSingleV2Params({tokenIn: tokenIn, tokenOut: tokenOut, exactAmount: amountIn})
);
} else if (action == MixedQuoterActions.V3_EXACT_INPUT_SINGLE) {
(tokenIn, tokenOut) = convertNativeToWETH(tokenIn, tokenOut);
// params[actionIndex]: abi.encode(fee)
uint24 fee = abi.decode(params[actionIndex], (uint24));
(uint256 _amountOut,,,) = quoteExactInputSingleV3(
QuoteExactInputSingleV3Params({
QuoteExactSingleV3Params({
tokenIn: tokenIn,
tokenOut: tokenOut,
amountIn: amountIn,
exactAmount: amountIn,
fee: fee,
sqrtPriceLimitX96: 0
})
);
amountIn = _amountOut;
} else if (action == MixedQuoterActions.V4_CL_EXACT_INPUT_SINGLE) {
QuoteMixedV4ExactInputSingleParams memory clParams =
abi.decode(params[actionIndex], (QuoteMixedV4ExactInputSingleParams));
QuoteMixedV4ExactSingleParams memory clParams =
abi.decode(params[actionIndex], (QuoteMixedV4ExactSingleParams));
(tokenIn, tokenOut) = convertWETHToV4NativeCurency(clParams.poolKey, tokenIn, tokenOut);
bool zeroForOne = tokenIn < tokenOut;
checkV4PoolKeyCurrency(clParams.poolKey, zeroForOne, tokenIn, tokenOut);
Expand All @@ -234,8 +234,8 @@ contract MixedQuoter is IMixedQuoter, IPancakeV3SwapCallback {
);
amountIn = deltaAmounts[zeroForOne ? 1 : 0].toUint256();
} else if (action == MixedQuoterActions.V4_BIN_EXACT_INPUT_SINGLE) {
QuoteMixedV4ExactInputSingleParams memory binParams =
abi.decode(params[actionIndex], (QuoteMixedV4ExactInputSingleParams));
QuoteMixedV4ExactSingleParams memory binParams =
abi.decode(params[actionIndex], (QuoteMixedV4ExactSingleParams));
(tokenIn, tokenOut) = convertWETHToV4NativeCurency(binParams.poolKey, tokenIn, tokenOut);
bool zeroForOne = tokenIn < tokenOut;
checkV4PoolKeyCurrency(binParams.poolKey, zeroForOne, tokenIn, tokenOut);
Expand All @@ -252,23 +252,13 @@ contract MixedQuoter is IMixedQuoter, IPancakeV3SwapCallback {
(tokenIn, tokenOut) = convertNativeToWETH(tokenIn, tokenOut);
// params[actionIndex] is zero bytes
amountIn = quoteExactInputSingleStable(
QuoteExactInputSingleStableParams({
tokenIn: tokenIn,
tokenOut: tokenOut,
amountIn: amountIn,
flag: 2
})
QuoteExactInputStableParams({tokenIn: tokenIn, tokenOut: tokenOut, exactAmount: amountIn, flag: 2})
);
} else if (action == MixedQuoterActions.SS_3_EXACT_INPUT_SINGLE) {
(tokenIn, tokenOut) = convertNativeToWETH(tokenIn, tokenOut);
// params[actionIndex] is zero bytes
amountIn = quoteExactInputSingleStable(
QuoteExactInputSingleStableParams({
tokenIn: tokenIn,
tokenOut: tokenOut,
amountIn: amountIn,
flag: 3
})
QuoteExactInputStableParams({tokenIn: tokenIn, tokenOut: tokenOut, exactAmount: amountIn, flag: 3})
);
} else {
revert UnsupportedAction(action);
Expand All @@ -294,8 +284,8 @@ contract MixedQuoter is IMixedQuoter, IPancakeV3SwapCallback {

uint256 action = uint256(uint8(actions[actionIndex - 1]));
if (action == MixedQuoterActions.V4_CL_EXACT_OUTPUT_SINGLE) {
QuoteMixedV4ExactInputSingleParams memory clParams =
abi.decode(params[actionIndex - 1], (QuoteMixedV4ExactInputSingleParams));
QuoteMixedV4ExactSingleParams memory clParams =
abi.decode(params[actionIndex - 1], (QuoteMixedV4ExactSingleParams));
bool zeroForOne = tokenIn < tokenOut;
checkV4PoolKeyCurrency(clParams.poolKey, zeroForOne, tokenIn, tokenOut);
(int128[] memory deltaAmounts,,) = clQuoter.quoteExactOutputSingle(
Expand All @@ -309,8 +299,8 @@ contract MixedQuoter is IMixedQuoter, IPancakeV3SwapCallback {
);
amountOut = uint256(int256(-deltaAmounts[zeroForOne ? 0 : 1]));
} else if (action == MixedQuoterActions.V4_BIN_EXACT_OUTPUT_SINGLE) {
QuoteMixedV4ExactInputSingleParams memory binParams =
abi.decode(params[actionIndex - 1], (QuoteMixedV4ExactInputSingleParams));
QuoteMixedV4ExactSingleParams memory binParams =
abi.decode(params[actionIndex - 1], (QuoteMixedV4ExactSingleParams));
bool zeroForOne = tokenIn < tokenOut;
checkV4PoolKeyCurrency(binParams.poolKey, zeroForOne, tokenIn, tokenOut);
(int128[] memory deltaAmounts,) = binQuoter.quoteExactOutputSingle(
Expand Down
40 changes: 19 additions & 21 deletions src/interfaces/IMixedQuoter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -16,29 +16,29 @@ interface IMixedQuoter {
error NoActions();
error UnsupportedAction(uint256 action);

struct QuoteMixedV4ExactInputSingleParams {
struct QuoteMixedV4ExactSingleParams {
PoolKey poolKey;
bytes hookData;
}

struct QuoteExactInputSingleV3Params {
struct QuoteExactSingleV3Params {
address tokenIn;
address tokenOut;
uint256 amountIn;
uint256 exactAmount;
uint24 fee;
uint160 sqrtPriceLimitX96;
}

struct QuoteExactInputSingleV2Params {
struct QuoteExactSingleV2Params {
address tokenIn;
address tokenOut;
uint256 amountIn;
uint256 exactAmount;
}

struct QuoteExactInputSingleStableParams {
struct QuoteExactInputStableParams {
address tokenIn;
address tokenOut;
uint256 amountIn;
uint256 exactAmount;
uint256 flag;
}

Expand All @@ -50,8 +50,8 @@ interface IMixedQuoter {
/// SS_3_EXACT_INPUT_SINGLE params are zero bytes
/// V2_EXACT_INPUT_SINGLE params are zero bytes
/// V3_EXACT_INPUT_SINGLE params are encoded as `uint24 fee`
/// V4_CL_EXACT_INPUT_SINGLE params are encoded as `QuoteMixedV4ExactInputSingleParams`
/// V4_BIN_EXACT_INPUT_SINGLE params are encoded as `QuoteMixedV4ExactInputSingleParams`
/// V4_CL_EXACT_INPUT_SINGLE params are encoded as `QuoteMixedV4ExactSingleParams`
/// V4_BIN_EXACT_INPUT_SINGLE params are encoded as `QuoteMixedV4ExactSingleParams`
/// @param amountIn The amount of the first token to swap
/// @return amountOut The amount of the last token that would be received
function quoteMixedExactInput(
Expand All @@ -65,8 +65,8 @@ interface IMixedQuoter {
/// @param paths The path of the swap, i.e. each token pair in the path
/// @param actions The actions to take for each pair in the path
/// @param params The params for each action in the path
/// V4_CL_EXACT_OUTPUT_SINGLE params are encoded as `QuoteMixedV4ExactInputSingleParams`
/// V4_BIN_EXACT_OUTPUT_SINGLE params are encoded as `QuoteMixedV4ExactInputSingleParams`
/// V4_CL_EXACT_OUTPUT_SINGLE params are encoded as `QuoteMixedV4ExactSingleParams`
/// V4_BIN_EXACT_OUTPUT_SINGLE params are encoded as `QuoteMixedV4ExactSingleParams`
/// @param amountOut The amount of the last token to receive
/// @return amountIn The amount of first token required to be paid
function quoteMixedExactOutput(
Expand All @@ -81,34 +81,32 @@ interface IMixedQuoter {
/// 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
/// exactAmount 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 quoteExactInputSingleV3(QuoteExactInputSingleV3Params memory params)
function quoteExactInputSingleV3(QuoteExactSingleV3Params memory params)
external
returns (uint256 amountOut, uint160 sqrtPriceX96After, uint32 initializedTicksCrossed, uint256 gasEstimate);

/// @notice Returns the amount out received for a given exact input but for a swap of a single V2 pool
/// @param params The params for the quote, encoded as `QuoteExactInputSingleV2Params`
/// @param params The params for the quote, encoded as `QuoteExactSingleV2Params`
/// tokenIn The token being swapped in
/// tokenOut The token being swapped out
/// amountIn The desired input amount
/// exactAmount The desired input amount
/// @return amountOut The amount of `tokenOut` that would be received
function quoteExactInputSingleV2(QuoteExactInputSingleV2Params memory params)
external
returns (uint256 amountOut);
function quoteExactInputSingleV2(QuoteExactSingleV2Params memory params) external returns (uint256 amountOut);

/// @notice Returns the amount out received for a given exact input but for a swap of a single Stable pool
/// @param params The params for the quote, encoded as `QuoteExactInputSingleStableParams`
/// @param params The params for the quote, encoded as `QuoteExactInputStableParams`
/// tokenIn The token being swapped in
/// tokenOut The token being swapped out
/// amountIn The desired input amount
/// exactAmount The desired input amount
/// flag The token amount in a single Stable pool. 2 for 2pool, 3 for 3pool
/// @return amountOut The amount of `tokenOut` that would be received
function quoteExactInputSingleStable(QuoteExactInputSingleStableParams memory params)
function quoteExactInputSingleStable(QuoteExactInputStableParams memory params)
external
returns (uint256 amountOut);

Expand Down
15 changes: 0 additions & 15 deletions src/libraries/external/V3SmartRouterHelper.sol
Original file line number Diff line number Diff line change
Expand Up @@ -100,21 +100,6 @@ library V3SmartRouterHelper {
amountIn = (numerator / denominator) + 1;
}

// performs chained getAmountIn calculations on any number of pairs
function getAmountsIn(address factory, uint256 amountOut, address[] memory path)
internal
view
returns (uint256[] memory amounts)
{
require(path.length >= 2);
amounts = new uint256[](path.length);
amounts[amounts.length - 1] = amountOut;
for (uint256 i = path.length - 1; i > 0; i--) {
(uint256 reserveIn, uint256 reserveOut) = getReserves(factory, path[i - 1], path[i]);
amounts[i - 1] = getAmountIn(amounts[i], reserveIn, reserveOut);
}
}

/**
* V3 *************************************************
*/
Expand Down
Loading

0 comments on commit e0f042a

Please sign in to comment.