Skip to content

Commit

Permalink
fix various issues with quoter and the tests
Browse files Browse the repository at this point in the history
  • Loading branch information
sparrowDom committed Oct 18, 2024
1 parent a9f4d28 commit 946061a
Show file tree
Hide file tree
Showing 4 changed files with 139 additions and 137 deletions.
5 changes: 5 additions & 0 deletions contracts/contracts/interfaces/aerodrome/IAMOStrategy.sol
Original file line number Diff line number Diff line change
Expand Up @@ -59,4 +59,9 @@ interface IAMOStrategy {
function claimGovernance() external;

function transferGovernance(address _governor) external;

function getPositionPrincipal()
external
view
returns (uint256 _amountWeth, uint256 _amountOethb);
}
Original file line number Diff line number Diff line change
Expand Up @@ -482,11 +482,10 @@ contract AerodromeAMOStrategy is InitializableAbstractStrategy {
* @param _amountToSwap The amount of the token to swap
* @param _swapWeth Swap using WETH when true, use OETHb when false
*/
function _removeLiquidityToEnsureSwap(
uint256 _amountToSwap,
bool _swapWeth
) internal {
// swapping OETHb to WETH doesn't require liquidity removal or when there
function _removeLiquidityToEnsureSwap(uint256 _amountToSwap, bool _swapWeth)
internal
{
// swapping OETHb to WETH doesn't require liquidity removal or when there
// is no amount to be swapped
if (!_swapWeth || _amountToSwap == 0) {
return;
Expand Down
110 changes: 51 additions & 59 deletions contracts/contracts/utils/AerodromeAMOQuoter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,10 @@ contract QuoterHelper {
/// --- CONSTANT & IMMUTABLE
////////////////////////////////////////////////////////////////
uint256 public constant BINARY_MIN_AMOUNT = 1 wei;
uint256 public constant BINARY_MAX_AMOUNT_FOR_REBALANCE = 3_000 ether;
uint256 public constant BINARY_MAX_AMOUNT_FOR_PUSH_PRICE = 5_000_000 ether;

uint256 public constant BINARY_MAX_ITERATIONS = 100;
uint256 public constant BINARY_MAX_ITERATIONS = 40;
uint256 public constant PERCENTAGE_BASE = 1e18; // 100%
uint256 public constant ALLOWED_VARIANCE_PERCENTAGE = 1e12; // 0.0001%
uint256 public constant ALLOWED_VARIANCE_PERCENTAGE = 1e15; // 0.1%

////////////////////////////////////////////////////////////////
/// --- VARIABLES STORAGE
Expand Down Expand Up @@ -83,27 +81,15 @@ contract QuoterHelper {
uint256 overrideBottomWethShare,
uint256 overrideTopWethShare
) public {
if (
overrideBottomWethShare != type(uint256).max ||
overrideTopWethShare != type(uint256).max
) {
// Current values
uint256 shareStart = strategy.allowedWethShareStart();
uint256 shareEnd = strategy.allowedWethShareEnd();

// Override values
if (overrideBottomWethShare != type(uint256).max) {
shareStart = overrideBottomWethShare;
}
if (overrideTopWethShare != type(uint256).max) {
shareEnd = overrideTopWethShare;
}
strategy.setAllowedPoolWethShareInterval(
overrideBottomWethShare,
overrideTopWethShare
);

strategy.setAllowedPoolWethShareInterval(shareStart, shareEnd);
}
uint256 iterations = 0;
uint256 low = BINARY_MIN_AMOUNT;
uint256 high = BINARY_MAX_AMOUNT_FOR_REBALANCE;
uint256 high;
(high, ) = strategy.getPositionPrincipal();
int24 lowerTick = strategy.lowerTick();
int24 upperTick = strategy.upperTick();
bool swapWETHForOETHB = getSwapDirectionForRebalance();
Expand Down Expand Up @@ -338,6 +324,14 @@ contract QuoterHelper {
return currentPrice > targetPrice;
}

// returns total amount in the position principal of the Aerodrome AMO strategy. Needed as a
// separate function because of the limitation in local variable count in getAmountToSwapToReachPrice
function getTotalStrategyPosition() internal returns (uint256) {
(uint256 wethAmount, uint256 oethBalance) = strategy
.getPositionPrincipal();
return wethAmount + oethBalance;
}

/// @notice Get the amount of tokens to swap to reach the target price.
/// @dev This act like a quoter, i.e. the transaction is not performed.
/// @dev Because the amount to swap can be largely overestimated, because CLAMM alow partial orders,
Expand All @@ -359,34 +353,53 @@ contract QuoterHelper {
{
uint256 iterations = 0;
uint256 low = BINARY_MIN_AMOUNT;
uint256 high = BINARY_MAX_AMOUNT_FOR_PUSH_PRICE;
// high search start is twice the position principle of Aerodrome AMO strategy.
// should be more than enough
uint256 high = getTotalStrategyPosition() * 2;
bool swapWETHForOETHB = getSwapDirection(sqrtPriceTargetX96);

while (low <= high && iterations < BINARY_MAX_ITERATIONS) {
uint256 mid = (low + high) / 2;

// Call QuoterV2 from SugarHelper
(, uint160 sqrtPriceX96After, , ) = quoterV2.quoteExactInputSingle(
IQuoterV2.QuoteExactInputSingleParams({
tokenIn: swapWETHForOETHB
? clPool.token0()
: clPool.token1(),
tokenOut: swapWETHForOETHB
? clPool.token1()
: clPool.token0(),
amountIn: mid,
tickSpacing: strategy.tickSpacing(),
sqrtPriceLimitX96: sqrtPriceTargetX96
})
);
(uint256 amountOut, uint160 sqrtPriceX96After, , ) = quoterV2
.quoteExactInputSingle(
IQuoterV2.QuoteExactInputSingleParams({
tokenIn: swapWETHForOETHB
? clPool.token0()
: clPool.token1(),
tokenOut: swapWETHForOETHB
? clPool.token1()
: clPool.token0(),
amountIn: mid,
tickSpacing: strategy.tickSpacing(),
sqrtPriceLimitX96: sqrtPriceTargetX96
})
);

if (
isWithinAllowedVariance(sqrtPriceX96After, sqrtPriceTargetX96)
) {
return (mid, iterations, swapWETHForOETHB, sqrtPriceX96After);
/** Very important to return `amountOut` instead of `mid` as the first return parameter.
* The issues was that when quoting we impose a swap price limit (sqrtPriceLimitX96: sqrtPriceTargetX96)
* and in that case the `amountIn` acts like a maximum amount to swap. And we don't know how much
* of that amount was actually consumed. For that reason we "estimate" it by returning the
* amountOut since that is only going to be a couple of basis point away from amountIn in the
* worst cases.
*
* Note: we could be returning mid instead of amountOut in cases when those values are only basis
* points apart (assuming that complete balance of amountIn has been consumed) but that might increase
* complexity too much in an already complex contract.
*/
return (
amountOut,
iterations,
swapWETHForOETHB,
sqrtPriceX96After
);
} else if (low == high) {
// target swap amount not found.
// try increasing BINARY_MAX_AMOUNT_FOR_PUSH_PRICE
// might be that "high" amount is too low on start
revert("SwapAmountNotFound");
} else if (
swapWETHForOETHB
Expand Down Expand Up @@ -487,32 +500,12 @@ contract AerodromeAMOQuoter {
);
event ValueNotFound(string message);

////////////////////////////////////////////////////////////////
/// --- FUNCTIONS
////////////////////////////////////////////////////////////////
/// @notice Use this to get the amount to swap before rebalance
/// @dev This call will only revert, check the logs to get returned values.
/// @dev Need to perform this call while impersonating the governor or strategist of AMO.
/// @return data Data struct with the amount and the number of iterations
function quoteAmountToSwapBeforeRebalance()
public
returns (Data memory data)
{
return
_quoteAmountToSwapBeforeRebalance(
type(uint256).max,
type(uint256).max
);
}

/// @notice Use this to get the amount to swap before rebalance and
/// update allowedWethShareStart and allowedWethShareEnd on AMO.
/// @dev This call will only revert, check the logs to get returned values.
/// @dev Need to perform this call while impersonating the governor of AMO.
/// @param overrideBottomWethShare New value for the allowedWethShareStart on AMO.
/// Use type(uint256).max to keep same value.
/// @param overrideTopWethShare New value for the allowedWethShareEnd on AMO.
/// Use type(uint256).max to keep same value.
/// @return data Data struct with the amount and the number of iterations
function quoteAmountToSwapBeforeRebalance(
uint256 overrideBottomWethShare,
Expand All @@ -539,7 +532,6 @@ contract AerodromeAMOQuoter {
revert("Previous call should only revert, it cannot succeed");
} catch (bytes memory reason) {
bytes4 receivedSelector = bytes4(reason);

if (receivedSelector == QuoterHelper.ValidAmount.selector) {
uint256 value;
uint256 iterations;
Expand Down
Loading

0 comments on commit 946061a

Please sign in to comment.