Platform: Code4rena
Start Date: 15/06/2022
Pot Size: $35,000 USDC
Total HM: 1
Participants: 36
Period: 3 days
Judge: Jack the Pug
Total Solo HM: 1
Id: 137
League: ETH
Rank: 22/36
Findings: 1
Award: $83.14
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: IllIllI
Also found by: 0x1f8b, 0xKitsune, 0xNazgul, 0xkatana, Chom, ElKu, JC, Meera, MiloTruck, Picodes, PierrickGT, SooYa, TerrierLover, UnusualTurtle, Waze, _Adam, asutorufos, c3phas, delfin454000, fatherOfBlocks, joestakey, minhquanym, oyc_109, robee, sach1r0, simon135
83.1436 USDC - $83.14
#1 Use require instead &&
use require instead of && for efficient gas cost. change it from
require( address(_nestedAsset) != address(0) && address(_nestedRecords) != address(0) && address(_reserve) != address(0) && address(_feeSplitter) != address(0) && address(_weth) != address(0) && _operatorResolver != address(0) && address(_withdrawer) != address(0), "NF: INVALID_ADDRESS" );
to
require(address(_nestedAsset) != address(0),"NF: INVALID_ADDRESS"); require(address(_nestedRecords) != address(0),"NF: INVALID_ADDRESS"); require(address(_reserve) != address(0),"NF: INVALID_ADDRESS"); require(address(_feeSplitter) != address(0),"NF: INVALID_ADDRESS"); require(address(_weth) != address(0),"NF: INVALID_ADDRESS"); require( _operatorResolver != address(0),"NF: INVALID_ADDRESS"); require(address(_withdrawer) != address(0),"NF: INVALID_ADDRESS");
#2 Change to storage
Use storage instead of memory to reduce the gas fee.
bytes32[] memory operatorsCache = operators;
to
bytes32[] storage operatorsCache = operators;
apply to others.
#3 Looping
default uint is 0 so remove unnecassary explicit can reduce gas. caching the array length can reduce gas it caused access to a local variable is more cheap than query storage / calldata / memory in solidity. pre increment ++i more cheaper gas than post increment i++. i suggest to use pre increment.
#4 Default value and increment
default uint is 0 so remove unnecassary explicit can reduce gas pre increment ++i more cheaper gas than post increment i++. i suggest to use pre increment.
#5 Inequality
non strict inequality are cheaper than strict one. i suggest to use >= or <= instead of > and < if possible.
#6 Caching names.length
caching the names.length can reduce gas it caused access to a local variable is more cheap than query storage / calldata / memory in solidity and it use twice.
#7 Cache the cacheTmp.implementation
cache the cacheTmp.implementation to the memory for reduce the gas fee because it use multiple times.
#8 Use calldata
In the external functions where the function argument is read-only, the function() has an inputed parameter that using memory, if this function didnt change the parameter, its cheaper to use calldata then memory. so we suggest to change it.
#9 Division
A division by 2 can be calculated by shifting one to the right. The div opcode used 5 gas and SHR opcode used 3 gas. Solidity's division operation also includes a division-by-0 prevention by pass using shifting. so i suggest to use >>1.
#10 Sort struct
shorting the struct can reduce gas cost, so change it from
struct CurvePool { address poolAddress; uint96 poolCoinAmount; address lpToken;
to
struct CurvePool { uint96 poolCoinAmount; address poolAddress; address lpToken;
#11 Short the string
reduce size of string error message to bytes32 for cheap gas if possible.
#12 Caching the targets.length
caching the targets.length can reduce gas it caused access to a local variable is more cheap than query storage / calldata / memory in solidity and it use twice.
require(targets.length == values.length, "TimelockController: length mismatch"); require(targets.length == datas.length, "TimelockController: length mismatch");
i suggest to add uint256 _targets = targets.length;
uint256 _targets = targets.length; require(_targets == values.length, "TimelockController: length mismatch"); require(_targets == datas.length, "TimelockController: length mismatch");
#0 - Yashiru
2022-06-22T15:31:24Z
Gas optimization confirmed
#1 - obatirou
2022-06-22T16:11:49Z
Examples are not relevant:
BeefyVaultOperator
we cannot use calldata (either storage or memory for contructor)callOperator
, MixinOperatorResolver
we modify the variable hence we cannot use calldata#2 - Yashiru
2022-06-23T08:22:08Z
Gas optimization confirmed
#3 - Yashiru
2022-06-24T11:42:42Z
Duplicated of #49 at TimelockControllerEmergency.sol
#4 - obatirou
2022-06-24T12:56:27Z
Duplicate of point 2 from issue #62
#5 - Yashiru
2022-06-24T13:33:40Z
Duplicated of #89 at Use Shift Right/Left instead of Division/Multiplication
#6 - Yashiru
2022-06-24T15:41:29Z
Duplicated of #2 at For loop optimizaion
Duplicated of #2 at For loop optimizaion
#7 - maximebrugel
2022-06-24T15:44:26Z
Two addresses can't be packed (20 bytes and 20 bytes).
#8 - obatirou
2022-06-24T15:49:48Z
https://github.com/code-423n4/2022-06-nested-findings/issues/29#issuecomment-1165702145
#9 - maximebrugel
2022-06-24T16:19:36Z
#10 - Yashiru
2022-06-27T10:20:06Z
nestedRecords.getAssetTokens()
can't return storage datas, data location must be "memory" or "calldata" for return parameter in functioncallOperator()
can't return storage datas, data location must be "memory" or "calldata" for return parameter in functionresolverOperatorsRequired()
can't return storage datas, data location must be "memory" or "calldata" for return parameter in functionabi.decode()
can't return storage datas, data location must be "memory" or "calldata" for return parameter in functionresolverOperatorsRequired()
can't return storage datas, data location must be "memory" or "calldata" for return parameter in function