Platform: Code4rena
Start Date: 26/09/2022
Pot Size: $50,000 USDC
Total HM: 13
Participants: 113
Period: 5 days
Judge: 0xean
Total Solo HM: 6
Id: 166
League: ETH
Rank: 30/113
Findings: 2
Award: $88.95
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: 0xNazgul
Also found by: 0x1f8b, 0x52, 0xDecorativePineapple, 0xSmartContract, 0xmatt, Aeros, Aymen0909, Bnke0x0, Chom, CodingNameKiki, Deivitto, DimitarDimitrov, IllIllI, JC, Jeiwan, Lambda, Matin, Migue, Mukund, Ocean_Sky, Olivierdem, RaymondFam, RockingMiles, Rolezn, Ruhum, Satyam_Sharma, Shinchan, Tomo, Trabajo_de_mates, V_B, Waze, __141345__, a12jmx, ajtra, asutorufos, aysha, brgltd, bulej93, carrotsmuggler, catchup, cccz, chrisdior4, cryptonue, cryptphi, d3e4, defsec, delfin454000, durianSausage, erictee, fatherOfBlocks, gogo, kaden, karanctf, ladboy233, lukris02, mahdikarimi, martin, mics, natzuu, oyc_109, p_crypt0, pedr02b2, rbserver, reassor, rotcivegaf, rvierdiiev, sikorico, slowmoses, sorrynotsorry, tnevler, trustindistrust
52.0441 USDC - $52.04
It's a best practice to use the latest compiler version. The specified minimum compiler version is quite old (0.7.6). Older compilers might be susceptible to some bugs. It's recommended changing the solidity version pragma to the latest version to enforce the use of an up-to-date compiler.
A list of known compiler bugs and their severity can be found here: https://etherscan.io/solcbuginfo
To check the bugfixed and improvements of latest versions see the following link
Update the pragma to 0.8.16
AlgebraFactory.sol#L2 AlgebraPool.sol#L2 AlgebraPoolDeployer.sol#L2 DataStorageOperator.sol#L2 AdaptiveFee.sol#L2 Constants.sol#L2 DataStorage.sol#L2 PriceMovementMath.sol#L2 TickManager.sol#L2 TickTable.sol#L2 TokenDeltaMath.sol#L2 PoolImmutables.sol#L2 PoolState.sol#L2
AlgebraFactory.sol#L54 AlgebraFactory.sol#L55 DataStorageOperator.sol#L33
AlgebraFactory.sol AlgebraPool.sol AlgebraPoolDeployer.sol DataStorageOperator.sol AdaptiveFee.sol Constants.sol DataStorage.sol PriceMovementMath.sol TickManager.sol TickTable.sol TokenDeltaMath.sol PoolImmutables.sol PoolState.sol
🌟 Selected for report: IllIllI
Also found by: 0x1f8b, 0x5rings, 0xNazgul, 0xRoxas, 0xSmartContract, 0xbepresent, 0xmatt, Aeros, Amithuddar, Awesome, Aymen0909, B2, Bnke0x0, ChristianKuri, CodingNameKiki, Deivitto, Diraco, Fitraldys, HardlyCodeMan, JC, Mukund, Noah3o6, Olivierdem, RaymondFam, ReyAdmirado, RockingMiles, Rolezn, Ruhum, Saintcode_, Shinchan, SnowMan, TomJ, Tomio, Tomo, V_B, Waze, __141345__, ajtra, asutorufos, aysha, beardofginger, bobirichman, brgltd, bulej93, c3phas, ch0bu, cryptonue, defsec, delfin454000, dharma09, durianSausage, emrekocak, erictee, fatherOfBlocks, francoHacker, gianganhnguyen, gogo, imare, kaden, karanctf, ladboy233, lukris02, m_Rassska, martin, medikko, mics, natzuu, oyc_109, peiw, rbserver, ret2basic, rotcivegaf, saian, shark, slowmoses, tnevler, trustindistrust, zeesaw, zishansami
36.908 USDC - $36.91
++I (--I) cost less gas than I++ (I--) especially in a loop.
contract TestPost { function testPost() public { uint256 i; i++; } } contract TestPre { function testPre() public { uint256 i; ++i; } }
Storage array length checks incur an extra Gwarmaccess (100 gas) per loop. Store the array length in a variable and use it in the for loop helps to save gas
Split of conditions of an require sentence in different requires sentences can save gas
AlgebraFactory.sol#L110 AlgebraPool.sol#L739 AlgebraPool.sol#L743 AlgebraPool.sol#L953 AlgebraPool.sol#L968 DataStorageOperator.sol#L46
In cases where we used a variable from state assigned to a local variable it's the same gas save.
contract TestA { uint256 _paramA; function Test () public returns (bool) { return _paramA > 0; } } contract TestB { uint256 _paramA; function Test () public returns (bool) { return _paramA != 0; } } contract TestC { uint256 _paramA; function Test () public returns (bool) { uint256 aux = _paramA; return aux > 0; } } contract TestD { uint256 _paramA; function Test () public returns (bool) { uint256 aux = _paramA; return aux != 0; } }
AlgebraPool.sol#L224 AlgebraPool.sol#L228 AlgebraPool.sol#L237 AlgebraPool.sol#L434 AlgebraPool.sol#L451 AlgebraPool.sol#L452 AlgebraPool.sol#L454 AlgebraPool.sol#L455 AlgebraPool.sol#L469 AlgebraPool.sol#L505 AlgebraPool.sol#L506 AlgebraPool.sol#L617 AlgebraPool.sol#L667 AlgebraPool.sol#L808 AlgebraPool.sol#L814 AlgebraPool.sol#L898 AlgebraPool.sol#L904 AlgebraPool.sol#L911 AlgebraPool.sol#L924 AlgebraPool.sol#L927 AlgebraPool.sol#L938 AlgebraPool.sol#L941 DataStorageOperator.sol#L138 DataStorageOperator.sol#L139 DataStorage.sol#L80 PriceMovementMath.sol#L52 PriceMovementMath.sol#L53
This is especially with state variables. In the following example I'm trying to demostrate the save gas in a loop of 10 iterations.
contract TestA { uint256 i; function Test () public { for(;i<10;){ i += 1; } } } contract TestB { uint256 i; function Test () public { for(;i<10;){ i = i + 1; } } }
AlgebraPool.sol#L257 AlgebraPool.sol#L258 AlgebraPool.sol#L801 AlgebraPool.sol#L804 AlgebraPool.sol#L810 AlgebraPool.sol#L811 AlgebraPool.sol#L814 AlgebraPool.sol#L922 AlgebraPool.sol#L931 AlgebraPool.sol#L936 AlgebraPool.sol#L945 AdaptiveFee.sol#L84 AdaptiveFee.sol#L88 AdaptiveFee.sol#L92 AdaptiveFee.sol#L96 AdaptiveFee.sol#L100 AdaptiveFee.sol#L104 AdaptiveFee.sol#L107 DataStorage.sol#L79 DataStorage.sol#L80 DataStorage.sol#L81 DataStorage.sol#L83 DataStorage.sol#L119 DataStorage.sol#L251 DataStorage.sol#L252 DataStorage.sol#L255 DataStorage.sol#L256 TickManager.sol#L58 TickManager.sol#L59 TickTable.sol#L92 TickTable.sol#L95 TickTable.sol#L100 TickTable.sol#L112 TickTable.sol#L115
Custom errors are available from solidity version 0.8.4. Custom errors save ~50 gas each time they're hitby avoiding having to allocate and store the revert string. Not defining the strings also save deployment gas.
AlgebraFactory.sol#L43 AlgebraFactory.sol#L60 AlgebraFactory.sol#L62 AlgebraFactory.sol#L63 AlgebraFactory.sol#L78 AlgebraFactory.sol#L85 AlgebraFactory.sol#L92 AlgebraFactory.sol#L109 AlgebraFactory.sol#L110 AlgebraPool.sol#L55 AlgebraPool.sol#L60 AlgebraPool.sol#L61 AlgebraPool.sol#L62 AlgebraPool.sol#L122 AlgebraPool.sol#L134 AlgebraPool.sol#L194 AlgebraPool.sol#L224 AlgebraPool.sol#L229 AlgebraPool.sol#L434 AlgebraPool.sol#L454 AlgebraPool.sol#L455 AlgebraPool.sol#L469 AlgebraPool.sol#L474 AlgebraPool.sol#L475 AlgebraPool.sol#L608 AlgebraPool.sol#L614 AlgebraPool.sol#L636 AlgebraPool.sol#L641 AlgebraPool.sol#L645 AlgebraPool.sol#L731 AlgebraPool.sol#L733 AlgebraPool.sol#L739 AlgebraPool.sol#L743 AlgebraPool.sol#L898 AlgebraPool.sol#L921 AlgebraPool.sol#L935 AlgebraPool.sol#L953 AlgebraPool.sol#L960 AlgebraPool.sol#L968 AlgebraPoolDeployer.sol#L22 AlgebraPoolDeployer.sol#L27 AlgebraPoolDeployer.sol#L37 AlgebraPoolDeployer.sol#L38 DataStorageOperator.sol#L27 DataStorageOperator.sol#L43 DataStorageOperator.sol#L45 DataStorageOperator.sol#L46 DataStorage.sol#L238 DataStorage.sol#L369 PriceMovementMath.sol#L52 PriceMovementMath.sol#L53 PriceMovementMath.sol#L70 PriceMovementMath.sol#L71 PriceMovementMath.sol#L87 TickManager.sol#L96 TickTable.sol#L15 TokenDeltaMath.sol#L30 TokenDeltaMath.sol#L51 PoolState.sol#L41
If 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 of at least 0.8.0 to get overflow protection without SafeMath Use a solidity version of at least 0.8.2 to get compiler automatic inlining Use a solidity version of at least 0.8.3 to get better struct packing and cheaper multiple storage reads Use a solidity version of at least 0.8.4 to get custom errors, which are cheaper at deployment than revert()/require() strings Use a solidity version of at least 0.8.10 to have external calls skip contract existence checks if the external call has a return value. https://github.com/ethereum/solidity/releases
AlgebraFactory.sol#L2 AlgebraPool.sol#L2 AlgebraPoolDeployer.sol#L2 DataStorageOperator.sol#L2 AdaptiveFee.sol#L2 Constants.sol#L2 DataStorage.sol#L2 PriceMovementMath.sol#L2 TickManager.sol#L2 TickTable.sol#L2 TokenDeltaMath.sol#L2 PoolImmutables.sol#L2 PoolState.sol#L2
If a variable is not set/initialized, it is assumed to have the default value (0 for uint, false for bool, address(0) for address,...). Explicitly initializing it with its default value is an anti-pattern and wastes gas.
Use uint256(1) and uint256(2) for true/false to avoid a Gwarmaccess (100 gas), and to avoid Gsset (20000 gas) when changing from �false� to �true�, after having been �true� in the past
AlgebraPool.sol#L293 AlgebraPool.sol#L294 AlgebraPool.sol#L680 AlgebraPool.sol#L686 AlgebraPool.sol#L695 AlgebraPool.sol#L728 DataStorage.sol#L15 DataStorage.sol#L161 DataStorage.sol#L166 TickManager.sol#L27 PoolState.sol#L15
AlgebraFactory.sol#L123 AlgebraPoolDeployer.sol#L51
<x> * 2 is equivalent to <x> << 1 and <x> / 2 is the same as <x> >> 1. The MUL and DIV opcodes cost 5 gas, whereas SHL and SHR only cost 3 gas
When retrieving data from a memory location, assigning the data to a memory variable causes all fields of the struct/array to be read from memory, resulting in a Gcoldsload (2100 gas) for each field of the struct/array. When reading fields from new memory variables, they cause an extra MLOAD instead of a cheap stack read. Rather than declaring a variable with the memory keyword, it is much cheaper to declare a variable with the storage keyword and cache all fields that need to be read again in a stack variable, because the fields actually read will only result in a Gcoldsload.
The only case where the entire struct/array is read into a memory variable is when the entire struct/array is returned by a function, passed to a function that needs memory, or when the array/struct is read from another store array/struc