BriVault

First Flight #52
Beginner FriendlySolidity
100 EXP
View results
Submission Details
Impact: medium
Likelihood: medium
Invalid

MEDIUM-04: Fixed Array Size Wastes Gas

Root + Impact

The teams array is hardcoded to 48 elements, forcing all 48 storage slots to be set even for tournaments with fewer teams, wasting hundreds of thousands of gas.

Description

Normal behavior for flexible contracts expects using dynamic arrays that accommodate different use cases. Not all tournaments have exactly 48 teams.

The current implementation uses a fixed-size array string[48], which means every tournament must pay to initialize all 48 slots even if only using 16, 32, or other counts.

// @> Forces setting all 48 slots even if tournament has fewer teams
string[48] public teams;
function setCountry(string[48] memory countries) public onlyOwner {
// @> Loops through all 48 elements
for (uint256 i = 0; i < countries.length; ++i) {
teams[i] = countries[i];
}
emit CountriesSet(countries);
}

Risk

Likelihood:

  • Many tournaments have fewer than 48 teams

  • Each unused slot still costs gas to set (even if empty string)

  • Every tournament deployment incurs this cost

Impact:

  • Tournament with 16 teams wastes gas setting 32 empty slots

  • Each SSTORE operation costs ~20,000 gas for first write

  • 32 unused slots = ~640,000 wasted gas

  • Makes smaller tournaments unnecessarily expensive

  • Reduces flexibility for different competition formats

  • Hardcoded assumption limits reusability

Proof of Concept

// Current implementation - Fixed array
string[48] public teams;
// Scenario: Tournament with 16 teams
string[48] memory countries;
countries[0] = "Team1";
// ... set teams 1-15 ...
countries[16] = ""; // Empty
// ... countries[17-47] all empty ...
vault.setCountry(countries);
// Gas breakdown:
// - 16 team name writes: 16 * 20,000 = 320,000 gas
// - 32 empty string writes: 32 * 20,000 = 640,000 gas (WASTED)
// Total: 960,000 gas (67% wasted!)
// ----
// Optimized - Dynamic array
string[] public teams;
// Same scenario: Tournament with 16 teams
string[] memory countries = new string[](16);
countries[0] = "Team1";
// ... set teams 1-15 ...
vault.setCountry(countries);
// Gas breakdown:
// - 16 team name writes: 16 * 20,000 = 320,000 gas
// - Array length set: 5,000 gas
// Total: 325,000 gas
// SAVED: 635,000 gas (66% savings!)

Recommended Mitigation

-string[48] public teams;
+string[] public teams;
-function setCountry(string[48] memory countries) public onlyOwner {
+function setCountry(string[] calldata countries) external onlyOwner {
+ require(countries.length > 0, "Must have at least one team");
+ require(countries.length <= 48, "Too many teams");
+
+ // Clear existing teams
+ delete teams;
+
+ // Set only the needed teams
for (uint256 i = 0; i < countries.length; ++i) {
- teams[i] = countries[i];
+ require(bytes(countries[i]).length > 0, "Empty team name");
+ teams.push(countries[i]);
}
- emit CountriesSet(countries);
+
+ emit CountriesSet(block.timestamp, countries.length);
}
// Update validation in other functions
function joinEvent(uint256 countryId) public {
if (stakedAsset[msg.sender] == 0) {
revert noDeposit();
}
- if (countryId >= teams.length) {
+ if (countryId >= teams.length || bytes(teams[countryId]).length == 0) {
revert invalidCountry();
}
// ... rest of function ...
}

Additional benefits:

  • Supports tournaments with 2, 4, 8, 16, 32, or any number of teams

  • More flexible for different competition formats

  • Validates all team names are non-empty

  • Can clear and reset teams if needed

Estimated Gas Savings:

  • 16-team tournament: ~640,000 gas saved

  • 32-team tournament: ~320,000 gas saved

  • Variable based on actual team count vs 48

Updates

Appeal created

bube Lead Judge 19 days ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity
Assigned finding tags:

Gas optimizations

Gas optimizations are invalid according to the CodeHawks documentation.

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.

Give us feedback!