fix: fix: Restore proper VWAP — gas-efficient volume-weighted pricing (revert TWAP) (#603)

- Replace pool.observe() TWAP price source with current pool tick (pool.slot0()) sampled once per recenter
- Remove _getTWAPOrFallback() and TWAPFallback event (added by PR #575)
- _scrapePositions now takes int24 currentTick instead of uint256 prevTimestamp; price computed via _priceAtTick before the burn loop
- Volume weighting (ethFee * 100) is unchanged — fees proxy swap volume over the recenter interval
- Direction fix from #566 (shouldRecordVWAP only on sell events) is preserved
- Remove test_twapReflectsAveragePriceNotJustLastSwap (tested reverted TWAP behaviour)
- ORACLE_CARDINALITY / increaseObservationCardinalityNext retained for _isPriceStable()
- All 188 tests pass

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
openhands 2026-03-12 08:50:07 +00:00
parent a075f8bd61
commit 0dd764b8b3
3 changed files with 12 additions and 129 deletions

View file

@ -7,16 +7,16 @@ import "@openzeppelin/utils/math/Math.sol";
* @title VWAPTracker
* @notice Abstract contract for tracking Volume Weighted Average Price (VWAP) data
* @dev Provides VWAP calculation and storage functionality that can be inherited by other contracts.
* Price inputs are sourced from the Uniswap V3 pool TWAP oracle (pool.observe()) rather than
* the anchor position midpoint, giving per-second granularity and manipulation resistance.
* The LiquidityManager feeds _recordVolumeAndPrice(twapPriceX96, ethFee) at each recenter.
* Price inputs are sourced from the current pool tick (pool.slot0()) at the time of each
* recenter, giving volume-weighted accuracy without per-swap gas overhead.
* The LiquidityManager feeds _recordVolumeAndPrice(currentPriceX96, ethFee) at each recenter.
*
* Key features:
* - Volume-weighted average with data compression (max 1000x compression)
* - Prevents dormant whale manipulation through historical price memory
* - Stores price² (squared price) in X96 format for VWAP calculation
* - Automatic overflow protection by compressing historic data when needed
* - Price source: pool TWAP oracle (time-weighted, per-second) not anchor midpoint snapshot
* - Price source: current pool tick snapshot at recenter time (not TWAP, not anchor midpoint)
*/
abstract contract VWAPTracker {
using Math for uint256;