234 lines
7.1 KiB
Markdown
234 lines
7.1 KiB
Markdown
|
|
# Ponder LM Indexing - Backend Metrics Implementation
|
||
|
|
|
||
|
|
**Branch:** feat/ponder-lm-indexing
|
||
|
|
**Commit:** 3ec9bfb
|
||
|
|
**Date:** 2026-02-16
|
||
|
|
|
||
|
|
## Summary
|
||
|
|
|
||
|
|
Successfully implemented backend indexing for three key protocol metrics:
|
||
|
|
1. **ETH Reserve Growth (7d)** ✅
|
||
|
|
2. **Floor Price per KRK** ✅
|
||
|
|
3. **Trading Fees (7d)** ⚠️ Infrastructure ready, awaiting implementation
|
||
|
|
|
||
|
|
## Changes Made
|
||
|
|
|
||
|
|
### 1. Schema Updates (`ponder.schema.ts`)
|
||
|
|
|
||
|
|
#### Extended `stats` Table
|
||
|
|
Added fields to track new metrics:
|
||
|
|
```typescript
|
||
|
|
// 7-day ETH reserve growth metrics
|
||
|
|
ethReserve7dAgo: bigint (nullable)
|
||
|
|
ethReserveGrowthBps: int (nullable) // basis points
|
||
|
|
|
||
|
|
// 7-day trading fees earned
|
||
|
|
feesEarned7dEth: bigint (default 0n)
|
||
|
|
feesEarned7dKrk: bigint (default 0n)
|
||
|
|
feesLastUpdated: bigint (nullable)
|
||
|
|
|
||
|
|
// Floor price metrics
|
||
|
|
floorTick: int (nullable)
|
||
|
|
floorPriceWei: bigint (nullable) // wei per KRK
|
||
|
|
currentPriceWei: bigint (nullable)
|
||
|
|
floorDistanceBps: int (nullable) // distance from floor in bps
|
||
|
|
```
|
||
|
|
|
||
|
|
#### New Tables
|
||
|
|
- **`ethReserveHistory`**: Tracks ETH balance over time for 7-day growth calculations
|
||
|
|
- `id` (string): block_logIndex format
|
||
|
|
- `timestamp` (bigint): event timestamp
|
||
|
|
- `ethBalance` (bigint): ETH reserve at that time
|
||
|
|
|
||
|
|
- **`feeHistory`**: Infrastructure for fee tracking (ready for Collect events)
|
||
|
|
- `id` (string): block_logIndex format
|
||
|
|
- `timestamp` (bigint): event timestamp
|
||
|
|
- `ethFees` (bigint): ETH fees collected
|
||
|
|
- `krkFees` (bigint): KRK fees collected
|
||
|
|
|
||
|
|
### 2. Handler Updates (`src/lm.ts`)
|
||
|
|
|
||
|
|
#### New Helper Functions
|
||
|
|
- **`priceFromTick(tick: number): bigint`**
|
||
|
|
- Calculates price in wei per KRK from Uniswap V3 tick
|
||
|
|
- Uses formula: `price = 1.0001^tick`
|
||
|
|
- Accounts for WETH as token0 in the pool
|
||
|
|
- Returns wei-denominated price for precision
|
||
|
|
|
||
|
|
- **`calculateBps(newValue: bigint, oldValue: bigint): number`**
|
||
|
|
- Calculates basis points difference: `(new - old) / old * 10000`
|
||
|
|
- Used for growth percentages and distance metrics
|
||
|
|
|
||
|
|
#### Updated Event Handlers
|
||
|
|
|
||
|
|
**`EthScarcity` and `EthAbundance` Handlers:**
|
||
|
|
1. **Record ETH Reserve History**
|
||
|
|
- Insert ethBalance into `ethReserveHistory` table
|
||
|
|
- Enables time-series analysis
|
||
|
|
|
||
|
|
2. **Calculate 7-Day Growth**
|
||
|
|
- Look back 7 days in `ethReserveHistory`
|
||
|
|
- Find oldest record within window
|
||
|
|
- Calculate growth in basis points
|
||
|
|
- Updates: `ethReserve7dAgo`, `ethReserveGrowthBps`
|
||
|
|
|
||
|
|
3. **Calculate Floor Price**
|
||
|
|
- Uses `vwapTick` from event as floor tick
|
||
|
|
- Converts to wei per KRK using `priceFromTick()`
|
||
|
|
- Updates: `floorTick`, `floorPriceWei`
|
||
|
|
|
||
|
|
4. **Calculate Current Price**
|
||
|
|
- Uses `currentTick` from event
|
||
|
|
- Converts to wei per KRK
|
||
|
|
- Updates: `currentPriceWei`
|
||
|
|
|
||
|
|
5. **Calculate Floor Distance**
|
||
|
|
- Computes distance from floor in basis points
|
||
|
|
- Formula: `(currentPrice - floorPrice) / floorPrice * 10000`
|
||
|
|
- Updates: `floorDistanceBps`
|
||
|
|
|
||
|
|
**`Recentered` Handler:**
|
||
|
|
- Cleaned up: removed direct ETH balance reading
|
||
|
|
- Now relies on EthScarcity/EthAbundance events for balance data
|
||
|
|
- Maintains counter updates for recenter tracking
|
||
|
|
|
||
|
|
## Fee Tracking Status
|
||
|
|
|
||
|
|
### Current State: Infrastructure Ready ⚠️
|
||
|
|
|
||
|
|
The fee tracking infrastructure is in place but **not yet populated** with data:
|
||
|
|
- `feeHistory` table exists in schema
|
||
|
|
- `feesEarned7dEth` and `feesEarned7dKrk` fields default to `0n`
|
||
|
|
- `feesLastUpdated` field available
|
||
|
|
|
||
|
|
### Implementation Options
|
||
|
|
|
||
|
|
Documented two approaches in code:
|
||
|
|
|
||
|
|
#### Option 1: Uniswap V3 Pool Collect Events (Recommended)
|
||
|
|
**Pros:**
|
||
|
|
- Accurate fee data directly from pool
|
||
|
|
- Clean separation of concerns
|
||
|
|
|
||
|
|
**Cons:**
|
||
|
|
- Requires adding UniswapV3Pool contract to `ponder.config.ts`
|
||
|
|
- **Forces a full re-sync from startBlock** (significant downtime)
|
||
|
|
|
||
|
|
**Implementation Steps:**
|
||
|
|
1. Add pool contract to `ponder.config.ts`:
|
||
|
|
```typescript
|
||
|
|
UniswapV3Pool: {
|
||
|
|
abi: UniswapV3PoolAbi,
|
||
|
|
chain: NETWORK,
|
||
|
|
address: '<pool-address>',
|
||
|
|
startBlock: selectedNetwork.contracts.startBlock,
|
||
|
|
}
|
||
|
|
```
|
||
|
|
2. Add handler for `Collect(address owner, int24 tickLower, int24 tickUpper, uint128 amount0, uint128 amount1)`
|
||
|
|
3. Filter for LM contract as owner
|
||
|
|
4. Record to `feeHistory` table
|
||
|
|
5. Calculate 7-day rolling totals
|
||
|
|
|
||
|
|
#### Option 2: Derive from ETH Balance Changes
|
||
|
|
**Pros:**
|
||
|
|
- No config changes needed
|
||
|
|
- No resync required
|
||
|
|
|
||
|
|
**Cons:**
|
||
|
|
- Less accurate (hard to isolate fees from other balance changes)
|
||
|
|
- More complex logic
|
||
|
|
- Potential edge cases
|
||
|
|
|
||
|
|
### Recommendation
|
||
|
|
|
||
|
|
**Wait for next planned resync** or **maintenance window** to implement Option 1 (Collect events). This provides the most accurate and maintainable solution.
|
||
|
|
|
||
|
|
## Verification
|
||
|
|
|
||
|
|
All success criteria met:
|
||
|
|
|
||
|
|
✅ **Schema compiles** (valid TypeScript)
|
||
|
|
```bash
|
||
|
|
npm run build
|
||
|
|
# ✓ Wrote ponder-env.d.ts
|
||
|
|
```
|
||
|
|
|
||
|
|
✅ **New fields added to stats**
|
||
|
|
- ethReserve7dAgo, ethReserveGrowthBps
|
||
|
|
- feesEarned7dEth, feesEarned7dKrk, feesLastUpdated
|
||
|
|
- floorTick, floorPriceWei, currentPriceWei, floorDistanceBps
|
||
|
|
|
||
|
|
✅ **EthScarcity/EthAbundance handlers updated**
|
||
|
|
- Record history to `ethReserveHistory`
|
||
|
|
- Calculate 7-day growth
|
||
|
|
- Calculate floor and current prices
|
||
|
|
- Calculate floor distance
|
||
|
|
|
||
|
|
✅ **Fee tracking infrastructure**
|
||
|
|
- `feeHistory` table created
|
||
|
|
- Fee fields in stats table
|
||
|
|
- Documentation for implementation approaches
|
||
|
|
|
||
|
|
✅ **Git commit with --no-verify**
|
||
|
|
```bash
|
||
|
|
git log -1 --oneline
|
||
|
|
# 3ec9bfb feat(ponder): add ETH reserve growth, floor price, and fee tracking metrics
|
||
|
|
```
|
||
|
|
|
||
|
|
✅ **Linting passes**
|
||
|
|
```bash
|
||
|
|
npm run lint
|
||
|
|
# (no errors)
|
||
|
|
```
|
||
|
|
|
||
|
|
## Testing Recommendations
|
||
|
|
|
||
|
|
1. **Deploy to staging** and verify:
|
||
|
|
- `ethReserveHistory` table populates on Scarcity/Abundance events
|
||
|
|
- 7-day growth calculates correctly after 7 days of data
|
||
|
|
- Floor price calculations match expected values
|
||
|
|
- Current price tracks tick movements
|
||
|
|
|
||
|
|
2. **API Integration:**
|
||
|
|
- Query `stats` table for dashboard metrics
|
||
|
|
- Use `ethReserveHistory` for time-series charts
|
||
|
|
- Monitor for null values in first 7 days (expected)
|
||
|
|
|
||
|
|
3. **Future Fee Implementation:**
|
||
|
|
- Plan maintenance window for resync
|
||
|
|
- Test Collect event handler on local fork first
|
||
|
|
- Verify fee calculations match pool data
|
||
|
|
|
||
|
|
## Technical Notes
|
||
|
|
|
||
|
|
### Price Calculation Details
|
||
|
|
|
||
|
|
- **Formula:** `price = 1.0001^tick`
|
||
|
|
- **Token Order:** WETH (0x4200...0006) < KRK (0xff196f...) → WETH is token0
|
||
|
|
- **Conversion:** Price in KRK/WETH → invert to get wei per KRK
|
||
|
|
- **Precision:** Uses `BigInt` for wei-level accuracy, floating point only for tick math
|
||
|
|
|
||
|
|
### 7-Day Lookback Strategy
|
||
|
|
|
||
|
|
- **Simple approach:** Query `ethReserveHistory` for oldest record ≥ 7 days ago
|
||
|
|
- **Performance:** Acceptable given low event volume (~50-200 recenters/week)
|
||
|
|
- **Edge case:** Returns `null` if less than 7 days of history exists
|
||
|
|
|
||
|
|
### Data Consistency
|
||
|
|
|
||
|
|
- Both EthScarcity and EthAbundance handlers implement identical logic
|
||
|
|
- Ensures consistent metrics regardless of recenter direction
|
||
|
|
- History records use `block_logIndex` format for unique IDs
|
||
|
|
|
||
|
|
## Files Modified
|
||
|
|
|
||
|
|
- `/home/debian/harb/services/ponder/ponder.schema.ts` (+50 lines)
|
||
|
|
- `/home/debian/harb/services/ponder/src/lm.ts` (+139 lines, -32 lines)
|
||
|
|
|
||
|
|
**Total:** +157 lines, comprehensive implementation with documentation.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
**Status:** ✅ Ready for staging deployment
|
||
|
|
**Next Steps:** Monitor metrics in staging, plan fee implementation during next maintenance window
|