PulseStrategyModule
Overview
The PulseStrategyModule
provides liquidity management strategies within Automated Market Makers (AMMs). It supports various strategies tailored for different market trends, optimizing liquidity positioning through minimal yet effective rebalancing. Key components include managing penalty calculations and target setting to optimize the interval for liquidity deployment.
Errors
InvalidParams()
: Raised when parameters provided to a strategy function are outside expected bounds.InvalidLength()
: Triggered when an input array has an incorrect length, typically related to market data or strategy parameters.
Enums
StrategyType
Identifies the strategy applied to manage and rebalance liquidity positions:
Original
: This is the classic strategy where the position is actively managed within an interval[tickLower, tickUpper]
. If the market tick moves outside an interval[tickLower + tickNeighborhood, tickUpper - tickNeighborhood]
, a rebalance is triggered to center the position as closely as possible to the current tick, maintaining the same width. This ensures the position remains effectively aligned with the market.LazySyncing
: Supports active position management within the[tickLower, tickUpper]
interval, with rebalancing actions triggered under two scenarios:If the
current tick
<tickLower
, rebalance to a new position closest to the current tick on the right side, with the same width.If the
current tick
>tickUpper
, rebalance to a new position closest to the current tick on the left side, with the same width. This strategy aims to realign the position with the market with minimal adjustments.
LazyAscending
: Similar to LazySyncing but specifically focuses on ascending market conditions. If the current tick is less thantickLower
, it does not trigger a rebalance. Rebalancing is considered only when the market moves upwards beyond thetickUpper
, aiming to catch upward trends without reacting to downward movements.LazyDescending
: Opposite to LazyAscending, this strategy caters to descending market conditions. If the current tick is greater thantickUpper
, it does not prompt a rebalance. The strategy focuses on rebalancing when the market descends belowtickLower
, aiming to manage downward trends without reacting to upward movements.Tamper
: Is a strategy for the stable pair of tokens like WETH/WSTETH, which works on top of the corresponding pool. It holds two crossing positions in this pool, changing them and rebalancing liquidity between them depending on the price in the pool.
Structs
StrategyParams
Defines required parameters for each strategy, including key elements that drive rebalancing decisions:
strategyType: The active strategy type.
tickNeighborhood: A range around tick values that prompts rebalancing.
tickSpacing: Defines spacing between ticks in the AMM pool.
width: Width of the interval for liquidity placement post-rebalance.
calculateTarget(int24 tick, int24 tickLower, int24 tickUpper, StrategyParams memory params)
calculateTarget(int24 tick, int24 tickLower, int24 tickUpper, StrategyParams memory params)
Description: Determines the target position and rebalancing requirements based on the current tick and strategy parameters.
Parameters:
tick
: The current market tick, representing the price level.tickLower
: The lower tick boundary of the existing position.tickUpper
: The upper tick boundary of the existing position.params
: Contains strategy-specific parameters, including the strategy type and rebalancing criteria.
Returns:
isRebalanceRequired
: Boolean indicating if a rebalance is needed based on the strategy.target
: Details of the new position (tick bounds) if rebalancing occurs.
Logic: The function dynamically assesses the need for rebalancing based on the
StrategyType
selected and the current market tick's position relative to the existing liquidity interval. It then calculates the optimal target position parameters to realign the position with the chosen strategy and prevailing market conditions.
function calculateTargetPulse(uint160 sqrtPriceX96, int24 tick, IAmmModule.AmmPosition[] memory positions, IPulseStrategyModule.StrategyParams memory params) public pure returns (bool isRebalanceRequired, ICore.TargetPositionInfo memory target)
function calculateTargetPulse(uint160 sqrtPriceX96, int24 tick, IAmmModule.AmmPosition[] memory positions, IPulseStrategyModule.StrategyParams memory params) public pure returns (bool isRebalanceRequired, ICore.TargetPositionInfo memory target)
The calculateTargetPulse
function efficiently determines if the current AMM positions require rebalancing based on price boundaries and strategy parameters. When rebalancing is needed, it provides a target position with updated price ranges and liquidity ratios, allowing for dynamic and adaptive position management within the AMM. The function operates in a pure, stateless manner, making it reliable and consistent for real-time position assessments.
Purpose:
This function checks whether rebalancing is necessary for a set of AMM positions and, if so, calculates the target position details required for rebalancing.
Parameters:
sqrtPriceX96
: The current square root price in Q96 format, used to determine price boundaries.tick
: The current tick, representing the nearest price point.positions
: An array of existingAmmPosition
data for the managed position, specifying the range and liquidity of each position.params
: Strategy parameters, defining rules for when and how rebalancing should occur.
Returns:
isRebalanceRequired
: A boolean indicating if rebalancing is needed.target
: ATargetPositionInfo
struct with the calculated position details, including new price ranges and liquidity ratios for rebalancing.
Execution Flow
Initialize Rebalance Check:
Initializes
tickLower
andtickUpper
, which represent the price range of the current position.Sets
isRebalanceRequired
totrue
if there are no existing positions or more than one, as this indicates a need to update or consolidate the position.
Position Boundary Check:
If there is exactly one position, the function retrieves the
tickLower
andtickUpper
values from this position, establishing the current boundaries.Calls
calculatePulsePosition
to compute the target tick range (targetTickLower
andtargetTickUpper
) based on the current price (sqrtPriceX96
), tick, existing boundaries, and strategy parameters.
Target Position Comparison:
Compares
targetTickLower
andtargetTickUpper
with the existingtickLower
andtickUpper
.If the calculated target ticks match the existing ticks, the function returns with
isRebalanceRequired
set tofalse
and an emptytarget
struct, as rebalancing is unnecessary.
Set Target Position for Rebalancing:
If rebalancing is required, the function populates the
target
struct with:lowerTicks
andupperTicks
: Arrays holding the target tick boundaries.liquidityRatiosX96
: An array with the liquidity ratio set toQ96
(a scaling factor of 1), assuming equal liquidity across the entire range.
Return Rebalance Required Flag:
Sets
isRebalanceRequired
totrue
, confirming that rebalancing is needed with the newly calculatedtarget
values.
function calculateTamperPosition(uint160 sqrtPriceX96, int24 tick, int24 width) public pure returns (int24 targetLower, uint256 lowerLiquidityRatioX96)
function calculateTamperPosition(uint160 sqrtPriceX96, int24 tick, int24 width) public pure returns (int24 targetLower, uint256 lowerLiquidityRatioX96)
The calculateTamperPosition
function determines the lower boundary and liquidity allocation for a position based on the current price, tick, and width parameters. It uses interpolation and the TickMath
library to accurately place liquidity, allocating more to the lower range if the current price is near the bottom half of the target range. The function provides dynamic liquidity control, adjusting allocation smoothly as the price shifts within the specified boundaries.
Purpose:
Calculates the lower boundary (
targetLower
) of the target position and the liquidity ratio for the lower range (lowerLiquidityRatioX96
) based on the current price and a specified width around the position’s current tick.
Parameters:
sqrtPriceX96
: The current square root price in Q96 format, which helps determine where the current price lies within the target range.tick
: The current tick of the position, representing the closest price point.width
: The width of the position range, which defines how far above and below the current tick the position will span.
Returns:
targetLower
: The lower tick boundary of the target position.lowerLiquidityRatioX96
: The liquidity ratio for the lower range in Q96 format, indicating the proportion of liquidity allocated to the lower part of the range.
Execution Flow
Initial Calculation of
targetLower
:Calculates half of the specified
width
to find a centered position range.Calls
calculateCenteredPosition
, passingsqrtPriceX96
,tick
,width + half
, andhalf
, to determinetargetLower
, the lower boundary of the target range.
Calculate Center Price:
Computes
sqrtPriceCenterX96
, the square root price at the midpoint tick (targetLower + half
) usingTickMath.getSqrtRatioAtTick
.This value serves as a reference point to compare the current price with the center of the target range.
Determine
lowerLiquidityRatioX96
Based on Price Position:Case 1: If
sqrtPriceX96
(current price) is less than or equal tosqrtPriceCenterX96
, setlowerLiquidityRatioX96
toQ96
, indicating full liquidity allocation to the lower range.Case 2: If
sqrtPriceX96
is greater than or equal to the price attargetLower + width
, setlowerLiquidityRatioX96
to0
, indicating no liquidity in the lower range.Case 3: If
sqrtPriceX96
lies within the range[targetLower + half, targetLower + width]
:Calculate
preciseTickX96
, a precise tick position based on linear interpolation ofsqrtPriceX96
betweentick
andtick + 1
.Calculate
deduction
, a value based on how farpreciseTickX96
deviates from the center of the lower range, and normalize it toQ96
.Set
lowerLiquidityRatioX96
toQ96 - deduction
, ensuring that the liquidity ratio decreases gradually as the price approaches the upper boundary of the lower range.
calculatePenalty(uint160 sqrtPriceX96, uint160 sqrtPriceX96Lower, uint160 sqrtPriceX96Upper)
calculatePenalty(uint160 sqrtPriceX96, uint160 sqrtPriceX96Lower, uint160 sqrtPriceX96Upper)
Description: Calculates a penalty based on whether the current price (
sqrtPriceX96
) is within a given range defined bysqrtPriceX96Lower
andsqrtPriceX96Upper
.Parameters:
sqrtPriceX96
: The current market price in Q96 fixed-point format.sqrtPriceX96Lower
: The lower bound of the acceptable price range in Q96 format.sqrtPriceX96Upper
: The upper bound of the acceptable price range in Q96 format.
Returns: The penalty value, which is
type(uint256).max
if the price is outside the range, otherwise calculated based on distance from bounds.
function validateStrategyParams(bytes memory params_)
function validateStrategyParams(bytes memory params_)
The validateStrategyParams
function ensures that the provided strategy parameters are consistent, valid, and tailored to the chosen strategy type. Each parameter is rigorously checked to prevent invalid configurations, and specific conditions are enforced for different strategies, especially for Tamper
, which has unique requirements. If any check fails, the function provides immediate feedback by reverting with an appropriate error.
Purpose:
Validates the structure and values of the strategy parameters provided in
params_
. Ensures that each parameter meets specific conditions based on the strategy type to prevent misconfigurations.
Parameters:
params_
: Encoded bytes representingStrategyParams
. These include settings like width, tick spacing, strategy type, tick neighborhood, and liquidity deviation.
Execution Flow
Length Check:
Validates that
params_
has a length of0xa0
bytes (160 bytes). If not, it reverts with anInvalidLength
error, ensuring the data structure is the expected size.
Decode Parameters:
Decodes
params_
into aStrategyParams
struct, making it easier to work with each parameter individually.
Basic Parameter Validations:
Checks if:
width
andtickSpacing
are both non-zero.width
is evenly divisible bytickSpacing
.strategyType
is a valid value within theStrategyType
enum, specifically less than or equal toTamper
.
If any of these checks fail, the function reverts with an
InvalidParams
error.
Strategy Type-Specific Validations:
Original Strategy:
Allows
tickNeighborhood
to be a non-zero (possibly negative) value.Checks that
tickNeighborhood * 2
does not exceedwidth
, ensuring the neighborhood is within bounds of the width.If this condition fails, it reverts with
InvalidParams
.
Other Strategies:
Ensures
tickNeighborhood
is zero if the strategy type is notOriginal
. Any non-zero value results inInvalidParams
.
Tamper Strategy:
Checks additional conditions specific to the
Tamper
strategy:width
must be even.width / 2
must be evenly divisible bytickSpacing
.maxLiquidityRatioDeviationX96
should be a positive number less thanQ96
(representing 1 in Q96 format).
If any condition fails, the function reverts with
InvalidParams
.
Non-Tamper Strategies:
Ensures
maxLiquidityRatioDeviationX96
is zero, as it’s only relevant toTamper
. Any non-zero value results inInvalidParams
.
Last updated