Platform: Code4rena
Start Date: 07/10/2022
Pot Size: $50,000 USDC
Total HM: 4
Participants: 62
Period: 5 days
Judge: 0xean
Total Solo HM: 2
Id: 169
League: ETH
Rank: 44/62
Findings: 1
Award: $20.79
๐ Selected for report: 0
๐ Solo Findings: 0
๐ Selected for report: IllIllI
Also found by: 0x1f8b, 0xNazgul, 0xSmartContract, 0xdeadbeef, B2, Bnke0x0, Deivitto, ElKu, Jujic, KoKo, Pheonix, RaymondFam, RedOneN, RockingMiles, Rolezn, Saintcode_, Shinchan, TomJ, Tomio, __141345__, ajtra, aysha, c3phas, carlitox477, catchup, delfin454000, emrekocak, erictee, fatherOfBlocks, gerdusx, gianganhnguyen, gogo, martin, mcwildy, medikko, oyc_109, pedr02b2, rbserver, ret2basic, rotcivegaf, saian, sakman, zishansami
20.7905 USDC - $20.79
When a function with a memory
array is called externally, the abi.decode()
step has to use a for-loop to copy each index of the calldata
to the memory
index. Each iteration of this for-loop costs at least 60 gas (i.e. 60 * <mem_array>.length
). Using calldata
directly, obliviates the need for such a loop in the contract code and runtime execution.
When arguments are read-only on external functions, the data location should be calldata
5 Instances: -L1GraphTokenGateway.sol lines 290, 331 -Managed.sol line 173 -L2GraphTokenGateway.sol lines 266, 286
REQUIRE()
STATMENTS INSTEAD OF REQUIRE(EXPRESSION && EXPRESSION && ...)
2 Instances: -L1GraphTokenGateway.sol line 142 -Governed.sol line 55 -GraphProxy.sol line 143
L1GraphTokenGateway.sol line 142
The order of the functions inside the if statement in line 142:
require(_escrow != address(0) && Address.isContract(_escrow), "INVALID_ESCROW");
can be switched to:
require(Address.isContract(_escrow) && _escrow != address(0), "INVALID_ESCROW");
for optimal gas usage because Address.isContract(_escrow) is more probable to be FALSE hence second one wonโt be executed and hence save you gas.
Same case in GraphProxy.sol 143
The order of the functions inside the if statement in line 142:
require( _pendingImplementation != address(0) && msg.sender == _pendingImplementation, "Caller must be the pending implementation" );
can be switched to:
require(msg.sender == _pendingImplementation && _pendingImplementation != address(0) , "Caller must be the pending implementation" );
for optimal gas usage because msg.sender == _pendingImplementation is more probable to be FALSE hence second one wonโt be executed and hence save you gas.
>=
COSTS LESS GAS THAN >
The compiler uses opcodes GT
and ISZERO
for solidity code that uses >
, but only requires LT
for >=
, which saves 3 gas
4 Instances: -L1GraphTokenGateway lines 201, 217 -L2GraphTokenGateway lines 146, 147
REQUIRE()
/REVERT()
STRINGS LONGER THAN 32 BYTES COST EXTRA GASEach extra memory word of bytes past the original 32 incurs an MSTORE which costs 3 gas
Instances: -GraphTokenGateway.sol line 21 -Managed.sol line 53 -GraphProxy.sol lines 105, 141, 144 -GraphUpgradeable.sol line 32
PRIVATE
RATHER THAN PUBLIC
FOR CONSTANTS, SAVES GASIf needed, the value can be read from the verified contract source code. Savings are due to the compiler not having to create non-payable getter functions for deployment calldata, and not adding another entry to the method ID table
Use a solidity version above 0.8.0, it integrates overflow/underflow checking so there would be no need to use Safemath