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: 60/113
Findings: 2
Award: $76.06
🌟 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.0364 USDC - $52.04
The contracts should be deployed using the most up-to-date, recent version of Solidity. Consider switching to a 0.8.x version, preferably a stable one (e.g. 0.8.4 - 0.8.7).
Using =0.7.6:
In src/core/contracts/AlgebraFactory.sol, the setOwner(), setFarmingAddress(), and setVaultAddress() methods should have checks to ensure the address is not accidentally set to the 0-address.
Original:
/// @inheritdoc IAlgebraFactory function setOwner(address _owner) external override onlyOwner { require(owner != _owner); // should check to ensure it isn't 0 address emit Owner(_owner); owner = _owner; } /// @inheritdoc IAlgebraFactory function setFarmingAddress(address _farmingAddress) external override onlyOwner { require(farmingAddress != _farmingAddress); // should check to ensure it isn't 0 address emit FarmingAddress(_farmingAddress); farmingAddress = _farmingAddress; } /// @inheritdoc IAlgebraFactory function setVaultAddress(address _vaultAddress) external override onlyOwner { require(vaultAddress != _vaultAddress); // should check to ensure it isn't 0 address emit VaultAddress(_vaultAddress); vaultAddress = _vaultAddress; }
Fix:
/// @inheritdoc IAlgebraFactory function setOwner(address _owner) external override onlyOwner { require(owner != _owner); require(_owner != address(0)); emit Owner(_owner); owner = _owner; } /// @inheritdoc IAlgebraFactory function setFarmingAddress(address _farmingAddress) external override onlyOwner { require(farmingAddress != _farmingAddress); require(_farmingAddress != address(0)); emit FarmingAddress(_farmingAddress); farmingAddress = _farmingAddress; } /// @inheritdoc IAlgebraFactory function setVaultAddress(address _vaultAddress) external override onlyOwner { require(vaultAddress != _vaultAddress); require(_vaultAddress != address(0)); emit VaultAddress(_vaultAddress); vaultAddress = _vaultAddress; }
Use scientific notation rather than exponentiation for big numbers. Places where this could be implemented:
🌟 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
24.0182 USDC - $24.02
Splitting up require()/revert() statements that use && saves gas.
Places where require() statements exist with && (and should be split up):
In src/core/contracts/libraries/DataStorage.sol, the getTimePoints() method calls secondsAgos.length multiple times (including in a for loop). It should be cached in a stack variable rather than being accessed every time (especially in the loop).
Original:
function getTimepoints( Timepoint[UINT16_MODULO] storage self, uint32 time, uint32[] memory secondsAgos, int24 tick, uint16 index, uint128 liquidity ) internal view returns ( int56[] memory tickCumulatives, uint160[] memory secondsPerLiquidityCumulatives, uint112[] memory volatilityCumulatives, uint256[] memory volumePerAvgLiquiditys ) { tickCumulatives = new int56[](secondsAgos.length); // since this is called 4 times, it should be cached in stack variable secondsPerLiquidityCumulatives = new uint160[](secondsAgos.length); volatilityCumulatives = new uint112[](secondsAgos.length); volumePerAvgLiquiditys = new uint256[](secondsAgos.length); uint16 oldestIndex; // check if we have overflow in the past uint16 nextIndex = index + 1; // considering overflow if (self[nextIndex].initialized) { oldestIndex = nextIndex; } Timepoint memory current; for (uint256 i = 0; i < secondsAgos.length; i++) { // .length should not be called on every loop, cache it in a stack variable current = getSingleTimepoint(self, time, secondsAgos[i], tick, index, oldestIndex, liquidity); (tickCumulatives[i], secondsPerLiquidityCumulatives[i], volatilityCumulatives[i], volumePerAvgLiquiditys[i]) = ( current.tickCumulative, current.secondsPerLiquidityCumulative, current.volatilityCumulative, current.volumePerLiquidityCumulative ); } }
Fix:
function getTimepoints( Timepoint[UINT16_MODULO] storage self, uint32 time, uint32[] memory secondsAgos, int24 tick, uint16 index, uint128 liquidity ) internal view returns ( int56[] memory tickCumulatives, uint160[] memory secondsPerLiquidityCumulatives, uint112[] memory volatilityCumulatives, uint256[] memory volumePerAvgLiquiditys ) { uint256 secondsAgosLength = secondsAgos.length; tickCumulatives = new int56[](secondsAgosLength); secondsPerLiquidityCumulatives = new uint160[](secondsAgosLength); volatilityCumulatives = new uint112[](secondsAgosLength); volumePerAvgLiquiditys = new uint256[](secondsAgosLength); uint16 oldestIndex; // check if we have overflow in the past uint16 nextIndex = index + 1; // considering overflow if (self[nextIndex].initialized) { oldestIndex = nextIndex; } Timepoint memory current; for (uint256 i = 0; i < secondsAgosLength; i++) { current = getSingleTimepoint(self, time, secondsAgos[i], tick, index, oldestIndex, liquidity); (tickCumulatives[i], secondsPerLiquidityCumulatives[i], volatilityCumulatives[i], volumePerAvgLiquiditys[i]) = ( current.tickCumulative, current.secondsPerLiquidityCumulative, current.volatilityCumulative, current.volumePerLiquidityCumulative ); } }
In src/core/contracts/libraries/DataStorage.sol (at line 307), i++ is used. ++i uses less gas, and so it could be switched to this.