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: 69/198
Findings: 2
Award: $31.11
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: AkshaySrivastav
Also found by: 0v3rf10w, 0x040, 0x1f8b, 0x4non, 0x5rings, 0x85102, 0xA5DF, 0xDecorativePineapple, 0xNazgul, 0xSky, 0xSmartContract, 0xbepresent, 0xf15ers, 0xmatt, 2997ms, Aeros, Aymen0909, B2, Bahurum, Bnke0x0, CertoraInc, Chom, ChristianKuri, CodingNameKiki, Deivitto, Diana, Diraco, Dravee, ElKu, Funen, IllIllI, JC, JLevick, JohnSmith, JohnnyTime, KIntern_NA, Lambda, Margaret, MasterCookie, OptimismSec, RaymondFam, Respx, ReyAdmirado, RockingMiles, Rohan16, Rolezn, Ruhum, RustyRabbit, Sm4rty, SooYa, StevenL, TomJ, Tomo, V_B, Waze, Yiko, __141345__, a12jmx, ajtra, ak1, async, ayeslick, aysha, berndartmueller, bin2chen, bobirichman, brgltd, bulej93, c3phas, carrotsmuggler, cccz, ch13fd357r0y3r, chatch, cryptostellar5, cryptphi, csanuragjain, d3e4, datapunk, delfin454000, dic0de, djxploit, durianSausage, eighty, erictee, exd0tpy, fatherOfBlocks, gogo, got_targ, hansfriese, ignacio, ikbkln, indijanc, innertia, joestakey, karanctf, ladboy233, leosathya, lukris02, martin, medikko, millersplanet, nalus, natzuu, neko_nyaa, neumo, obront, oyc_109, pcarranzav, peanuts, pedr02b2, pedroais, peiw, peritoflores, prasantgupta52, rajatbeladiya, rbserver, reassor, ret2basic, rokinot, romand, rotcivegaf, rvierdiiev, sach1r0, seyni, sikorico, slowmoses, sorrynotsorry, supernova, tibthecat, tnevler, ubermensch, yongskiws, zzykxx, zzzitron
18.8655 USDC - $18.87
public
functions not called by the contract should be declared external
insteadThere are 2 instances of this issue:
File: contracts/AccessProtected.sol 39: function setAdmin(address admin, bool isEnabled) public onlyAdmin {
https://github.com/code-423n4/2022-09-vtvl/tree/main/contracts/AccessProtected.sol
File: contracts/VTVLVesting.sol 398: function withdrawAdmin(uint112 _amountRequested) public onlyAdmin {
https://github.com/code-423n4/2022-09-vtvl/tree/main/contracts/VTVLVesting.sol
There are 1 instances of this issue:
File: contracts/token/VariableSupplyERC20Token.sol 2: pragma solidity ^0.8.14;
https://github.com/code-423n4/2022-09-vtvl/tree/main/contracts/token/VariableSupplyERC20Token.sol
There are 4 instances of this issue:
File: contracts/AccessProtected.sol /// @audit
https://github.com/code-423n4/2022-09-vtvl/tree/main/contracts/AccessProtected.sol
File: contracts/token/FullPremintERC20Token.sol /// @audit
https://github.com/code-423n4/2022-09-vtvl/tree/main/contracts/token/FullPremintERC20Token.sol
File: contracts/token/VariableSupplyERC20Token.sol /// @audit
https://github.com/code-423n4/2022-09-vtvl/tree/main/contracts/token/VariableSupplyERC20Token.sol
File: contracts/VTVLVesting.sol /// @audit
https://github.com/code-423n4/2022-09-vtvl/tree/main/contracts/VTVLVesting.sol
There are 1 instances of this issue:
File: contracts/token/FullPremintERC20Token.sol /// @audit
https://github.com/code-423n4/2022-09-vtvl/tree/main/contracts/token/FullPremintERC20Token.sol
indexed
fieldsThere are 1 instances of this issue:
File: contracts/VTVLVesting.sol event ClaimRevoked(address indexed _recipient, uint112 _numTokensWithheld, uint256 revocationTimestamp, Claim _claim)
https://github.com/code-423n4/2022-09-vtvl/tree/main/contracts/VTVLVesting.sol
There are 2 instances of this issue:
File: contracts/AccessProtected.sol 5: import "@openzeppelin/contracts/access/Ownable.sol";
https://github.com/code-423n4/2022-09-vtvl/tree/main/contracts/AccessProtected.sol
File: contracts/VTVLVesting.sol 6: import "@openzeppelin/contracts/access/Ownable.sol";
https://github.com/code-423n4/2022-09-vtvl/tree/main/contracts/VTVLVesting.sol
🌟 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
12.236 USDC - $12.24
++i
will cost less gas than i++
. The same change can be applied to i--
as well.This change would save up to 6 gas per instance/loop.
There are 1 instances of this issue:
File: contracts/VTVLVesting.sol 353: for (uint256 i = 0; i < length; i++) {
https://github.com/code-423n4/2022-09-vtvl/tree/main/contracts/VTVLVesting.sol
!= 0
on uints
costs less gas than > 0
.This change saves 3 gas per instance/loop
There are 10 instances of this issue:
File: contracts/token/FullPremintERC20Token.sol 11: require(supply_ > 0, "NO_ZERO_MINT");
https://github.com/code-423n4/2022-09-vtvl/tree/main/contracts/token/FullPremintERC20Token.sol
File: contracts/token/VariableSupplyERC20Token.sol 27: require(initialSupply_ > 0 || maxSupply_ > 0, "INVALID_AMOUNT"); 31: if(initialSupply_ > 0) {
https://github.com/code-423n4/2022-09-vtvl/tree/main/contracts/token/VariableSupplyERC20Token.sol
File: contracts/VTVLVesting.sol 107: require(_claim.startTimestamp > 0, "NO_ACTIVE_CLAIM"); 256: require(_linearVestAmount + _cliffAmount > 0, "INVALID_VESTED_AMOUNT"); 257: require(_startTimestamp > 0, "INVALID_START_TIMESTAMP"); 263: require(_releaseIntervalSecs > 0, "INVALID_RELEASE_INTERVAL"); 272: _cliffReleaseTimestamp > 0 && 273: _cliffAmount > 0 && 449: require(bal > 0, "INSUFFICIENT_BALANCE");
https://github.com/code-423n4/2022-09-vtvl/tree/main/contracts/VTVLVesting.sol
constant
/non-immutable
variables to zero than to let the default of zero be appliedNot overwriting the default for stack variables saves 8 gas. Storage and memory variables have larger savings
There are 3 instances of this issue:
File: contracts/VTVLVesting.sol 27: uint112 public numTokensReservedForVesting = 0; 148: uint112 vestAmt = 0; 353: for (uint256 i = 0; i < length; i++) {
https://github.com/code-423n4/2022-09-vtvl/tree/main/contracts/VTVLVesting.sol
payable
Marking a function as payable
reduces gas cost since the compiler does not have to check whether a payment was provided or not. This change will save around 21 gas per function call.
There are 5 instances of this issue:
File: contracts/AccessProtected.sol 39: function setAdmin(address admin, bool isEnabled) public onlyAdmin {
https://github.com/code-423n4/2022-09-vtvl/tree/main/contracts/AccessProtected.sol
File: contracts/token/VariableSupplyERC20Token.sol 36: function mint(address account, uint256 amount) public onlyAdmin {
https://github.com/code-423n4/2022-09-vtvl/tree/main/contracts/token/VariableSupplyERC20Token.sol
File: contracts/VTVLVesting.sol 398: function withdrawAdmin(uint112 _amountRequested) public onlyAdmin { 418: function revokeClaim(address _recipient) external onlyAdmin hasActiveClaim(_recipient) { 446: function withdrawOtherToken(IERC20 _otherTokenAddress) external onlyAdmin {
https://github.com/code-423n4/2022-09-vtvl/tree/main/contracts/VTVLVesting.sol
++i
/i++
should be unchecked{++I}
/unchecked{I++}
in for
-loopsWhen an increment or any arithmetic operation is not possible to overflow it should be placed in unchecked{}
block. \This is because of the default compiler overflow and underflow safety checks since Solidity version 0.8.0. \In for-loops it saves around 30-40 gas per loop
There are 1 instances of this issue:
File: contracts/VTVLVesting.sol 353: for (uint256 i = 0; i < length; i++) {
https://github.com/code-423n4/2022-09-vtvl/tree/main/contracts/VTVLVesting.sol
<x> += <y>
costs more gas than <x> = <x> + <y>
for state variablesThere are 4 instances of this issue:
File: contracts/token/VariableSupplyERC20Token.sol 43: mintableSupply -= amount;
https://github.com/code-423n4/2022-09-vtvl/tree/main/contracts/token/VariableSupplyERC20Token.sol
File: contracts/VTVLVesting.sol 301: numTokensReservedForVesting += allocatedAmount; 383: numTokensReservedForVesting -= amountRemaining; 433: numTokensReservedForVesting -= amountRemaining;
https://github.com/code-423n4/2022-09-vtvl/tree/main/contracts/VTVLVesting.sol
Use if(x)
/if(!x)
instead of if(x == true)
/if(x == false)
.
There are 1 instances of this issue:
File: contracts/VTVLVesting.sol 111: require(_claim.isActive == true, "NO_ACTIVE_CLAIM");
https://github.com/code-423n4/2022-09-vtvl/tree/main/contracts/VTVLVesting.sol
require()
statements that use &&
saves gasInstead of using &&
on single require
check using two require
checks can save gas
There are 2 instances of this issue:
File: 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"); 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: );
https://github.com/code-423n4/2022-09-vtvl/tree/main/contracts/VTVLVesting.sol
calldata
instead of memory
for function parametersIf a reference type function parameter is read-only, it is cheaper in gas to use calldata instead of memory. Calldata is a non-modifiable, non-persistent area where function arguments are stored, and behaves mostly like memory. Try to use calldata as a data location because it will avoid copies and also makes sure that the data cannot be modified.
There are 8 instances of this issue:
File: contracts/VTVLVesting.sol 147: function _baseVestedAmount(Claim memory _claim, uint40 _referenceTs) internal pure returns (uint112) { 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)
https://github.com/code-423n4/2022-09-vtvl/tree/main/contracts/VTVLVesting.sol
x <= y
with x < y + 1
, and x >= y
with x > y - 1
In the EVM, there is no opcode for >=
or <=
. When using greater than or equal, two operations are performed: >
and =
. Using strict comparison operators hence saves gas
There are 5 instances of this issue:
File: contracts/token/VariableSupplyERC20Token.sol 41: require(amount <= mintableSupply, "INVALID_AMOUNT");
https://github.com/code-423n4/2022-09-vtvl/tree/main/contracts/token/VariableSupplyERC20Token.sol
File: contracts/VTVLVesting.sol 160: if(_referenceTs >= _claim.cliffReleaseTimestamp) { 274: _cliffReleaseTimestamp <= _startTimestamp 295: require(tokenAddress.balanceOf(address(this)) >= numTokensReservedForVesting + allocatedAmount, "INSUFFICIENT_BALANCE"); 402: require(amountRemaining >= _amountRequested, "INSUFFICIENT_BALANCE");
https://github.com/code-423n4/2022-09-vtvl/tree/main/contracts/VTVLVesting.sol
revert()
/require()
strings to save gasCustom 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
There are 24 instances of this issue:
File: contracts/AccessProtected.sol 25: require(_admins[_msgSender()], "ADMIN_ACCESS_REQUIRED"); 40: require(admin != address(0), "INVALID_ADDRESS");
https://github.com/code-423n4/2022-09-vtvl/tree/main/contracts/AccessProtected.sol
File: contracts/token/FullPremintERC20Token.sol 11: require(supply_ > 0, "NO_ZERO_MINT");
https://github.com/code-423n4/2022-09-vtvl/tree/main/contracts/token/FullPremintERC20Token.sol
File: contracts/token/VariableSupplyERC20Token.sol 27: require(initialSupply_ > 0 || maxSupply_ > 0, "INVALID_AMOUNT"); 37: require(account != address(0), "INVALID_ADDRESS"); 41: require(amount <= mintableSupply, "INVALID_AMOUNT");
https://github.com/code-423n4/2022-09-vtvl/tree/main/contracts/token/VariableSupplyERC20Token.sol
File: contracts/VTVLVesting.sol 82: require(address(_tokenAddress) != address(0), "INVALID_ADDRESS"); 107: require(_claim.startTimestamp > 0, "NO_ACTIVE_CLAIM"); 111: require(_claim.isActive == true, "NO_ACTIVE_CLAIM"); 129: require(_claim.startTimestamp == 0, "CLAIM_ALREADY_EXISTS"); 255: require(_recipient != address(0), "INVALID_ADDRESS"); 256: require(_linearVestAmount + _cliffAmount > 0, "INVALID_VESTED_AMOUNT"); 257: require(_startTimestamp > 0, "INVALID_START_TIMESTAMP"); 262: require(_startTimestamp < _endTimestamp, "INVALID_END_TIMESTAMP"); 263: require(_releaseIntervalSecs > 0, "INVALID_RELEASE_INTERVAL"); 264: require((_endTimestamp - _startTimestamp) % _releaseIntervalSecs == 0, "INVALID_INTERVAL_LENGTH"); 270: require( 271: ( 272: _cliffReleaseTimestamp > 0 && 273: _cliffAmount > 0 && 274: _cliffReleaseTimestamp <= _startTimestamp 275: ) || ( 276: _cliffReleaseTimestamp == 0 && 277: _cliffAmount == 0 278: ), "INVALID_CLIFF"); 295: require(tokenAddress.balanceOf(address(this)) >= numTokensReservedForVesting + allocatedAmount, "INSUFFICIENT_BALANCE"); 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: ); 374: require(allowance > usrClaim.amountWithdrawn, "NOTHING_TO_WITHDRAW"); 402: require(amountRemaining >= _amountRequested, "INSUFFICIENT_BALANCE"); 426: require( _claim.amountWithdrawn < finalVestAmt, "NO_UNVESTED_AMOUNT"); 447: require(_otherTokenAddress != tokenAddress, "INVALID_TOKEN"); 449: require(bal > 0, "INSUFFICIENT_BALANCE");
https://github.com/code-423n4/2022-09-vtvl/tree/main/contracts/VTVLVesting.sol