Omniscia Euler Finance Audit
BorrowUtils Code Style Findings
BorrowUtils Code Style Findings
BUS-01C: Ineffectual Usage of Safe Arithmetics
Type | Severity | Location |
---|---|---|
Language Specific | BorrowUtils.sol:L65, L77, L160, L164 |
Description:
The linked mathematical operation is guaranteed to be performed safely by surrounding conditionals evaluated in either require
checks or if-else
constructs.
Example:
159if (owed > prevOwed) {160 uint256 change = (owed.toAssetsUp() - prevOwed.toAssetsUp()).toUint();161 emit Borrow(account, change);162 DToken(dTokenAddress).emitTransfer(address(0), account, change);163} else if (prevOwed > owed) {164 uint256 change = (prevOwed.toAssetsUp() - owed.toAssetsUp()).toUint();165
166 emit Repay(account, change);167 DToken(dTokenAddress).emitTransfer(account, address(0), change);168}
Recommendation:
Given that safe arithmetics are toggled on by default in pragma
versions of 0.8.X
, we advise the linked statement to be wrapped in an unchecked
code block thereby optimizing its execution cost.
Alleviation (fb2dd77a6f):
The optimization has been partially applied as only the example referenced in the exhibit has been optimized. We advise all referenced instances by the exhibit (i.e. the Location
lines) to be addressed, optimizing the codebase further.
Alleviation (0f2192ac81):
The optimization proposed has been applied to the remaining instances, rendering this exhibit fully addressed.
BUS-02C: Inefficient Update of User's Debt
Type | Severity | Location |
---|---|---|
Gas Optimization | BorrowUtils.sol:L36, L46, L63 |
Description:
The BorrowUtils::increaseBorrow
function will inefficiently adjust the vaultStorage.users[account]
data location twice redundantly, once when synchronizing the user's borrow position and once when incrementing it.
Example:
29function updateUserBorrow(VaultCache memory vaultCache, address account)30 private31 returns (Owed newOwed, Owed prevOwed)32{33 prevOwed = vaultStorage.users[account].getOwed();34 newOwed = getCurrentOwed(vaultCache, account, prevOwed);35
36 vaultStorage.users[account].setOwed(newOwed);37 vaultStorage.users[account].interestAccumulator = vaultCache.interestAccumulator;38}39
40function increaseBorrow(VaultCache memory vaultCache, address account, Assets assets) internal {41 (Owed owed, Owed prevOwed) = updateUserBorrow(vaultCache, account);42
43 Owed amount = assets.toOwed();44 owed = owed + amount;45
46 vaultStorage.users[account].setOwed(owed);47 vaultStorage.totalBorrows = vaultCache.totalBorrows = vaultCache.totalBorrows + amount;48
49 logBorrowChange(account, prevOwed, owed);50}
Recommendation:
We advise the BorrowUtils::updateUserBorrow
function to accept an Owed
/ uint256
argument that indicates whether the newOwed
value should be incremented and by how much, optimizing the code's gas cost by one warm SSTORE
operation.
A similar optimization can be applied for the BorrowUtils::decreaseBorrow
function albeit with different operations based on an Assets
instead of Owed
argument.
Alleviation (fb2dd77a6ff9b7f710edb48e7eb5437e0db4fc1a):
The code has been optimized per our recommendation, splitting the BorrowUtils::updateUserBorrow
function into the BorrowUtils::loadUserBorrow
and BorrowUtils::setUserBorrow
functions and thus permitting them to be invoked separately in an optimal way.
BUS-03C: Inefficient mapping
Lookups
Type | Severity | Location |
---|---|---|
Gas Optimization | BorrowUtils.sol:L33, L36, L37 |
Description:
The linked statements perform key-based lookup operations on mapping
declarations from storage multiple times for the same key redundantly.
Example:
29function updateUserBorrow(VaultCache memory vaultCache, address account)30 private31 returns (Owed newOwed, Owed prevOwed)32{33 prevOwed = vaultStorage.users[account].getOwed();34 newOwed = getCurrentOwed(vaultCache, account, prevOwed);35
36 vaultStorage.users[account].setOwed(newOwed);37 vaultStorage.users[account].interestAccumulator = vaultCache.interestAccumulator;38}
Recommendation:
As the lookups internally perform an expensive keccak256
operation, we advise the lookups to be cached wherever possible to a single local declaration that either holds the value of the mapping
in case of primitive types or holds a storage
pointer to the struct
contained.
As the compiler's optimizations may take care of these caching operations automatically at-times, we advise the optimization to be selectively applied, tested, and then fully adopted to ensure that the proposed caching model indeed leads to a reduction in gas costs.
Alleviation (fb2dd77a6ff9b7f710edb48e7eb5437e0db4fc1a):
The exhibit's recommendation has been applied to the partial version of the original function under BorrowUtils::setUserBorrow
, rendering the exhibit alleviated.