Platform: Code4rena
Start Date: 20/09/2022
Pot Size: $30,000 USDC
Total HM: 12
Participants: 198
Period: 3 days
Judge: 0xean
Total Solo HM: 2
Id: 164
League: ETH
Rank: 189/198
Findings: 1
Award: $9.09
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: IllIllI
Also found by: 0v3rf10w, 0x040, 0x1f8b, 0x4non, 0x85102, 0xA5DF, 0xDanielC, 0xNazgul, 0xSmartContract, 0xbepresent, 0xc0ffEE, 0xsam, 2997ms, AkshaySrivastav, Amithuddar, Atarpara, Aymen0909, B2, Bnke0x0, CertoraInc, Chom, ChristianKuri, CodingNameKiki, Deivitto, Diana, DimitarDimitrov, Diraco, Funen, JC, JLevick, JohnSmith, Junnon, KIntern_NA, Lambda, MasterCookie, Matin, Noah3o6, Ocean_Sky, OptimismSec, RaymondFam, Respx, ReyAdmirado, RockingMiles, Rohan16, Rolezn, Ruhum, Saintcode_, Satyam_Sharma, Sm4rty, SnowMan, SooYa, Sta1400, StevenL, Tadashi, Tagir2003, TomJ, Tomio, Tomo, V_B, Waze, WilliamAmbrozic, Yiko, __141345__, a12jmx, adriro, ajtra, ak1, async, aysha, beardofginger, bobirichman, brgltd, bulej93, c3phas, carrotsmuggler, caventa, ch0bu, cryptostellar5, cryptphi, csanuragjain, d3e4, delfin454000, dharma09, djxploit, durianSausage, eighty, emrekocak, erictee, exd0tpy, fatherOfBlocks, francoHacker, gianganhnguyen, gogo, got_targ, hxzy, ignacio, ikbkln, imare, indijanc, jag, jpserrat, karanctf, ladboy233, leosathya, lucacez, lukris02, m9800, malinariy, martin, medikko, mics, millersplanet, mrpathfindr, nalus, natzuu, neko_nyaa, oyc_109, pauliax, peanuts, pedroais, peiw, pfapostol, prasantgupta52, rbserver, ret2basic, rokinot, rotcivegaf, rvierdiiev, sach1r0, samruna, seyni, slowmoses, subtle77, supernova, tgolding55, tibthecat, tnevler, w0Lfrum, yaemsobak, zishansami
9.086 USDC - $9.09
Custom errors from Solidity 0.8.4 are cheaper than revert strings.
https://blog.soliditylang.org/2021/04/21/custom-errors/
Examples in contracts:
require(supply_ > 0, "NO_ZERO_MINT");
require(initialSupply_ > 0 || maxSupply_ > 0, "INVALID_AMOUNT");
require(account != address(0), "INVALID_ADDRESS");
require(amount <= mintableSupply, "INVALID_AMOUNT");
require(_admins[_msgSender()], "ADMIN_ACCESS_REQUIRED");
require(admin != address(0), "INVALID_ADDRESS");
require(address(_tokenAddress) != address(0), "INVALID_ADDRESS");
require(_claim.startTimestamp > 0, "NO_ACTIVE_CLAIM");
require(_claim.isActive == true, "NO_ACTIVE_CLAIM");
require(_claim.startTimestamp == 0, "CLAIM_ALREADY_EXISTS");
require(_recipient != address(0), "INVALID_ADDRESS"); require(_linearVestAmount + _cliffAmount > 0, "INVALID_VESTED_AMOUNT"); require(_startTimestamp > 0, "INVALID_START_TIMESTAMP");
require(_startTimestamp < _endTimestamp, "INVALID_END_TIMESTAMP"); // _endTimestamp must be after _startTimestamp require(_releaseIntervalSecs > 0, "INVALID_RELEASE_INTERVAL"); require((_endTimestamp - _startTimestamp) % _releaseIntervalSecs == 0, "INVALID_INTERVAL_LENGTH");
require( ( _cliffReleaseTimestamp > 0 && _cliffAmount > 0 && _cliffReleaseTimestamp <= _startTimestamp ) || ( _cliffReleaseTimestamp == 0 && _cliffAmount == 0 ), "INVALID_CLIFF");
require(tokenAddress.balanceOf(address(this)) >= numTokensReservedForVesting + allocatedAmount, "INSUFFICIENT_BALANCE");
require(_startTimestamps.length == length && _endTimestamps.length == length && _cliffReleaseTimestamps.length == length && _releaseIntervalsSecs.length == length && _linearVestAmounts.length == length && _cliffAmounts.length == length, "ARRAY_LENGTH_MISMATCH" );
require(allowance > usrClaim.amountWithdrawn, "NOTHING_TO_WITHDRAW");
require(amountRemaining >= _amountRequested, "INSUFFICIENT_BALANCE");
require( _claim.amountWithdrawn < finalVestAmt, "NO_UNVESTED_AMOUNT");
require(_otherTokenAddress != tokenAddress, "INVALID_TOKEN"); // tokenAddress address is already sure to be nonzero due to constructor
require(bal > 0, "INSUFFICIENT_BALANCE");
!= 0 costs less gas compared to > 0 for unsigned integer.
Examples in contracts:
require(supply_ > 0, "NO_ZERO_MINT");
require(initialSupply_ > 0 || maxSupply_ > 0, "INVALID_AMOUNT");
if(initialSupply_ > 0) {
if(mintableSupply > 0) {
require(_claim.startTimestamp > 0, "NO_ACTIVE_CLAIM");
require(_linearVestAmount + _cliffAmount > 0, "INVALID_VESTED_AMOUNT"); // Actually only one of linearvested/cliff amount must be 0, not necessarily both require(_startTimestamp > 0, "INVALID_START_TIMESTAMP");
require(_releaseIntervalSecs > 0, "INVALID_RELEASE_INTERVAL");
require( ( _cliffReleaseTimestamp > 0 && _cliffAmount > 0 && _cliffReleaseTimestamp <= _startTimestamp ) || ( _cliffReleaseTimestamp == 0 && _cliffAmount == 0 ), "INVALID_CLIFF");
require(bal > 0, "INSUFFICIENT_BALANCE");
When a variable is not initialized, it will have its default values. For example, 0 for uint, false for bool and address(0) for address.
uint a = 0;
to
uint a;
Examples in contracts:
uint112 public numTokensReservedForVesting = 0;
uint112 vestAmt = 0;
for (uint256 i = 0; i < length; i++) {
for(...; i++)
to
for(...; ++i)
Examples in contracts:
for (uint256 i = 0; i < length; i++) {
Instead of using the && operator in a single require statement to check multiple conditions,using multiple require statements with 1 condition per require statement will save gas.
require(a && b);
to
require(a); require(b);
Examples in code: Line 344-351
require(_startTimestamps.length == length && _endTimestamps.length == length && _cliffReleaseTimestamps.length == length && _releaseIntervalsSecs.length == length && _linearVestAmounts.length == length && _cliffAmounts.length == length, "ARRAY_LENGTH_MISMATCH" );
In Solidity 0.8+, there’s a default overflow check on unsigned integers. you can uncheck this in for-loops and save some gas.
for (uint256 i; i < length; ++i) { // ... }
to
for (uint256 i; i < length;) { // ... unchecked { ++i; } }
Examples in code:
for (uint256 i = 0; i < length; i++) {
#0 - 0xean
2022-09-25T22:44:15Z
Warden submitted as QA report, moved to Gas