Platform: Code4rena
Start Date: 07/06/2022
Pot Size: $75,000 USDC
Total HM: 11
Participants: 77
Period: 7 days
Judge: gzeon
Total Solo HM: 7
Id: 124
League: ETH
Rank: 36/77
Findings: 2
Award: $136.79
π Selected for report: 0
π Solo Findings: 0
π Selected for report: berndartmueller
Also found by: 0x1f8b, 0x29A, 0xDjango, 0xNazgul, 0xNineDec, 0xf15ers, 0xkatana, 0xmint, Bronicle, Chom, Cityscape, Deivitto, Funen, GimelSec, GreyArt, IllIllI, JC, Lambda, Meera, Nethermind, Picodes, PierrickGT, Ruhum, Sm4rty, Tadashi, TerrierLover, TomJ, Trumpero, Waze, _Adam, antonttc, ayeslick, c3phas, catchup, cccz, cloudjunky, cryptphi, csanuragjain, delfin454000, dipp, ellahi, fatherOfBlocks, hake, hansfriese, hyh, joestakey, jonah1005, kenzo, minhquanym, oyc_109, sach1r0, saian, simon135, slywaters, sorrynotsorry, sseefried, unforgiven, xiaoming90, z3s, zzzitron
89.1872 USDC - $89.19
A known vulnerable compiler version may accidentally be selected or security tools might fall-back to an older compiler version ending up checking a different EVM compilation that is ultimately deployed on the blockchain.
wfCashERC4626.sol::2 => pragma solidity ^0.8.0;
Avoid floating pragmas for non-library contracts. It is recommended to pin to a concrete compiler version.
The usage of deprecated library functions should be discouraged.
wfCashBase.sol::68 => assetToken.safeApprove(address(NotionalV2), type(uint256).max); wfCashBase.sol::73 => underlyingToken.safeApprove(address(NotionalV2), type(uint256).max);
Use safeIncreaseAllowance
/ safeDecreaseAllowance
instead of safeApprove
.
Missing @return
natspec throughout the codebase
manual
π Selected for report: IllIllI
Also found by: 0v3rf10w, 0x1f8b, 0x29A, 0xKitsune, 0xNazgul, 0xSolus, 0xf15ers, 0xkatana, 0xmint, 8olidity, Chom, Cityscape, DavidGialdi, Deivitto, ElKu, Fitraldys, Funen, GreyArt, Lambda, Meera, Picodes, PierrickGT, Sm4rty, Tadashi, TerrierLover, TomJ, Tomio, UnusualTurtle, Waze, _Adam, antonttc, asutorufos, berndartmueller, c3phas, catchup, csanuragjain, delfin454000, djxploit, ellahi, fatherOfBlocks, hake, hansfriese, hyh, joestakey, kaden, minhquanym, oyc_109, rfa, sach1r0, saian, samruna, simon135, slywaters, ynnad
47.6016 USDC - $47.60
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.
NotionalTradeModule.sol::238 => for(uint256 i = 0; i < modules.length; i++) { NotionalTradeModule.sol::254 => for(uint256 i = 0; i < modules.length; i++) { NotionalTradeModule.sol::393 => for(uint256 i = 0; i < positionsLength; i++) { NotionalTradeModule.sol::519 => uint32 minImpliedRate = 0; NotionalTradeModule.sol::605 => for(uint256 i = 0; i < positionsLength; i++) { NotionalTradeModule.sol::618 => for(uint256 i = 0; i < positionsLength; i++) {
Remove explicit zero initialization.
Contracts in scope use pragma solidity ^0.8.0
, allowing wide enough range of versions.
wfCashERC4626.sol::2 => pragma solidity ^0.8.0;
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.
Shortening revert strings to fit in 32 bytes will decrease deployment time gas and will decrease runtime gas when the revert condition is met. Revert strings that are longer than 32 bytes require at least one additional mstore, along with additional overhead for computing memory offset, etc.
NotionalTradeModule.sol::169 => require(_setToken.isComponent(address(_sendToken)), "Send token must be an index component"); NotionalTradeModule.sol::199 => require(_setToken.isComponent(address(wrappedfCash)), "FCash to redeem must be an index component"); NotionalTradeModule.sol::378 => require(wrappedfCashAddress.isContract(), "WrappedfCash not deployed for given parameters"); NotionalTradeModule.sol::573 => require(_paymentToken == assetToken, "Token is neither asset nor underlying token");
Shorten the revert strings to fit in 32 bytes, or use custom errors if >0.8.4.
Reading array length at each iteration of the loop takes 6 gas (3 for mload and 3 to place memory_offset) in the stack. Caching the array length in the stack saves around 3 gas per iteration.
NotionalTradeModule.sol::238 => for(uint256 i = 0; i < modules.length; i++) { NotionalTradeModule.sol::254 => for(uint256 i = 0; i < modules.length; i++) {
Store the arrayβs length in a variable before the for-loop.
++i
costs less gas compared to i++
or i += 1
++i
costs less gas compared to i++
or i += 1
for unsigned integer, as pre-increment is cheaper (about 5 gas per iteration). This statement is true even with the optimizer enabled.
NotionalTradeModule.sol::238 => for(uint256 i = 0; i < modules.length; i++) { NotionalTradeModule.sol::254 => for(uint256 i = 0; i < modules.length; i++) { NotionalTradeModule.sol::393 => for(uint256 i = 0; i < positionsLength; i++) { NotionalTradeModule.sol::605 => for(uint256 i = 0; i < positionsLength; i++) { NotionalTradeModule.sol::618 => for(uint256 i = 0; i < positionsLength; i++) {
Use ++i
instead of i++
to increment the value of an uint variable.
Same thing for --i
and i--
.
c4udit, manual