Platform: Code4rena
Start Date: 13/01/2022
Pot Size: $75,000 USDC
Total HM: 9
Participants: 27
Period: 7 days
Judge: leastwood
Total Solo HM: 5
Id: 73
League: ETH
Rank: 17/27
Findings: 2
Award: $92.63
🌟 Selected for report: 0
🚀 Solo Findings: 0
0.0614 LPT - $2.28
6.2568 USDC - $6.26
Jujic
Here you could use unchecked{++i} to save gas since it is more efficient then i++.
for (uint256 i = 0; i < _unbondingLockIds.length; i++)
Remix
#0 - yondonfu
2022-01-23T13:10:03Z
0.3637 LPT - $13.49
37.086 USDC - $37.09
Jujic
Some of these variables can be cached to slightly reduce gas usage
function l1CirculatingSupply() public view returns (uint256) { // After the first update from L1, l1TotalSupply should always be >= l2SupplyFromL1 // The below check is defensive to avoid reverting if this invariant for some reason violated return l1TotalSupply >= l2SupplyFromL1 ? l1TotalSupply - l2SupplyFromL1 : 0; }
Remix
Consider caching the storage variables in the stack.
#0 - yondonfu
2022-01-23T19:51:44Z
0.0614 LPT - $2.28
6.2568 USDC - $6.26
Jujic
Increase gas costs on all onlyRole operations
The MINTER_ROLE
and BURNER_ROLE
variables are marked as constant:
bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE"); bytes32 public constant BURNER_ROLE = keccak256("BURNER_ROLE");
This results in the keccak operation being performed whenever the variable is used, increasing gas costs relative to just storing the output hash. Changing to immutable will only perform hashing on contract deployment which will save gas.
https://github.com/ethereum/solidity/issues/9232#issuecomment-646131646
Change the variable to be immutable rather than constant
#0 - yondonfu
2022-01-23T01:07:49Z
🌟 Selected for report: sirhashalot
Also found by: Dravee, Jujic, WatchPug, aga7hokakological, defsec, gzeon, p4st13r4, robee
0.0387 LPT - $1.43
3.9418 USDC - $3.94
Jujic
Shortening revert strings to fit in 32 bytes will decrease deployment time gas and will decrease runtime gas when the revert condition has been met.
require( _l2Addr != address(0), "L1Migrator#requireValidMigration: INVALID_L2_ADDR" ); require( msg.sender == _l1Addr || recoverSigner(_structHash, _sig) == _l1Addr, "L1Migrator#requireValidMigration: FAIL_AUTH" );
Shorten the revert strings to fit in 32 bytes.
#0 - yondonfu
2022-01-21T16:19:31Z
0.0795 LPT - $2.95
8.1107 USDC - $8.11
Jujic
For the arithmetic operations that will never over/underflow, using the unchecked directive (Solidity v0.8 has default overflow/underflow checks) can save some gas from the unnecessary internal over/underflow checks.
function decreaseL2SupplyFromL1(uint256 _amount) external onlyL2LPTGateway { if (_amount > l2SupplyFromL1) { l2SupplyFromL1 = 0; } else { l2SupplyFromL1 -= _amount; }
Remix
Consider using 'unchecked' where it is safe to do so.
unchecked { l2SupplyFromL1 -= _amount; }
#0 - yondonfu
2022-01-23T01:04:40Z
0.0614 LPT - $2.28
6.2568 USDC - $6.26
Jujic
The local variable used as for loop index need not be initialized to 0 because the default value is 0. Avoiding this anti-pattern can save a few opcodes and therefore a tiny bit of gas.
for (uint256 i = 0; i < _unbondingLockIds.length; i++)
Remix
Remove explicit 0 initialization of for loop index variable.
#0 - yondonfu
2022-01-23T13:10:52Z