Omniscia Morpho Labs Audit
SupplyHarvestVault Code Style Findings
SupplyHarvestVault Code Style Findings
SHV-01C: Ineffectual Usage of Safe Arithmetics
Type | Severity | Location |
---|---|---|
Language Specific | SupplyHarvestVault.sol:L147 |
Description:
The linked mathematical operation is guaranteed to be performed safely by surrounding conditionals evaluated in either require
checks or if-else
constructs.
Example:
145rewardsFee = rewardsAmount.percentMul(harvestingFeeMem);146rewardsFees[i] = rewardsFee;147rewardsAmount -= rewardsFee;
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:
The Morpho team has wrapped the referenced statement as well as the accumulation of fees in an unchecked
code block. We assume that the Morpho team has validated the addition accumulation cannot overflow and as such mark this exhibit as addressed.
SHV-02C: Inefficient Reward Fee Supply Workflow
Type | Severity | Location |
---|---|---|
Gas Optimization | SupplyHarvestVault.sol:L148 |
Description:
The reward fee is transferred on each iteration for the exact same asset in the current implementation which is inefficient.
Example:
102function harvest()103 external104 returns (105 address[] memory rewardTokens,106 uint256[] memory rewardsAmounts,107 uint256[] memory rewardsFees108 )109{110 address poolTokenMem = poolToken;111
112 {113 address[] memory poolTokens = new address[](1);114 poolTokens[0] = poolTokenMem;115 (rewardTokens, rewardsAmounts) = morpho.claimRewards(poolTokens, false);116 }117
118 address assetMem = asset();119 ISwapper swapperMem = swapper;120 uint16 harvestingFeeMem = harvestingFee;121 uint256 nbRewardTokens = rewardTokens.length;122 uint256 toSupply;123 rewardsFees = new uint256[](nbRewardTokens);124
125 for (uint256 i; i < nbRewardTokens; ) {126 uint256 rewardsAmount = rewardsAmounts[i];127
128 if (rewardsAmount > 0) {129 ERC20 rewardToken = ERC20(rewardTokens[i]);130
131 // Note: Uniswap pairs are considered to have enough market depth.132 // The amount swapped is considered low enough to avoid relying on any oracle.133 if (assetMem != address(rewardToken)) {134 rewardToken.safeTransfer(address(swapperMem), rewardsAmount);135 rewardsAmount = swapperMem.executeSwap(136 address(rewardToken),137 rewardsAmount,138 assetMem,139 address(this)140 );141 }142
143 uint256 rewardsFee;144 if (harvestingFeeMem > 0) {145 rewardsFee = rewardsAmount.percentMul(harvestingFeeMem);146 rewardsFees[i] = rewardsFee;147 rewardsAmount -= rewardsFee;148 ERC20(assetMem).safeTransfer(msg.sender, rewardsFee);149 }150
151 rewardsAmounts[i] = rewardsAmount;152 toSupply += rewardsAmount;153
154 emit Harvested(msg.sender, address(rewardToken), rewardsAmount, rewardsFee);155 }156
157 unchecked {158 ++i;159 }160 }161
162 morpho.supply(poolTokenMem, address(this), toSupply);163}
Recommendation:
We advise the total reward fee to be accumulated similarly to the toSupply
variable and a single transfer to be performed at the end of the function's execution.
Alleviation:
The fees are now accumulated instead and transferred in a single action at the end of the function's execution thereby optimizing the gas cost of the function significantly.