OlympusPrice.v2.sol#storePrice: The moving average prices are used recursively for the calculation of the moving average price.
The moving average prices should be calculated by only oracle feed prices. But now, they are calculated by not only oracle feed prices but also moving average price recursively.\\nThat is, the `storePrice` function uses the current price obtained from the `_getCurrentPrice` function to update the moving average price. However, in the case of `asset.useMovingAverage = true`, the `_getCurrentPrice` function computes the current price using the moving average price.\\nThus, the moving average prices are used recursively to calculate moving average price, so the current prices will be obtained incorrectly.\\n`OlympusPrice.v2.sol#storePrice` function is the following.\\n```\\n    function storePrice(address asset_) public override permissioned {\\n        Asset storage asset = _assetData[asset_];\\n\\n        // Check if asset is approved\\n        if (!asset.approved) revert PRICE_AssetNotApproved(asset_);\\n\\n        // Get the current price for the asset\\n   (uint256 price, uint48 currentTime) = _getCurrentPrice(asset_);\\n\\n        // Store the data in the obs index\\n        uint256 oldestPrice = asset.obs[asset.nextObsIndex];\\n        asset.obs[asset.nextObsIndex] = price;\\n\\n        // Update the last observation time and increment the next index\\n        asset.lastObservationTime = currentTime;\\n        asset.nextObsIndex = (asset.nextObsIndex + 1) % asset.numObservations;\\n\\n        // Update the cumulative observation, if storing the moving average\\n        if (asset.storeMovingAverage)\\n       asset.cumulativeObs = asset.cumulativeObs + price - oldestPrice;\\n\\n        // Emit event\\n        emit PriceStored(asset_, price, currentTime);\\n    }\\n```\\n\\n`L319` obtain the current price for the asset by calling the `_getCurrentPrice` function and use it to update `asset.cumulativeObs` in `L331`. The `_getCurrentPrice` function is the following.\\n```\\n    function _getCurrentPrice(address asset_) internal view returns (uint256, uint48) {\\n        Asset storage asset = _assetData[asset_];\\n\\n        // Iterate through feeds to get prices to aggregate with strategy\\n        Component[] memory feeds = abi.decode(asset.feeds, (Component[]));\\n        uint256 numFeeds = feeds.length;\\n   uint256[] memory prices = asset.useMovingAverage\\n            ? new uint256[](numFeeds + 1)\\n            : new uint256[](numFeeds);\\n        uint8 _decimals = decimals; // cache in memory to save gas\\n        for (uint256 i; i < numFeeds; ) {\\n            (bool success_, bytes memory data_) = address(_getSubmoduleIfInstalled(feeds[i].target))\\n                .staticcall(\\n                    abi.encodeWithSelector(feeds[i].selector, asset_, _decimals, feeds[i].params)\\n                );\\n\\n            // Store price if successful, otherwise leave as zero\\n            // Idea is that if you have several price calls and just\\n            // one fails, it'll DOS the contract with this revert.\\n            // We handle faulty feeds in the strategy contract.\\n            if (success_) prices[i] = abi.decode(data_, (uint256));\\n\\n            unchecked {\\n                ++i;\\n            }\\n        }\\n\\n        // If moving average is used in strategy, add to end of prices array\\n   if (asset.useMovingAverage) prices[numFeeds] = asset.cumulativeObs / asset.numObservations;\\n\\n        // If there is only one price, ensure it is not zero and return\\n        // Otherwise, send to strategy to aggregate\\n        if (prices.length == 1) {\\n            if (prices[0] == 0) revert PRICE_PriceZero(asset_);\\n            return (prices[0], uint48(block.timestamp));\\n        } else {\\n            // Get price from strategy\\n            Component memory strategy = abi.decode(asset.strategy, (Component));\\n            (bool success, bytes memory data) = address(_getSubmoduleIfInstalled(strategy.target))\\n                .staticcall(abi.encodeWithSelector(strategy.selector, prices, strategy.params));\\n\\n            // Ensure call was successful\\n            if (!success) revert PRICE_StrategyFailed(asset_, data);\\n\\n            // Decode asset price\\n            uint256 price = abi.decode(data, (uint256));\\n\\n            // Ensure value is not zero\\n            if (price == 0) revert PRICE_PriceZero(asset_);\\n\\n            return (price, uint48(block.timestamp));\\n        }\\n    }\\n```\\n\\nAs can be seen, when `asset.useMovingAverage = true`, the `_getCurrentPrice` calculates the current `price` `price` using the moving average `price` obtained by `asset.cumulativeObs / asset.numObservations` in `L160`.\\nSo the `price` value in `L331` is obtained from not only oracle feed prices but also moving average `price`. Then, `storePrice` calculates the cumulative observations asset.cumulativeObs = asset.cumulativeObs + `price` - oldestPrice using the `price` which is obtained incorrectly above.\\nThus, the moving average prices are used recursively for the calculation of the moving average price.
When updating the current price and cumulative observations in the `storePrice` function, it should use the oracle price feeds and not include the moving average prices. So, instead of using the `asset.useMovingAverage` state variable in the `_getCurrentPrice` function, we can add a `useMovingAverage` parameter as the following.\\n```\\n  function _getCurrentPrice(address asset_, bool useMovingAverage) internal view returns (uint256, uint48) {\\n        Asset storage asset = _assetData[asset_];\\n\\n        // Iterate through feeds to get prices to aggregate with strategy\\n        Component[] memory feeds = abi.decode(asset.feeds, (Component[]));\\n        uint256 numFeeds = feeds.length;\\n      uint256[] memory prices = useMovingAverage\\n            ? new uint256[](numFeeds + 1)\\n            : new uint256[](numFeeds);\\n        uint8 _decimals = decimals; // cache in memory to save gas\\n        for (uint256 i; i < numFeeds; ) {\\n            (bool success_, bytes memory data_) = address(_getSubmoduleIfInstalled(feeds[i].target))\\n                .staticcall(\\n                    abi.encodeWithSelector(feeds[i].selector, asset_, _decimals, feeds[i].params)\\n                );\\n\\n            // Store price if successful, otherwise leave as zero\\n            // Idea is that if you have several price calls and just\\n            // one fails, it'll DOS the contract with this revert.\\n            // We handle faulty feeds in the strategy contract.\\n            if (success_) prices[i] = abi.decode(data_, (uint256));\\n\\n            unchecked {\\n                ++i;\\n            }\\n        }\\n\\n        // If moving average is used in strategy, add to end of prices array\\n      if (useMovingAverage) prices[numFeeds] = asset.cumulativeObs / asset.numObservations;\\n\\n        // If there is only one price, ensure it is not zero and return\\n        // Otherwise, send to strategy to aggregate\\n        if (prices.length == 1) {\\n            if (prices[0] == 0) revert PRICE_PriceZero(asset_);\\n            return (prices[0], uint48(block.timestamp));\\n        } else {\\n            // Get price from strategy\\n            Component memory strategy = abi.decode(asset.strategy, (Component));\\n            (bool success, bytes memory data) = address(_getSubmoduleIfInstalled(strategy.target))\\n                .staticcall(abi.encodeWithSelector(strategy.selector, prices, strategy.params));\\n\\n            // Ensure call was successful\\n            if (!success) revert PRICE_StrategyFailed(asset_, data);\\n\\n            // Decode asset price\\n            uint256 price = abi.decode(data, (uint256));\\n\\n            // Ensure value is not zero\\n            if (price == 0) revert PRICE_PriceZero(asset_);\\n\\n            return (price, uint48(block.timestamp));\\n        }\\n    }\\n```\\n\\nThen we should set `useMovingAverage = false` to call `_getCurrentPrice` function only in the `storePrice` function. In other cases, we should set `useMovingAverage = asset.useMovingAverage` to call `_getCurrentPrice` function.
Now the moving average prices are used recursively for the calculation of the moving average price. Then, the moving average prices become more smoothed than the intention of the administrator. That is, even when the actual price fluctuations are large, the price fluctuations of `_getCurrentPrice` function will become too small.\\nMoreover, even though all of the oracle price feeds fails, the moving averge prices will be calculated only by moving average prices.\\nThus the current prices will become incorrect. If `_getCurrentPrice` function value is miscalculated, it will cause fatal damage to the protocol.
```\\n    function storePrice(address asset_) public override permissioned {\\n        Asset storage asset = _assetData[asset_];\\n\\n        // Check if asset is approved\\n        if (!asset.approved) revert PRICE_AssetNotApproved(asset_);\\n\\n        // Get the current price for the asset\\n   (uint256 price, uint48 currentTime) = _getCurrentPrice(asset_);\\n\\n        // Store the data in the obs index\\n        uint256 oldestPrice = asset.obs[asset.nextObsIndex];\\n        asset.obs[asset.nextObsIndex] = price;\\n\\n        // Update the last observation time and increment the next index\\n        asset.lastObservationTime = currentTime;\\n        asset.nextObsIndex = (asset.nextObsIndex + 1) % asset.numObservations;\\n\\n        // Update the cumulative observation, if storing the moving average\\n        if (asset.storeMovingAverage)\\n       asset.cumulativeObs = asset.cumulativeObs + price - oldestPrice;\\n\\n        // Emit event\\n        emit PriceStored(asset_, price, currentTime);\\n    }\\n```\\n