Platform: Code4rena
Start Date: 21/04/2022
Pot Size: $100,000 USDC
Total HM: 18
Participants: 60
Period: 7 days
Judge: gzeon
Total Solo HM: 10
Id: 112
League: ETH
Rank: 33/60
Findings: 2
Award: $254.48
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: IllIllI
Also found by: 0v3rf10w, 0x52, 0xDjango, 0xkatana, Dravee, Funen, Kenshin, Ruhum, StyxRave, Tadashi, TerrierLover, TrungOre, antonttc, berndartmueller, catchup, csanuragjain, defsec, dipp, fatherOfBlocks, hake, horsefacts, hubble, jayjonah8, joestakey, kebabsec, kenta, m4rio_eth, oyc_109, pauliax, peritoflores, rayn, remora, robee, securerodd, simon135, sorrynotsorry, sseefried, z3s
169.5152 USDC - $169.52
CvxCrvRewardsLocker
changes, they will not be able to be updated.If any constant address in CvxCrvRewardsLocker
changes, they will not be able to be updated.
Also valid for(list not exhaustive): -CTokenRegistry -ConvexStrategyBase -StrategySwaper
CvxCrvRewardsLocker.setTreasury; L147-L154
Accidentally setting treasury
to address zero may lead to losing all funds when withdrawing.
TopUpActionFeeHandler.actionContract#L55
If actionContract
is accidentally set to zero the payFees
function would become inaccessible because there is no other way to set actionContract
.
safeApprove
from OpenZeppelin has been deprecatedsafeApprove
from OpenZeppelin has been deprecated.
Instead it is recommended to use increase/decrease allowance.
Please refer to SafeERC20.sol#L38
CvxCrvRewardsLocker.withdraw#L156-L164 CvxCrvRewardsLocker.withdraw#L217-L225
Suggest changing withdraw#L156-L164 to fullWithdraw to avoid confusion and improve readability.
CompoundHandler
CompoundHandler#L46 Change tup-up to top-up.
StakerVault.unstakeFor
could bypass allowance.Hook in ERC777 reenters unstakeFor
and bypasses _allowances
update which is only calculated after safeTransfer
.
Beaware that if LpToken ever uses the ERC777 standard this could be an attack vector.
#0 - chase-manning
2022-04-28T10:09:06Z
I consider this report to be of particularly high quality
🌟 Selected for report: joestakey
Also found by: 0v3rf10w, 0x1f8b, 0x4non, 0xDjango, 0xNazgul, 0xkatana, 0xmint, Dravee, Funen, IllIllI, MaratCerby, NoamYakov, Tadashi, TerrierLover, Tomio, WatchPug, catchup, defsec, fatherOfBlocks, hake, horsefacts, kenta, oyc_109, pauliax, rayn, rfa, robee, saian, securerodd, simon135, slywaters, sorrynotsorry, tin537, z3s
84.957 USDC - $84.96
GAS
processExpiredLocks
CvxCrvRewardsLocker.processExpiredLocks; L133-L145
Gas could be saved by changing:
function processExpiredLocks(bool relock) external override returns (bool) { if (relock) { require(!prepareWithdrawal, Error.PREPARED_WITHDRAWAL); } if (relock) { ICvxLocker(CVX_LOCKER).processExpiredLocks(relock); } else { ICvxLocker(CVX_LOCKER).withdrawExpiredLocksTo(treasury); } return true; }
To:
function processExpiredLocks(bool relock) external override returns (bool) { if (relock) { require(!prepareWithdrawal, Error.PREPARED_WITHDRAWAL); ICvxLocker(CVX_LOCKER).processExpiredLocks(relock); } else { ICvxLocker(CVX_LOCKER).withdrawExpiredLocksTo(treasury); } return true; }
TopUpActionFeeHandler.payFees#L81-L109
If lpToken.safeTransferFrom
reverts keeperAmount
and treasuryAmount
will be unnecessarily calculated.
uint256 keeperAmount = amount.scaledMul(getKeeperFeeFraction()); uint256 treasuryAmount = amount.scaledMul(getTreasuryFeeFraction()); LpToken lpToken = LpToken(lpTokenAddress); lpToken.safeTransferFrom(msg.sender, address(this), amount);
I suggest setting keeperAmount
and treasuryAmount
after lpToken.safeTransferFrom
as seen below.
LpToken lpToken = LpToken(lpTokenAddress); lpToken.safeTransferFrom(msg.sender, address(this), amount); uint256 keeperAmount = amount.scaledMul(getKeeperFeeFraction()); uint256 treasuryAmount = amount.scaledMul(getTreasuryFeeFraction());
hasAnyRole
can be more gas efficientRoleManager.hasAnyRole#L73-L86
i = 0
as zero is already the default value.roles.length
would save gas from calculating it every iteration++i
is more effecient than using a postfix i++
In summary I suggest changing it from:
for (uint256 i = 0; i < roles.length; i++) { if (hasRole(roles[i], account)) { return true; } }
To:
size = roles.length; for (uint256 i; i < size; ++i) { if (hasRole(roles[i], account)) { return true; } }
Also valid for(list not exhaustive):