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: 160/198
Findings: 1
Award: $9.32
🌟 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.3188 USDC - $9.32
++i/--i
costs less gas than post-increment i++/i--
Saves 6 gas per loop in a for loop
Total instances of this issue: 1
instance #1 Link: https://github.com/code-423n4/2022-09-vtvl/blob/main/contracts/VTVLVesting.sol#L353
contracts/VTVLVesting.sol 353: for (uint256 i = 0; i < length; i++) {
++i/i++
should be placed in unchecked blocks to save gas as it is impossible for them to overflow in for and while loopsUnchecked keyword is available in solidity version 0.8.0
or higher and can be applied to iterator variables to save gas.
Saves more than 30 gas
per loop.
Total instances of this issue: 1
instance #1 Link: https://github.com/code-423n4/2022-09-vtvl/blob/main/contracts/VTVLVesting.sol#L353
contracts/VTVLVesting.sol 353: for (uint256 i = 0; i < length; i++) {
x += y
costs more gas than x = x + y
for state variablesTotal instances of this issue: 3
instance #1 Link: https://github.com/code-423n4/2022-09-vtvl/blob/main/contracts/VTVLVesting.sol#L161
contracts/VTVLVesting.sol 161: vestAmt += _claim.cliffAmount;
instance #2 Link: https://github.com/code-423n4/2022-09-vtvl/blob/main/contracts/VTVLVesting.sol#L179
contracts/VTVLVesting.sol 179: vestAmt += linearVestAmount;
instance #3 Link: https://github.com/code-423n4/2022-09-vtvl/blob/main/contracts/VTVLVesting.sol#L381
contracts/VTVLVesting.sol 381: usrClaim.amountWithdrawn += amountRemaining;
unchecked {}
block where the variable cannot underflow because of a previous require()
require(a <= b); x = b - a
==> require(a <= b); unchecked { x = b - a }
Total instances of this issue: 3
instance #1 Link: https://github.com/code-423n4/2022-09-vtvl/blob/main/contracts/token/VariableSupplyERC20Token.sol#L43
contracts/token/VariableSupplyERC20Token.sol 43: mintableSupply -= amount;
instance #2 Link: https://github.com/code-423n4/2022-09-vtvl/blob/main/contracts/VTVLVesting.sol#L377
contracts/VTVLVesting.sol 377: uint112 amountRemaining = allowance - usrClaim.amountWithdrawn;
instance #3 Link: https://github.com/code-423n4/2022-09-vtvl/blob/main/contracts/VTVLVesting.sol#L429
contracts/VTVLVesting.sol 429: uint112 amountRemaining = finalVestAmt - _claim.amountWithdrawn;
if (<x> == true) ==> if (<x>) if (<x> == false) => if (!<x>)
Total instances of this issue: 1
instance #1 Link: https://github.com/code-423n4/2022-09-vtvl/blob/main/contracts/VTVLVesting.sol#L111
contracts/VTVLVesting.sol 111: require(_claim.isActive == true, "NO_ACTIVE_CLAIM");
payable
to functions which are only meant to be called by specific actors like onlyOwner
will save gas costMarking functions payable removes additional checks for whether a payment was provided, hence reducing gas cost
Total instances of this issue: 7
instance #1 Link: https://github.com/code-423n4/2022-09-vtvl/blob/main/contracts/token/VariableSupplyERC20Token.sol#L36
contracts/token/VariableSupplyERC20Token.sol 36: function mint(address account, uint256 amount) public onlyAdmin {
instance #2 Link: https://github.com/code-423n4/2022-09-vtvl/blob/main/contracts/AccessProtected.sol#L39
contracts/AccessProtected.sol 39: function setAdmin(address admin, bool isEnabled) public onlyAdmin {
instance #3 Permalink: https://github.com/code-423n4/2022-09-vtvl/blob/main/contracts/VTVLVesting.sol#L317-L325
contracts/VTVLVesting.sol 317: function createClaim( 318: address _recipient, 319: uint40 _startTimestamp, 320: uint40 _endTimestamp, 321: uint40 _cliffReleaseTimestamp, 322: uint40 _releaseIntervalSecs, 323: uint112 _linearVestAmount, 324: uint112 _cliffAmount 325: ) external onlyAdmin {
instance #4 Permalink: https://github.com/code-423n4/2022-09-vtvl/blob/main/contracts/VTVLVesting.sol#L333-L341
contracts/VTVLVesting.sol 333: function createClaimsBatch( 334: address[] memory _recipients, 335: uint40[] memory _startTimestamps, 336: uint40[] memory _endTimestamps, 337: uint40[] memory _cliffReleaseTimestamps, 338: uint40[] memory _releaseIntervalsSecs, 339: uint112[] memory _linearVestAmounts, 340: uint112[] memory _cliffAmounts) 341: external onlyAdmin {
instance #5 Link: https://github.com/code-423n4/2022-09-vtvl/blob/main/contracts/VTVLVesting.sol#L398
contracts/VTVLVesting.sol 398: function withdrawAdmin(uint112 _amountRequested) public onlyAdmin {
instance #6 Link: https://github.com/code-423n4/2022-09-vtvl/blob/main/contracts/VTVLVesting.sol#L418
contracts/VTVLVesting.sol 418: function revokeClaim(address _recipient) external onlyAdmin hasActiveClaim(_recipient) {
instance #7 Link: https://github.com/code-423n4/2022-09-vtvl/blob/main/contracts/VTVLVesting.sol#L446
contracts/VTVLVesting.sol 446: function withdrawOtherToken(IERC20 _otherTokenAddress) external onlyAdmin {
Since the default value is already zero, overwriting is not required.
Saves 8 gas
per instance.
Total instances of this issue: 3
instance #1 Link: https://github.com/code-423n4/2022-09-vtvl/blob/main/contracts/VTVLVesting.sol#L27
contracts/VTVLVesting.sol 27: uint112 public numTokensReservedForVesting = 0;
instance #2 Link: https://github.com/code-423n4/2022-09-vtvl/blob/main/contracts/VTVLVesting.sol#L148
contracts/VTVLVesting.sol 148: uint112 vestAmt = 0;
instance #3 Link: https://github.com/code-423n4/2022-09-vtvl/blob/main/contracts/VTVLVesting.sol#L353
contracts/VTVLVesting.sol 353: for (uint256 i = 0; i < length; i++) {
require()
containing multiple checks joined with && should be broken into multiple require statementsTotal instances of this issue: 2
instance #1 Permalink: https://github.com/code-423n4/2022-09-vtvl/blob/main/contracts/VTVLVesting.sol#L270-L278
contracts/VTVLVesting.sol 270: require( 271: ( 272: _cliffReleaseTimestamp > 0 && 273: _cliffAmount > 0 && 274: _cliffReleaseTimestamp <= _startTimestamp 275: ) || ( 276: _cliffReleaseTimestamp == 0 && 277: _cliffAmount == 0 278: ), "INVALID_CLIFF");
instance #2 Permalink: https://github.com/code-423n4/2022-09-vtvl/blob/main/contracts/VTVLVesting.sol#L344-L351
contracts/VTVLVesting.sol 344: require(_startTimestamps.length == length && 345: _endTimestamps.length == length && 346: _cliffReleaseTimestamps.length == length && 347: _releaseIntervalsSecs.length == length && 348: _linearVestAmounts.length == length && 349: _cliffAmounts.length == length, 350: "ARRAY_LENGTH_MISMATCH" 351: );
Gas usage becomes higher with uint/int smaller than 256 bits because EVM operates on 32 bytes and uses additional operations to reduce the size from 32 bytes to the target size.
Total instances of this issue: 14
instance #1 Link: https://github.com/code-423n4/2022-09-vtvl/blob/main/contracts/VTVLVesting.sol#L27
contracts/VTVLVesting.sol 27: uint112 public numTokensReservedForVesting = 0;
instance #2 Link: https://github.com/code-423n4/2022-09-vtvl/blob/main/contracts/VTVLVesting.sol#L147
contracts/VTVLVesting.sol 147: function _baseVestedAmount(Claim memory _claim, uint40 _referenceTs) internal pure returns (uint112) {
instance #3 Link: https://github.com/code-423n4/2022-09-vtvl/blob/main/contracts/VTVLVesting.sol#L148
contracts/VTVLVesting.sol 148: uint112 vestAmt = 0;
instance #4 Link: https://github.com/code-423n4/2022-09-vtvl/blob/main/contracts/VTVLVesting.sol#L169
contracts/VTVLVesting.sol 169: uint40 truncatedCurrentVestingDurationSecs = (currentVestingDurationSecs / _claim.releaseIntervalSecs) * _claim.releaseIntervalSecs;
instance #5 Link: https://github.com/code-423n4/2022-09-vtvl/blob/main/contracts/VTVLVesting.sol#L176
contracts/VTVLVesting.sol 176: uint112 linearVestAmount = _claim.linearVestAmount * truncatedCurrentVestingDurationSecs / finalVestingDurationSecs;
instance #6 Link: https://github.com/code-423n4/2022-09-vtvl/blob/main/contracts/VTVLVesting.sol#L196
contracts/VTVLVesting.sol 196: function vestedAmount(address _recipient, uint40 _referenceTs) public view returns (uint112) {
instance #7 Permalink: https://github.com/code-423n4/2022-09-vtvl/blob/main/contracts/VTVLVesting.sol#L245-L253
contracts/VTVLVesting.sol 245: function _createClaimUnchecked( 246: address _recipient, 247: uint40 _startTimestamp, 248: uint40 _endTimestamp, 249: uint40 _cliffReleaseTimestamp, 250: uint40 _releaseIntervalSecs, 251: uint112 _linearVestAmount, 252: uint112 _cliffAmount 253: ) private hasNoClaim(_recipient) {
instance #8 Link: https://github.com/code-423n4/2022-09-vtvl/blob/main/contracts/VTVLVesting.sol#L292
contracts/VTVLVesting.sol 292: uint112 allocatedAmount = _cliffAmount + _linearVestAmount;
instance #9 Permalink: https://github.com/code-423n4/2022-09-vtvl/blob/main/contracts/VTVLVesting.sol#L317-L325
contracts/VTVLVesting.sol 317: function createClaim( 318: address _recipient, 319: uint40 _startTimestamp, 320: uint40 _endTimestamp, 321: uint40 _cliffReleaseTimestamp, 322: uint40 _releaseIntervalSecs, 323: uint112 _linearVestAmount, 324: uint112 _cliffAmount 325: ) external onlyAdmin {
instance #10 Link: https://github.com/code-423n4/2022-09-vtvl/blob/main/contracts/VTVLVesting.sol#L371
contracts/VTVLVesting.sol 371: uint112 allowance = vestedAmount(_msgSender(), uint40(block.timestamp));
instance #11 Link: https://github.com/code-423n4/2022-09-vtvl/blob/main/contracts/VTVLVesting.sol#L377
contracts/VTVLVesting.sol 377: uint112 amountRemaining = allowance - usrClaim.amountWithdrawn;
instance #12 Link: https://github.com/code-423n4/2022-09-vtvl/blob/main/contracts/VTVLVesting.sol#L398
contracts/VTVLVesting.sol 398: function withdrawAdmin(uint112 _amountRequested) public onlyAdmin {
instance #13 Link: https://github.com/code-423n4/2022-09-vtvl/blob/main/contracts/VTVLVesting.sol#L422
contracts/VTVLVesting.sol 422: uint112 finalVestAmt = finalVestedAmount(_recipient);
instance #14 Link: https://github.com/code-423n4/2022-09-vtvl/blob/main/contracts/VTVLVesting.sol#L429
contracts/VTVLVesting.sol 429: uint112 amountRemaining = finalVestAmt - _claim.amountWithdrawn;
Custom errors are available from solidity version 0.8.4.
Total instances of this issue: 21
instance #1 Link: https://github.com/code-423n4/2022-09-vtvl/blob/main/contracts/token/FullPremintERC20Token.sol#L11
contracts/token/FullPremintERC20Token.sol 11: require(supply_ > 0, "NO_ZERO_MINT");
instance #2 Link: https://github.com/code-423n4/2022-09-vtvl/blob/main/contracts/token/VariableSupplyERC20Token.sol#L27
contracts/token/VariableSupplyERC20Token.sol 27: require(initialSupply_ > 0 || maxSupply_ > 0, "INVALID_AMOUNT");
instance #3 Link: https://github.com/code-423n4/2022-09-vtvl/blob/main/contracts/token/VariableSupplyERC20Token.sol#L37
contracts/token/VariableSupplyERC20Token.sol 37: require(account != address(0), "INVALID_ADDRESS");
instance #4 Link: https://github.com/code-423n4/2022-09-vtvl/blob/main/contracts/token/VariableSupplyERC20Token.sol#L41
contracts/token/VariableSupplyERC20Token.sol 41: require(amount <= mintableSupply, "INVALID_AMOUNT");
instance #5 Link: https://github.com/code-423n4/2022-09-vtvl/blob/main/contracts/AccessProtected.sol#L25
contracts/AccessProtected.sol 25: require(_admins[_msgSender()], "ADMIN_ACCESS_REQUIRED");
instance #6 Link: https://github.com/code-423n4/2022-09-vtvl/blob/main/contracts/AccessProtected.sol#L40
contracts/AccessProtected.sol 40: require(admin != address(0), "INVALID_ADDRESS");
instance #7 Link: https://github.com/code-423n4/2022-09-vtvl/blob/main/contracts/VTVLVesting.sol#L82
contracts/VTVLVesting.sol 82: require(address(_tokenAddress) != address(0), "INVALID_ADDRESS");
instance #8 Link: https://github.com/code-423n4/2022-09-vtvl/blob/main/contracts/VTVLVesting.sol#L107
contracts/VTVLVesting.sol 107: require(_claim.startTimestamp > 0, "NO_ACTIVE_CLAIM");
instance #9 Link: https://github.com/code-423n4/2022-09-vtvl/blob/main/contracts/VTVLVesting.sol#L111
contracts/VTVLVesting.sol 111: require(_claim.isActive == true, "NO_ACTIVE_CLAIM");
instance #10 Link: https://github.com/code-423n4/2022-09-vtvl/blob/main/contracts/VTVLVesting.sol#L129
contracts/VTVLVesting.sol 129: require(_claim.startTimestamp == 0, "CLAIM_ALREADY_EXISTS");
instance #11 Link: https://github.com/code-423n4/2022-09-vtvl/blob/main/contracts/VTVLVesting.sol#L255
contracts/VTVLVesting.sol 255: require(_recipient != address(0), "INVALID_ADDRESS");
instance #12 Link: https://github.com/code-423n4/2022-09-vtvl/blob/main/contracts/VTVLVesting.sol#L257
contracts/VTVLVesting.sol 257: require(_startTimestamp > 0, "INVALID_START_TIMESTAMP");
instance #13 Link: https://github.com/code-423n4/2022-09-vtvl/blob/main/contracts/VTVLVesting.sol#L263
contracts/VTVLVesting.sol 263: require(_releaseIntervalSecs > 0, "INVALID_RELEASE_INTERVAL");
instance #14 Link: https://github.com/code-423n4/2022-09-vtvl/blob/main/contracts/VTVLVesting.sol#L264
contracts/VTVLVesting.sol 264: require((_endTimestamp - _startTimestamp) % _releaseIntervalSecs == 0, "INVALID_INTERVAL_LENGTH");
instance #15 Permalink: https://github.com/code-423n4/2022-09-vtvl/blob/main/contracts/VTVLVesting.sol#L270-L278
contracts/VTVLVesting.sol 270: require( 271: ( 272: _cliffReleaseTimestamp > 0 && 273: _cliffAmount > 0 && 274: _cliffReleaseTimestamp <= _startTimestamp 275: ) || ( 276: _cliffReleaseTimestamp == 0 && 277: _cliffAmount == 0 278: ), "INVALID_CLIFF");
instance #16 Link: https://github.com/code-423n4/2022-09-vtvl/blob/main/contracts/VTVLVesting.sol#L295
contracts/VTVLVesting.sol 295: require(tokenAddress.balanceOf(address(this)) >= numTokensReservedForVesting + allocatedAmount, "INSUFFICIENT_BALANCE");
instance #17 Permalink: https://github.com/code-423n4/2022-09-vtvl/blob/main/contracts/VTVLVesting.sol#L344-L351
contracts/VTVLVesting.sol 344: require(_startTimestamps.length == length && 345: _endTimestamps.length == length && 346: _cliffReleaseTimestamps.length == length && 347: _releaseIntervalsSecs.length == length && 348: _linearVestAmounts.length == length && 349: _cliffAmounts.length == length, 350: "ARRAY_LENGTH_MISMATCH" 351: );
instance #18 Link: https://github.com/code-423n4/2022-09-vtvl/blob/main/contracts/VTVLVesting.sol#L374
contracts/VTVLVesting.sol 374: require(allowance > usrClaim.amountWithdrawn, "NOTHING_TO_WITHDRAW");
instance #19 Link: https://github.com/code-423n4/2022-09-vtvl/blob/main/contracts/VTVLVesting.sol#L402
contracts/VTVLVesting.sol 402: require(amountRemaining >= _amountRequested, "INSUFFICIENT_BALANCE");
instance #20 Link: https://github.com/code-423n4/2022-09-vtvl/blob/main/contracts/VTVLVesting.sol#L426
contracts/VTVLVesting.sol 426: require( _claim.amountWithdrawn < finalVestAmt, "NO_UNVESTED_AMOUNT");
instance #21 Link: https://github.com/code-423n4/2022-09-vtvl/blob/main/contracts/VTVLVesting.sol#L449
contracts/VTVLVesting.sol 449: require(bal > 0, "INSUFFICIENT_BALANCE");