// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity ^0.8.19; import "forge-std/Test.sol"; import "../src/VWAPTracker.sol"; import "./mocks/MockVWAPTracker.sol"; /** * @title VWAP Double-Overflow Analysis * @notice Analyzes the realistic possibility of double-overflow scenarios * @dev Tests whether the minimal compression approach could lead to situations * where new volume cannot be recorded due to overflow even after compression */ contract ExtendedMockVWAPTracker is MockVWAPTracker { // Expose internal function for testing (bounds applied to prevent test overflow) function testRecordVolumeAndPriceUnsafe(uint256 currentPriceX96, uint256 fee) external view { // Cap extreme inputs to prevent overflow during test calculations if (currentPriceX96 > type(uint128).max) currentPriceX96 = type(uint128).max; if (fee > type(uint64).max) fee = type(uint64).max; if (currentPriceX96 == 0) currentPriceX96 = 1; if (fee == 0) fee = 1; uint256 volume = fee * 100; // Check if multiplication would overflow if (currentPriceX96 > type(uint256).max / volume) { console.log("Multiplication would overflow - extreme transaction detected"); return; } uint256 volumeWeightedPriceX96 = currentPriceX96 * volume; // Check if addition would overflow bool addWouldOverflow = cumulativeVolumeWeightedPriceX96 > type(uint256).max - volumeWeightedPriceX96; console.log("Current cumulative:", cumulativeVolumeWeightedPriceX96); console.log("New volume-weighted price:", volumeWeightedPriceX96); console.log("Would overflow on addition:", addWouldOverflow); } } contract VWAPDoubleOverflowAnalysisTest is Test { ExtendedMockVWAPTracker vwapTracker; function setUp() public { vwapTracker = new ExtendedMockVWAPTracker(); } /** * @notice Tests the actual compression behavior under extreme but realistic conditions */ function testCompressionUnderExtremeConditions() public { console.log("\n=== COMPRESSION BEHAVIOR TEST ==="); // Simulate a scenario with very large accumulated data uint256 largeValue = 10**70 + 1; // Triggers compression vm.store(address(vwapTracker), bytes32(uint256(0)), bytes32(largeValue)); vm.store(address(vwapTracker), bytes32(uint256(1)), bytes32(largeValue / 10**30)); console.log("Before compression trigger:"); console.log("Cumulative VWAP:", vwapTracker.cumulativeVolumeWeightedPriceX96()); console.log("Cumulative Volume:", vwapTracker.cumulativeVolume()); // Try to record a large but realistic transaction uint256 realisticHighPrice = (uint256(1000) << 96) / 3000; // $1000 HARB / $3000 ETH uint256 largeFee = 100 ether; // 100 ETH trade console.log("Recording large transaction:"); console.log("Price X96:", realisticHighPrice); console.log("Fee:", largeFee / 10**18, "ETH"); // This should trigger compression and succeed vwapTracker.recordVolumeAndPrice(realisticHighPrice, largeFee); console.log("After recording (post-compression):"); console.log("Cumulative VWAP:", vwapTracker.cumulativeVolumeWeightedPriceX96()); console.log("Cumulative Volume:", vwapTracker.cumulativeVolume()); console.log("Final VWAP:", vwapTracker.getVWAP()); // Verify it worked without reverting assertTrue(vwapTracker.cumulativeVolumeWeightedPriceX96() > 0, "Transaction should have been recorded successfully"); console.log("SUCCESS: Large transaction recorded even under extreme conditions"); } /** * @notice Tests if we can create a scenario that actually fails due to double-overflow */ function testAttemptToCreateDoubleOverflow() public { console.log("\n=== ATTEMPT TO CREATE DOUBLE-OVERFLOW ==="); // Set up state that's already maximally compressed (1000x was applied) uint256 maxSafeAfterCompression = type(uint256).max / 10**6; vm.store(address(vwapTracker), bytes32(uint256(0)), bytes32(maxSafeAfterCompression)); vm.store(address(vwapTracker), bytes32(uint256(1)), bytes32(maxSafeAfterCompression / 10**40)); // Try an impossibly large transaction that might cause double-overflow uint256 impossiblePrice = type(uint128).max; // Maximum reasonable price uint256 impossibleFee = type(uint64).max; // Maximum reasonable fee console.log("Attempting impossible transaction:"); console.log("Price:", impossiblePrice); console.log("Fee:", impossibleFee); console.log("Product:", impossiblePrice * impossibleFee * 100); // This should either succeed (with compression) or provide insight into edge case try vwapTracker.recordVolumeAndPrice(impossiblePrice, impossibleFee) { console.log("SUCCESS: Even impossible transaction was handled"); console.log("Final VWAP after impossible transaction:", vwapTracker.getVWAP()); } catch Error(string memory reason) { console.log("FAILED: Found the double-overflow edge case"); console.log("Error reason:", reason); // If this fails, we've found a legitimate edge case that needs addressing } catch { console.log("FAILED: Low-level failure in double-overflow scenario"); } } }