Changelog
Summary
The depth bands feature replaces the simple “1% depth” price impact model with a 30-band system that provides granular control over price impact curves. This enhancement allows for more realistic market depth modeling.Added
New Features
- 30 configurable bands (0-29) representing different liquidity depths
- Piecewise calculation using trapezoidal rule for smooth price impact curves
- Linear extrapolation beyond 100% depth for very large trades
- Separate depth configurations for longs (above) and shorts (below)
- Efficient storage packing: all band data in 2 slots per direction
- Non-decreasing validation for band liquidity/offset values
New Data Structures
IPriceImpact.PairDepthBands- Stores depth band liquidity configuration for each pair (4 slots: above/below × slot1/slot2)IPriceImpact.DepthBandsMapping- Global mapping of band indices to band percentage offsets from mid price (2 slots)IPriceImpact.DepthBandParameters- Working struct for depth band calculations
New Functions
initializeDepthBandsMapping(uint256 slot1, uint256 slot2)- Initialize global bands offset mapping (reinitializer(25))setPairDepthBands(uint256[] indices, PairDepthBands[] depthBands)- Set depth bands liquidity for multiple pairssetDepthBandsMapping(uint256 slot1, uint256 slot2)- Configure global bands offset valuesgetPairDepthBands(uint256 pairIndex)- Get single pair’s encoded depth bandsgetPairDepthBands(uint256[] indices)- Get multiple pairs’ encoded depth bands (array version)getPairDepthBandsDecoded(uint256 pairIndex)- Get single pair’s decoded depth bandsgetPairDepthBandsDecoded(uint256[] indices)- Get multiple pairs’ decoded depth bands (array version)getDepthBandsMapping()- Get global bands encoded mappinggetDepthBandsMappingDecoded()- Get global bands decoded mapping
New Internal Functions
_getDepthBandsPriceImpactP()- New price impact getter using depth bands_getTotalDepthUsd()- Extract total depth usd from encoded slot_getBandValue()- Extract band value from encoded slots (returns ppm for mappings, bps for depths)_calculateDepthBandsPriceImpact()- Core calculation using trapezoidal rule for average fill price
New Constants
DEPTH_BANDS_COUNT = 30- Total number of depth bandsDEPTH_BANDS_PER_SLOT1 = 14- Number of bands stored in slot1HUNDRED_P_BPS = 1e4- 100% in bps
Changed
Libraries
PriceImpactUtilsis now external and has been adjusted for the new bands feature
Modified Functions
getTradeCumulVolPriceImpactP()- Now forwards to_getDepthBandsPriceImpactPimplementation using depth bands
Storage Updates
IPriceImpact.PriceImpactStoragestruct updated:- Added
mapping(uint256 => PairDepthBands) pairDepthBands - Added
DepthBandsMapping depthBandsMapping - Reduced
__gaparray to [36] to accommodate new storage
- Added
Deprecated
Storage
pairDepths- Replaced bypairDepthBands
Removed
Functions
setPairDepths()- Replaced bysetPairDepthBands()getPairDepth()- Replaced bygetPairDepthBands()getPairDepths()- Replaced by array version ofgetPairDepthBands()
Technical Details
Band Structure
PairDepthBands (per-pair liquidity configuration):- Defines the actual liquidity distribution for each trading pair
- 30 bands representing cumulative percentages of total depth (0-100%)
- Each band liquidity percentage stored as basis points (bps), e.g., 2500 = 25% of total depth
- Separate configurations for above/below market price
- Storage encoding per direction:
- Slot1: totalDepthUsd (32 bits) + bands 0-13 (16 bits each)
- Slot2: bands 14-29 (16 bits each)
- Defines the cumulative offset from mid price at each band boundary
- Values stored as parts per million (ppm), e.g., 130 = 0.013% offset from mid price
- Storage encoding:
- Slot1: bands 0-13 offsets (16 bits each, first 32 bits unused)
- Slot2: bands 14-29 offsets (16 bits each)
Calculation Method
- Iterate through bands until trade size is consumed
- Use trapezoidal rule for average impact within each band
- Weight each band’s contribution by depth consumed
- Support linear extrapolation beyond 100% for large trades
Variable Naming Conventions
- Variables ending in
Usdrepresent USD-denominated values (1e18) - Variables ending in
Ppmrepresent parts per million (1e6) => percentage with 4 decimals - Variables ending in
Bpsrepresent basis points (1e4) => percentage with 2 decimals priceImpactPrepresents price impact percentage in 1e10 precision
Migration Path
- Initialize global depth bands mapping using
initializeDepthBandsMapping() - Migrate existing pairs from old depth model to depth bands
- New pairs should use
setPairDepthBands()directly - Between deployment and setting bands, dynamic price impact will be 0
- Monitor and adjust band configurations as needed
Key Specifications
Backwards Compatibility
- Fully backwards compatible: The new depth bands system produces identical results to the previous linear formula when configured with linear bands and the same depth values
Validation Requirements
- Pair depth bands: Must include the value 100% (10,000 bps) as one of the band values and it must be the maximum value
- Pair depth bands: Must be non-decreasing across bands since they are cumulative (each band value ≥ previous band value)
- Global depth offsets: Must be non-decreasing across bands since they are cumulative (each offset ≥ previous offset)
Trade Splitting Protection
- Cumulative volume price impact: Has 2x weight in the calculation to ensure trade splitting remains unprofitable
- This design choice prevents traders from gaming the system by splitting large trades into smaller ones
Gas Optimization
- Efficient storage packing reduces reads to 2 slots per direction + 2 slots for global offsets => 4 slots total
- Early exit from loop when trade size has been consumed
