Omniscia Euler Finance Audit
YieldAggregatorVault Manual Review Findings
YieldAggregatorVault Manual Review Findings
YAV-01M: Capital-Inefficient Limitation Implementations of Allocation System
Type | Severity | Location |
---|---|---|
Mathematical Operations | ![]() | YieldAggregatorVault.sol:L705-L706, L710, L743-L745 |
Description:
The YieldAggregatorVaultModule::_rebalance
function implementation is presently inefficient when dealing with strategy cap and deposit limitations as they are applied after the allocation point proportion has been evaluated.
This results in underutilized capital, as any capital that was meant for a strategy based on its allocation points but cannot be deposited to it due to its cap and / or deposit limit will remain at rest.
Impact:
This finding represents a capital efficiency recommendation rather than a vulnerability and has thus been designated with an unknown
severity rating.
Example:
703uint256 totalAllocationPointsCache = $.totalAllocationPoints;704uint256 totalAssetsAllocatableCache = _totalAssetsAllocatable();705uint256 targetAllocation =706 totalAssetsAllocatableCache * strategyData.allocationPoints / totalAllocationPointsCache;707
708uint120 capAmount = uint120(strategyData.cap.resolve());709// capAmount will be max uint256 if no cap is set710if (targetAllocation > capAmount) targetAllocation = capAmount;
Recommendation:
We advise this approach to be potentially revised, and unutilized capital to optionally carry over to another strategy whereby the relevant caps might not have been achieved.
While this issue can be circumvented with a reconfiguration of the proportions of each strategy, it would remain inefficient as each new deposit and withdrawal would require a re-adjustment of the allocations if one strategy has a higher practical cap limit than the other.
Alleviation:
The Euler Finance team evaluated this exhibit but opted to acknowledge it in the current iteration of the codebase.
YAV-02M: Unconditional Disbursement of Performance Fee
Type | Severity | Location |
---|---|---|
Logical Fault | ![]() | YieldAggregatorVault.sol:L676-L681 |
Description:
The current YieldAggregatorVaultModule::_accruePerformanceFee
function will attempt to mint shares to the fee recipient regardless of whether the maximum share limit has been achieved by the vault.
Such a state will cause the vault to enter a locked state whereby withdrawals become impossible unless unblocked by administrative action that would set the performance fee / recipient to 0
.
Impact:
The likelihood of this event is considered low, and due to its capability to be unblocked via administrative action it has been considered an informational vulnerability.
Example:
666function _accruePerformanceFee(uint256 _yield) private {667 YieldAggregatorStorage storage $ = Storage._getYieldAggregatorStorage();668
669 address cachedFeeRecipient = $.feeRecipient;670 uint96 cachedPerformanceFee = $.performanceFee;671
672 if (cachedFeeRecipient == address(0) || cachedPerformanceFee == 0) return;673
674 (uint256 feeAssets, uint256 feeShares) = _applyPerformanceFee(_yield, cachedPerformanceFee);675
676 if (feeShares != 0) {677 // Move feeAssets from gulpable amount to totalAssetsDeposited to not dilute other depositors.678 $.totalAssetsDeposited += feeAssets;679
680 _mint(cachedFeeRecipient, feeShares);681 }682
683 emit Events.AccruePerformanceFee(cachedFeeRecipient, _yield, feeShares);684}
Recommendation:
We advise the performance fee accrual system to mint the relevant feeShares
only when it is possible to do so, ignoring the accrued fees otherwise.
Alleviation:
The Euler Finance team evaluated this exhibit but opted to acknowledge it in the current iteration of the codebase.
YAV-03M: Incorrect Implementations of EIP-4626 Maximum Restrictions
Type | Severity | Location |
---|---|---|
Logical Fault | ![]() | YieldAggregatorVault.sol:L374-L376, L380-L382 |
Description:
The view
related functions around maximum mint and deposit amounts as per the EIP-4626 standard are presently implemented incorrectly as they indicate no limit is set.
These indications directly contradict the YieldAggregatorVaultModule::_update
function implementation which imposes a cap on mint operations based on the ERC20VotesUpgradeable
dependency.
Impact:
The YieldAggregatorVaultModule
implements deposit limit related functions of the EIP-4626 standard incorrectly, indicating that no limit exists whilst one is enforced during every share mint operation.
Example:
533function _update(address _from, address _to, uint256 _value)534 internal535 override (ERC20VotesUpgradeable, ERC20Upgradeable)536{537 /// call `_update()` on ERC20Upgradeable538 ERC20Upgradeable._update(_from, _to, _value);539
540 /// ERC20VotesUpgradeable `_update()`541 if (_from == address(0)) {542 uint256 supply = _totalSupply();543 uint256 cap = _maxSupply();544 require(supply <= cap, Errors.ERC20ExceededSafeSupply(supply, cap));545 }
Recommendation:
We advise the relevant functions to yield proper limitations for would-be depositors to the YieldAggregatorVaultModule
, ensuring proper conformity to the EIP-4626 standard.
Alleviation:
The EIP-4626 maximum restrictions have been corrected per our recommendation with a slight deviation, yielding the maximum value possible instead of 0
whenever an attempt to measure the maximum precisely reverts.
We consider that the updated measurement mechanism is in-line with the EIP-4626 standard and that the revert
based deviation can be safely acknowledged, rendering this exhibit to be ultimately alleviated.
YAV-04M: Improper Evaluation of Vault Assets
Type | Severity | Location |
---|---|---|
Mathematical Operations | ![]() | YieldAggregatorVault.sol:L771-L775 |
Description:
The current YieldAggregatorVaultModule::_totalAssets
function will yield all the assets that the system has presently deposited as well as any pending interest that has yet to be reflected.
The current asset evaluation mechanism is insecure as it does not account all the pending interest of the vault which is readily available to it, thereby permitting depositors to consistently undervalue the vault's position.
Impact:
The present YieldAggregatorVaultModule::_totalAssets
function implementation will not take into account the full pending interest distributed via the vault's gulp mechanism, thereby permitting new deposits to capture the pending interest incorrectly.
We consider the likelihood of this event to be continual (i.e. high) and the impact to be on average low with certain high-yield cases causing significant damage to existing depositors.
Example:
771function _totalAssets() private view returns (uint256) {772 YieldAggregatorStorage storage $ = Storage._getYieldAggregatorStorage();773
774 return $.totalAssetsDeposited + _interestAccruedFromCache($.interestLeft);775}
Recommendation:
We advise all inflow-related interactions (including performance fee accruals) to evaluate the total assets inclusive of the full pending interest and all outflow-related operations to continue with the same mechanism as presently implemented, ensuring that deposits consistently use the true value of the vault whilst withdrawals use the available value of the vault.
Alleviation:
The Euler Finance team evaluated this exhibit and while they confirm its validity, they have opted to acknowledge it due to time constraints.
In detail, they envision the arbitraged profit in the scenario described to be minimal and gradually smeared therefore rendering it a risky attack to execute whilst also acting as a natural deposit incentivization mechanism.
Based on the fact that the Euler Finance team is fully aware of the exhibit's ramifications and considers the present economic incentives introduced by it desirable, we consider this exhibit to be safely acknowledged.
YAV-05M: Improper Restriction of Harvests
Type | Severity | Location |
---|---|---|
Logical Fault | ![]() | YieldAggregatorVault.sol:L118, L151, L588-L593 |
Description:
As outlined in the technical documentation of the Euler Earn system, an edge case exists whereby loss socialization may be front-run and thus allow a contributor of the vault to avoid its effect.
We do not believe that such a scenario should be permitted as EIP-4626 vaults are expected to fluctuate in value and the current system permits any negative fluctuations to be arbitraged, effectively permitting users to interact with vaults in a risk-free manner.
Impact:
The current harvest cooldown system will continue to be in effect even if a negative yield is meant to be harvested, permitting depositors to front-run the negative yield's realization and affecting any user who did not withdraw in time.
While this vulnerability is known to the Euler Finance team, we consider it to be a non-acknowledgeable one and its impact was assessed as medium based on the combination of a medium likelihood (negative fluctuation during an in-cooldown period) and medium impact (avoidance of loss socialization by directly affecting other users' deposits).
Example:
585function _harvest(bool _isHarvestCoolDownCheckOn, bool _isOnlyCashReserveWithdraw) private returns (bool) {586 YieldAggregatorStorage storage $ = Storage._getYieldAggregatorStorage();587
588 if (589 (_isHarvestCoolDownCheckOn && ($.lastHarvestTimestamp + Constants.HARVEST_COOLDOWN >= block.timestamp))590 && _isOnlyCashReserveWithdraw591 ) {592 return false;593 }
Recommendation:
After discussing with the Euler Finance team, we concluded that the optimal approach to addressing this exhibit would be to introduce the strict evaluation of harvests optionally via a configurational flag of the YieldAggregator
.
Specifically, a YieldAggregator
deployment should be able to be configured to harvest all strategies if a negative yield event occurs ignoring the harvest cooldown.
Alleviation:
After extensive discussions with the Euler Finance team, we concluded that an acknowledgement of the exhibit is appropriate given that the vault can already be configured to execute synchronization operations on each interaction and this configuration can be selectively applied on chains / vaults that the Euler Finance team considers it imperative to do so.