Tick Tree Structure
The tick tree is the core data structure that enables efficient price discovery in Vif. It's a 3-level bitmap tree where each level uses 256-bit integers as bitmaps.
Tree Architecture
Root Layer (256 bits)
↓
Level 1 Layer (256 × 256 bits)
↓
Level 2 Layer (256 × 256 × 256 bits)Each set bit in a bitmap indicates that price level is active (has offers).
Finding the Best Price
To find the best price (lowest tick for asks, highest tick for bids):
1. Find least significant set bit in root bitmap
→ gives rootIndex (0-255)
2. Go to level1[rootIndex], find LSB
→ gives level1Index (0-255)
3. Go to level2[rootIndex][level1Index], find LSB
→ gives level2Index (0-255)
4. Calculate final tick index:
index = (rootIndex << 16) | (level1Index << 8) | level2Index
or equivalently:
index = rootIndex * 65536 + level1Index * 256 + level2IndexFinding the Next Price
After consuming all offers at the current price, we need to find the next best price:
1. Unset the current bit in level2 bitmap
2. Find next LSB in level2
- If found: done
- If not found: move to step 3
3. Unset the current bit in level1 bitmap
4. Find next LSB in level1
- If found: go down to corresponding level2, find its LSB
- If not found: move to step 5
5. Unset the current bit in root bitmap
6. Find next LSB in root
- If found: go down through level1 and level2
- If not found: no more prices availableThis traversal algorithm ensures O(1) complexity for moving to the next price point.
Storage Layout
The entire tree is stored as a fixed-size array:
// Total elements: 1 + 256 + 256*256 = 65,793 uint256 slots
tree[0] // Root bitmap (1 slot)
tree[1..256] // Level 1 bitmaps (256 slots)
tree[257..65792] // Level 2 bitmaps (65,536 slots)This fixed allocation means:
- Predictable gas costs for tree operations
- No dynamic allocation overhead
- Maximum of 16,777,216 possible price points (256³)
Index ↔ Tick ↔ Price Conversion
Index to Tick
Ticks are signed 24-bit integers, while indices are unsigned:
const MAX_TICK = 8_388_607; // type(int24).max
tick = index - MAX_TICK;
index = tick + MAX_TICK;Tick to Price
The price is calculated as:
Where price represents the ratio inboundAmount / outboundAmount.
- Higher tick = higher price = worse for taker
- Lower tick = lower price = better for taker
- 1 tick = 0.1 basis point (0.001%) price movement
In-Contract Calculation
Prices are represented as Q128.128 fixed-point numbers using binary exponentiation:
// For negative ticks:
price = binaryExp(-|tick|)
// For positive ticks:
price = 1 / binaryExp(|tick|)See Binary Exponentiation for implementation details.
Tick Spacing
Markets can specify a tick spacing to:
- Reduce gas costs on volatile pairs
- Prevent penny-jumping (makers placing orders 1 tick better)
- Align with traditional market tick sizes
// Example: tickSpacing = 10
// Only ticks ..., -20, -10, 0, 10, 20, ... are valid
actualTick = round(requestedTick / tickSpacing) * tickSpacingWhen placing an order:
- Your requested tick is rounded towards zero to the nearest valid tick
- The tree only activates indices corresponding to valid ticks
Example: WETH/USDC Market
Let's trace finding the best ask price in a WETH/USDC market:
// Setup
outboundToken = WETH
inboundToken = USDC
tickSpacing = 1
// Current state: offers at ticks -2,072,336 and -2,000,000
// These correspond to prices ~1000 USDC and ~1200 USDC per WETH
// Finding best price (lowest tick):
tick₁ = -2,072,336
index₁ = -2,072,336 + 8,388,607 = 6,316,271
// Convert to tree coordinates:
rootIndex = 6,316,271 >> 16 = 96
level1Index = (6,316,271 >> 8) & 0xFF = 101
level2Index = 6,316,271 & 0xFF = 143
// Tree lookup:
root[96] has bit set → check level1[96][101]
level1[96][101] has bit set → check level2[96][101][143]
level2[96][101][143] has bit set at position 143
// Result: Best offer is at tick -2,072,336
price = 1.00001^(-2,072,336) ≈ 0.8187 WETH/USDC
or equivalently: ~1221.7 USDC/WETHGas Optimization
The bitmap structure provides exceptional gas efficiency:
| Operation | Gas Cost | Notes |
|---|---|---|
| Find best price | ~3 SLOAD | One per level |
| Move to next price | ~3-9 SLOAD | Depends on tree descent |
| Activate price | ~3 SSTORE | Set bits in each level |
| Deactivate price | ~3 SSTORE | Unset bits in each level |
Compare this to:
- Linked list: O(n) traversal, unpredictable gas
- Heap: O(log n) operations, expensive updates
- Sorted array: O(n) insertion, O(1) lookup
The bitmap tree achieves near-constant time operations regardless of the number of active price points.
Related Concepts
- Tick - Understanding tick representation
- Binary Exponentiation - Price calculation
- Markets & Units - Market configuration