Platform: Code4rena
Start Date: 07/04/2022
Pot Size: $100,000 USDC
Total HM: 20
Participants: 62
Period: 7 days
Judge: LSDan
Total Solo HM: 11
Id: 107
League: ETH
Rank: 33/62
Findings: 2
Award: $239.97
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: Dravee
Also found by: 0x1f8b, 0xDjango, 0xkatana, AuditsAreUS, Cityscape, Foundation, Funen, Hawkeye, IllIllI, JC, JMukesh, Jujic, Kthere, PPrieditis, Picodes, Ruhum, TerrierLover, TrungOre, WatchPug, berndartmueller, catchup, cccz, cmichel, delfin454000, dy, ellahi, hickuphh3, horsefacts, hubble, hyh, ilan, jayjonah8, kebabsec, kenta, minhquanym, pauliax, rayn, reassor, rfa, robee, samruna
152.5804 USDC - $152.58
StrategyPUSDConvex.sol#L303-L307
.
function withdrawJPEG(address _to) external onlyController { // claim from convex rewards pool convexConfig.baseRewardPool.getReward(address(this), true); jpeg.safeTransfer(_to, jpeg.balanceOf(address(this))); }
Consider adding require(_to != address(0), "INVALID: 0");
to prevent accidental loss of funds.
Not consitently using safetransfers. Some cases of transfer
and transferFrom
without checking return value.
JPEGStaking.sol#L34
, JPEGStaking.sol#L52
, NFTVault.sol#L560
, NFTVault.sol#L899
.
Use safeTransfer
and safeTransferFrom
from OpenZeppelin's library.
_setupRole
function is deprecated in favor of _grantRole
.
https://docs.openzeppelin.com/contracts/4.x/api/access
JPEG.sol#L17
, StableCoin.sol#L26
, FungibleAssetVaultForDAO.sol#L75
, NFTVault.sol#L153
, Controller.sol#L26
, StrategyPUSDConvex.sol#L152
.
/// @param _nftContract The NFT contrat address. It could also be the address of an helper contract
Change contrat
to contract
.
🌟 Selected for report: Dravee
Also found by: 0v3rf10w, 0x1f8b, 0xDjango, 0xNazgul, 0xkatana, Cityscape, Cr4ckM3, FSchmoede, Foundation, Funen, Hawkeye, IllIllI, JMukesh, Meta0xNull, PPrieditis, Picodes, TerrierLover, Tomio, WatchPug, berndartmueller, catchup, delfin454000, dirk_y, ellahi, hickuphh3, ilan, kebabsec, kenta, nahnah, rayn, rfa, robee, rokinot, saian, securerodd, slywaters, sorrynotsorry
87.3915 USDC - $87.39
All the contracts in scope use pragma solidity ^0.8.0
, allowing wide enough range of versions.
pragma version^0.8.0 (contracts/escrow/NFTEscrow.sol#2) pragma version^0.8.0 (contracts/staking/JPEGStaking.sol#2) pragma version^0.8.0 (contracts/vaults/FungibleAssetVaultForDAO.sol#2) pragma version^0.8.0 (contracts/vaults/NFTVault.sol#2) pragma version^0.8.0 (contracts/farming/LPFarming.sol#2) pragma version^0.8.0 (contracts/farming/yVaultLPFarming.sol#2) pragma version^0.8.0 (contracts/tokens/JPEG.sol#2) pragma version^0.8.0 (contracts/tokens/StableCoin.sol#2) pragma version^0.8.0 (contracts/vaults/yVault/Controller.sol#2) pragma version^0.8.0 (contracts/vaults/yVault/strategies/StrategyPUSDConvex.sol#2) pragma version^0.8.0 (contracts/vaults/yVault/yVault.sol#2)
Consider locking compiler version, for example pragma solidity 0.8.6
.
This can have additional benefits, for example using custom errors to save gas and so forth.
Cache length outside of for loop to save gas.
LPFarming.sol#L348
, NFTVault.sol#L181
, NFTVault.sol#L184
, StrategyPUSDConvex.sol#L145
, StrategyPUSDConvex.sol#L319
.
More gas efficient example for LPFarming::claimAll()
.
function claimAll() external nonReentrant noContract(msg.sender) { uint256 len = poolInfo.length; for (uint256 i = 0; i < len; ++i) { _updatePool(i); _withdrawReward(i); }
Similar changes apply for the rest of the for-loops listed above.
!= 0 is cheapear than > 0 when comparing unsigned integers.
LPFarming.sol#L114
, LPFarming.sol#L218
, LPFarming.sol#L239
, LPFarming.sol#L320
, LPFarming.sol#L337
, LPFarming.sol#L354
, yVaultLPFarming.sol#L84
, yVaultLPFarming.sol#L101
, yVaultLPFarming.sol#L118
, yVaultLPFarming.sol#L139
, yVaultLPFarming.sol#L181
, JPEGLock.sol#L40
, JPEGStaking.sol#L32
, JPEGStaking.sol#L46
, FungibleAssetVaultForDAO.sol#L142
, FungibleAssetVaultForDAO.sol#L164
, FungibleAssetVaultForDAO.sol#L180
, FungibleAssetVaultForDAO.sol#L194
, NFTVault.sol#L278
, NFTVault.sol#L365
, NFTVault.sol#L637
, NFTVault.sol#L687
, NFTVault.sol#L764
, NFTVault.sol#L770
, NFTVault.sol#L882
, NFTVault.sol#L926
, StrategyPUSDConvex.sol#L322
, StrategyPUSDConvex.sol#L334
, yVault.sol#L143
, yVault.sol#L167
, yVault.sol#L170
.
Use != 0
instead of > 0
.
Revert strings > 32bytes use more gas.
JPEG.sol#L23
, StableCoin.sol#L41
, StableCoin.sol#L55
, StableCoin.sol#L69
, NFTVault.sol#L394
.
Make revert strings are <= 32bytes.
public
functions that are never called by the contract should be declared external
to save gas.
Controller.sol#L151
, yVault.sol#L115
.
withdraw(IERC20,uint256) should be declared external: - Controller.withdraw(IERC20,uint256) (contracts/vaults/yVault/Controller.sol#151-154) setFarmingPool(address) should be declared external: - YVault.setFarmingPool(address) (contracts/vaults/yVault/yVault.sol#115-118)
If a variable is not set/initialized, it is assumed to have the default value (0, false, 0x0 etc depending on the data type). Explicitly initializing it with its default value is an anti-pattern and wastes gas.
FungibleAssetVaultForDAO.sol#L45
, LPFarming.sol#L348
, NFTVault.sol#L181
, NFTVault.sol#L184
, StrategyPUSDConvex.sol#L145
, StrategyPUSDConvex.sol#L319
.
Remove explicit zero initialization.
In NFTVault::borrow()
, since a new uint256 variable feeAmount
is set to equal organizationFee
and organizationFee
does not get updated after, there is no reason to use feeAmount
when you can just use organizationFee
. Waste of gas.
Get rid of feeAmount
and use organizationFee
instead.
c4rena, manual, slither.