Vault_Base_ERC20#_updateVirtualPrice calculates interest incorrectly if updated frequently
Updating the virtual price of an asset happens in discrete increments of 3 minutes. This is done to reduce the chance of DOS loops. The issue is that it updates the time to an incorrect timestamp. It should update to the truncated 3 minute interval but instead updates to the current timestamp. The result is that the interest calculation can be abused to lower effective interest rate.\\n```\\nfunction _updateVirtualPrice(uint256 _currentBlockTime, address _collateralAddress) internal { \\n    (   ,\\n        ,\\n        ,\\n        uint256 interestPer3Min,\\n        uint256 lastUpdateTime,\\n        uint256 virtualPrice,\\n\\n    ) = _getCollateral(_collateralAddress);\\n    uint256 timeDelta = _currentBlockTime - lastUpdateTime;\\n    //exit gracefully if two users call the function for the same collateral in the same 3min period\\n    //@audit increments \\n    uint256 threeMinuteDelta = timeDelta / 180; \\n    if(threeMinuteDelta > 0) {\\n        for (uint256 i = 0; i < threeMinuteDelta; i++ ){\\n        virtualPrice = (virtualPrice * interestPer3Min) / LOAN_SCALE; \\n        }\\n        collateralBook.vaultUpdateVirtualPriceAndTime(_collateralAddress, virtualPrice, _currentBlockTime);\\n    }\\n}\\n```\\n\\n_updateVirtualPrice is used to update the interest calculations for the specified collateral and is always called with block.timestamp. Due to truncation threeMinuteDelta is always rounded down, that is if there has been 1.99 3-minute intervals it will truncate to 1. The issue is that in the collateralBook#vaultUpdateVirtualPriceAndTime subcall the time is updated to block.timestamp (_currentBlockTime).\\nExample: lastUpdateTime = 1000 and block.timestamp (_currentBlockTime) = 1359.\\ntimeDelta = 1359 - 1000 = 359\\nthreeMinuteDelta = 359 / 180 = 1\\nThis updates the interest by only as single increment but pushes the new time forward 359 seconds. When called again it will use 1359 as lastUpdateTime which means that 179 seconds worth of interest have been permanently lost. Users with large loan positions could abuse this to effectively halve their interest accumulation. Given how cheap optimism transactions are it is highly likely this could be exploited profitably with a bot.
Before updating the interest time it should first truncate it to the closest 3-minute interval:\\n```\\n    if(threeMinuteDelta > 0) {\\n        for (uint256 i = 0; i < threeMinuteDelta; i++ ){\\n            virtualPrice = (virtualPrice * interestPer3Min) / LOAN_SCALE; \\n        }\\n+       _currentBlockTime = (_currentBlockTime / 180) * 180;\\n        collateralBook.vaultUpdateVirtualPriceAndTime(_collateralAddress, virtualPrice, _currentBlockTime);\\n    }\\n```\\n
Interest calculations will be incorrect if they are updated frequently, which can be abused by users with large amounts of debt to halve their accumulated interest
```\\nfunction _updateVirtualPrice(uint256 _currentBlockTime, address _collateralAddress) internal { \\n    (   ,\\n        ,\\n        ,\\n        uint256 interestPer3Min,\\n        uint256 lastUpdateTime,\\n        uint256 virtualPrice,\\n\\n    ) = _getCollateral(_collateralAddress);\\n    uint256 timeDelta = _currentBlockTime - lastUpdateTime;\\n    //exit gracefully if two users call the function for the same collateral in the same 3min period\\n    //@audit increments \\n    uint256 threeMinuteDelta = timeDelta / 180; \\n    if(threeMinuteDelta > 0) {\\n        for (uint256 i = 0; i < threeMinuteDelta; i++ ){\\n        virtualPrice = (virtualPrice * interestPer3Min) / LOAN_SCALE; \\n        }\\n        collateralBook.vaultUpdateVirtualPriceAndTime(_collateralAddress, virtualPrice, _currentBlockTime);\\n    }\\n}\\n```\\n