Omniscia Euler Finance Audit
RiskManager Manual Review Findings
RiskManager Manual Review Findings
RMR-01M: Overprotective Security Mechanism
Type | Severity | Location |
---|---|---|
Logical Fault | RiskManager.sol:L105 |
Description:
The RiskManager::checkVaultStatus
function which is invoked as part of the Ethereum Vault Connector's execution flow after all interactions with the vault have concluded will ensure that the borrowCap
has not been breached.
A problem that arises from the current security mechanism is the fact that the entire vault will be inoperable if the total borrows have naturally exceeded the permitted borrowCap
. For example, a user with collateral but no debt will not be able to withdraw their collateral which is a restriction that should not be imposed.
Impact:
In the extreme circumstance that the borrowCap
has been reached due to natural interest accrual, the vault will be inoperable in functions that do not otherwise deal with borrow balances when it shouldn't be so.
Example:
84/// @inheritdoc IRiskManager85/// @dev See comment about re-entrancy for `checkAccountStatus`86function checkVaultStatus() public virtual reentrantOK onlyEVCChecks returns (bytes4 magicValue) {87 // Use the updating variant to make sure interest is accrued in storage before the interest rate update88 VaultCache memory vaultCache = updateVault();89 uint256 newInterestRate = computeInterestRate(vaultCache);90
91 logVaultStatus(vaultCache, newInterestRate);92
93 // We use the snapshot to check if the borrows or supply grew, and if so then we check the borrow and supply caps.94 // If snapshot is initialized, then caps are configured.95 // If caps are set in the middle of a batch, then snapshots represent the state of the vault at that time.96 if (vaultCache.snapshotInitialized) {97 vaultStorage.snapshotInitialized = vaultCache.snapshotInitialized = false;98
99 Assets snapshotCash = snapshot.cash;100 Assets snapshotBorrows = snapshot.borrows;101
102 uint256 prevBorrows = snapshotBorrows.toUint();103 uint256 borrows = vaultCache.totalBorrows.toAssetsUp().toUint();104
105 if (borrows > vaultCache.borrowCap && borrows > prevBorrows) revert E_BorrowCapExceeded();106
107 uint256 prevSupply = snapshotCash.toUint() + prevBorrows;108 uint256 supply = totalAssetsInternal(vaultCache);109
110 if (supply > vaultCache.supplyCap && supply > prevSupply) revert E_SupplyCapExceeded();111
112 snapshot.reset();113 }114
115 magicValue = IEVCVault.checkVaultStatus.selector;116}
Recommendation:
We advise the borrowCap
limitation specifically to be applied solely for operations that actively increase the cap rather than for natural interest rate increases, ensuring that users can still interact with the vault albeit at a limited capacity when the borrowCap
has been breached.
Alleviation (fb2dd77a6ff9b7f710edb48e7eb5437e0db4fc1a):
The Euler Finance team evaluated this exhibit and concluded that it is incorrect as the snapshot being evaluated will have reflected any borrow interest accrual in the prevBorrows
variable, effectively causing the if
clause to not trigger if the borrows were not increased as part of the overall user interaction.
As such, a user will continue to be able to withdraw even when the borrow has exceeded the cap rendering this exhibit invalid.