VTVL contest - tgolding55's results

Building no-code token management tools to empower web3 founders and investors, starting with token vesting.

General Information

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

VTVL

Findings Distribution

Researcher Performance

Rank: 189/198

Findings: 1

Award: $9.09

🌟 Selected for report: 0

🚀 Solo Findings: 0

Awards

9.086 USDC - $9.09

Labels

bug
G (Gas Optimization)

External Links

QA Report

Gas Optimizations

1. Custom Errors

Custom errors from Solidity 0.8.4 are cheaper than revert strings.

https://blog.soliditylang.org/2021/04/21/custom-errors/

Examples in contracts:

FullPremintERC20Token.sol

Line 11

require(supply_ > 0, "NO_ZERO_MINT");

VariableSupplyERC20Token

Line 27

require(initialSupply_ > 0 || maxSupply_ > 0, "INVALID_AMOUNT");

Line 37

require(account != address(0), "INVALID_ADDRESS");

Line 41

require(amount <= mintableSupply, "INVALID_AMOUNT");

AccessProtected.sol

Line 25

require(_admins[_msgSender()], "ADMIN_ACCESS_REQUIRED");

Line 40

require(admin != address(0), "INVALID_ADDRESS");

VTVLVesting.sol

Line 82

require(address(_tokenAddress) != address(0), "INVALID_ADDRESS");

Line 107

require(_claim.startTimestamp > 0, "NO_ACTIVE_CLAIM");

Line 111

require(_claim.isActive == true, "NO_ACTIVE_CLAIM");

Line 129

require(_claim.startTimestamp == 0, "CLAIM_ALREADY_EXISTS");

Line 255-257

require(_recipient != address(0), "INVALID_ADDRESS"); require(_linearVestAmount + _cliffAmount > 0, "INVALID_VESTED_AMOUNT"); require(_startTimestamp > 0, "INVALID_START_TIMESTAMP");

Line 262-264

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");

Line 270-278

require( ( _cliffReleaseTimestamp > 0 && _cliffAmount > 0 && _cliffReleaseTimestamp <= _startTimestamp ) || ( _cliffReleaseTimestamp == 0 && _cliffAmount == 0 ), "INVALID_CLIFF");

Line 295

require(tokenAddress.balanceOf(address(this)) >= numTokensReservedForVesting + allocatedAmount, "INSUFFICIENT_BALANCE");

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" );

Line 374

require(allowance > usrClaim.amountWithdrawn, "NOTHING_TO_WITHDRAW");

Line 402

require(amountRemaining >= _amountRequested, "INSUFFICIENT_BALANCE");

Line 426

require( _claim.amountWithdrawn < finalVestAmt, "NO_UNVESTED_AMOUNT");

Line 447

require(_otherTokenAddress != tokenAddress, "INVALID_TOKEN"); // tokenAddress address is already sure to be nonzero due to constructor

Line 449

require(bal > 0, "INSUFFICIENT_BALANCE");

2. != 0 is more efficient then > 0 for uints

!= 0 costs less gas compared to > 0 for unsigned integer.

Examples in contracts:

FullPremintERC20Token.sol

Line 11

require(supply_ > 0, "NO_ZERO_MINT");

VariableSupplyERC20Token

Line 27

require(initialSupply_ > 0 || maxSupply_ > 0, "INVALID_AMOUNT");

Line 31

if(initialSupply_ > 0) {

Line 40

if(mintableSupply > 0) {

VTVLVesting.sol

Line 107

require(_claim.startTimestamp > 0, "NO_ACTIVE_CLAIM");

Line 256-257

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");

Line 263

require(_releaseIntervalSecs > 0, "INVALID_RELEASE_INTERVAL");

Line 270-278

require( ( _cliffReleaseTimestamp > 0 && _cliffAmount > 0 && _cliffReleaseTimestamp <= _startTimestamp ) || ( _cliffReleaseTimestamp == 0 && _cliffAmount == 0 ), "INVALID_CLIFF");

Line 449

require(bal > 0, "INSUFFICIENT_BALANCE");

3. Unnecessary Default Value Initialization

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:

VTVLVesting.sol

Line 27

uint112 public numTokensReservedForVesting = 0;

Line 148

uint112 vestAmt = 0;

Line 353

for (uint256 i = 0; i < length; i++) {

4. ++i is more efficient then i++

for(...; i++)

to

for(...; ++i)

Examples in contracts:

VTVLVesting.sol

Line 353

for (uint256 i = 0; i < length; i++) {

5. Splitting require statements

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" );

6. Increments can be unchecked

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:

Line 353

for (uint256 i = 0; i < length; i++) {

#0 - 0xean

2022-09-25T22:44:15Z

Warden submitted as QA report, moved to Gas

AuditHub

A portfolio for auditors, a security profile for protocols, a hub for web3 security.

Built bymalatrax © 2024

Auditors

Browse

Contests

Browse

Get in touch

ContactTwitter