From 2efcd4c0d3a6691fbba431a7a25d50fcf7418260 Mon Sep 17 00:00:00 2001 From: tim Date: Tue, 25 Nov 2025 16:06:15 -0400 Subject: [PATCH] improved price tests --- test/PartyPool.t.sol | 51 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/test/PartyPool.t.sol b/test/PartyPool.t.sol index 5b26d26..1a09eab 100644 --- a/test/PartyPool.t.sol +++ b/test/PartyPool.t.sol @@ -2,6 +2,7 @@ /* solhint-disable */ pragma solidity ^0.8.30; +import "forge-std/console2.sol"; import {ABDKMath64x64} from "../lib/abdk-libraries-solidity/ABDKMath64x64.sol"; import {CommonBase} from "../lib/forge-std/src/Base.sol"; import {StdAssertions} from "../lib/forge-std/src/StdAssertions.sol"; @@ -1145,5 +1146,55 @@ contract PartyPoolTest is Test { assertEq(uint256(uint128(price)), uint256(uint128(expected)), "Price token1/token0 should be 3.0000000"); } + /// @notice Verify that PartyInfo.price() agrees (within tolerance) with the swapAmounts() quote + /// for a very small (de-minimis) exact-input swap from token1 -> token0. + function testPriceMatchesSwapForSmallInput() public { + // Build tokens array (reuse test tokens) + IERC20[] memory tokens = new IERC20[](3); + tokens[0] = IERC20(address(token0)); + tokens[1] = IERC20(address(token1)); + tokens[2] = IERC20(address(token2)); + + uint256 feePpm = 0; + // Use a large kappa to prevent slippage + int128 kappa = ABDKMath64x64.fromUInt(100); + + // Prepare explicit per-token initial deposits so token0 starts at 3x token1 + uint256[] memory deposits = new uint256[](3); + deposits[0] = INIT_BAL * 3; // token0 = 3 * INIT_BAL + deposits[1] = INIT_BAL; // token1 = INIT_BAL + deposits[2] = INIT_BAL; // token2 = INIT_BAL + + // Deploy a fresh pool with the specified deposits + (IPartyPool poolCustom, ) = Deploy.newPartyPoolWithDeposits("LP3X_SWAP", "LP3X_SWAP", tokens, kappa, feePpm, feePpm, false, deposits, 0); + + // Query the info viewer for the marginal price token1 (base) denominated in token0 (quote) + int128 infoPrice = info.price(poolCustom, 1, 0); + + // Choose a small-but-sufficient input amount in external units to avoid underflow/rounding issues + uint256 inputAmount = INIT_BAL/100; + + // Query the swapAmounts view to get grossIn (includes fee), amountOut, and fee + (uint256 grossIn, uint256 amountOut, uint256 inFee) = poolCustom.swapAmounts(1, 0, inputAmount, 0); + + // Net input consumed by kernel excludes the fee + uint256 netIn = grossIn > inFee ? grossIn - inFee : 0; + require(netIn > 0, "net input must be positive for price comparison"); + + // Compute swap-implied price as Q64.64 (quote per base) = amountOut / netIn + int128 swapPrice = ABDKMath64x64.divu(amountOut, netIn); + console2.log('info price', infoPrice); + console2.log('swap price', swapPrice); + + // Absolute difference between info.price and swap-implied price + int128 slippage = ABDKMath64x64.fromUInt(1) - swapPrice.div(infoPrice); + console2.log('slippage', slippage); + + // Tolerance ~ 4e-5 in Q64.64 + int128 tol = ABDKMath64x64.divu(4, 100_000); + + assertTrue(slippage <= tol, "price from info and swapAmounts should be close"); + } + } /* solhint-enable */