Omniscia Euler Finance Audit

Cache Manual Review Findings

Cache Manual Review Findings

CEH-01M: Inexistent Upward-Rounding Operation of Total Borrows

Description:

The share-based fee captured as part of a borrow interest update will calculate the shares to mint based on a newTotalAssets evaluation that does not round the borrows upwards, resulting in an under-evaluation of the newTotalAssets and thus an over-evaluation of the fees captured.

Impact:

Although the fees captured will be over-evaluated, the error by which this overvaluation will occur is small rendering this exhibit to be of minor severity.

Example:

src/EVault/shared/Cache.sol
98if (feeAssets != 0) {
99 uint256 newTotalAssets = vaultCache.cash.toUint() + (newTotalBorrows >> INTERNAL_DEBT_PRECISION);
100 newTotalShares = newTotalAssets * newTotalShares / (newTotalAssets - feeAssets);
101 newAccumulatedFees += newTotalShares - vaultCache.totalShares.toUint();
102 }
103
104 // Store new values in vaultCache, only if no overflows will occur. Fees are not larger than total shares, since they are included in them.
105
106 if (newTotalShares <= MAX_SANE_AMOUNT && newTotalBorrows <= MAX_SANE_DEBT_AMOUNT) {
107 vaultCache.totalBorrows = newTotalBorrows.toOwed();
108 vaultCache.interestAccumulator = newInterestAccumulator;
109 vaultCache.lastInterestAccumulatorUpdate = uint48(block.timestamp);
110
111 if (newTotalShares != Shares.unwrap(vaultCache.totalShares)) {
112 vaultCache.accumulatedFees = newAccumulatedFees.toShares();
113 vaultCache.totalShares = newTotalShares.toShares();
114 }
115 }
116 }
117}
118
119function totalAssetsInternal(VaultCache memory vaultCache) internal pure returns (uint256) {
120 // total assets can exceed Assets max amount (MAX_SANE_AMOUNT)
121 return vaultCache.cash.toUint() + vaultCache.totalBorrows.toAssetsUp().toUint();
122}

Recommendation:

We advise the newTotalAssets calculation to properly use the Cache::totalAssetsInternal function, ensuring that the total assets calculated properly represent the expected total assets after the interest rate update is reflected in the contract's storage.

Alleviation (fb2dd77a6ff9b7f710edb48e7eb5437e0db4fc1a):

The calculation will properly round upwards by using the newly introduced OwedLib::toAssetsUpUint256 function, alleviating this exhibit and ensuring consistency in the total asset evaluation across the system.

CEH-02M: Improper Interest Rate Update

Description:

In the current system, whether the interest rate update succeeds in the Cache::initVaultCache function relies on whether the newTotalShares and newTotalBorrows variables can be represented in their respective types.

Impact:

In the low-likelihood scenario whereby the vaultCache.totalShares value is very close to the MAX_SANE_AMOUNT but the vaultCache.totalBorrows value is relatively low, an interest rate update will be forfeited incorrectly. As the impact is high, we consider a medium-severity assessment as appropriate for this finding.

Example:

src/EVault/shared/Cache.sol
106if (newTotalShares <= MAX_SANE_AMOUNT && newTotalBorrows <= MAX_SANE_DEBT_AMOUNT) {
107 vaultCache.totalBorrows = newTotalBorrows.toOwed();
108 vaultCache.interestAccumulator = newInterestAccumulator;
109 vaultCache.lastInterestAccumulatorUpdate = uint48(block.timestamp);
110
111 if (newTotalShares != Shares.unwrap(vaultCache.totalShares)) {
112 vaultCache.accumulatedFees = newAccumulatedFees.toShares();
113 vaultCache.totalShares = newTotalShares.toShares();
114 }
115}

Recommendation:

We consider the current approach incorrect, as the total borrows and interest rate of the system should be updated distinctly from the fees permitting the system to accumulate interest on underlying borrows even if fees cannot be captured to increase the total share supply.

Alleviation (fb2dd77a6ff9b7f710edb48e7eb5437e0db4fc1a):

The code was updated to evaluate the borrow interest and accumulated fees updates distinctly, validating that the borrow interest rate can be applied at first and consequently evaluating whether fees can be safely accumulated.

As such, we consider this exhibit fully alleviated as a total borrow update taking precedence over a fee update is what we consider best practice.