Beginner FriendlyFoundryNFT
100 EXP
View results
Submission Details
Severity: low
Invalid

Naming conventions and gas optimizations

Summary

The lack of naming conventions like the one used by Chainlink, it makes difficult for developers differentiate state variables and memory variables and make gas optimizations.

Impact

Low - Doesn't impact in the correct use of the protocol

Recommendations

When using a state variables more than 2 times, like in a for loop, it may be wise to load the variable into memory first and use that variable to minize the gas consumption.

I recommend this naming convention for state and memory variables:

If it's a state variable the name will be the same as we see in the Solidity Documentation, camelcase but it will be preceded by 's_variableName', and memory variables simple camelcase 'variableName'.

With this change in can be easier for developers in where to do the optimization, and by adopting this pattern, (prioritize the use of memory variables instead).

PoC

Let's have this example, let's suppose we want to add 200 players into the raffle, let's rewrite the enterRaffle() function to use memory variables, and let's see the gas consumption of each test.

Paste this function into PuppyRaffle
function enterRaffleOptimized(address[] calldata newPlayers) public payable {
require(msg.value == entranceFee * newPlayers.length, "PuppyRaffle: Must send enough to enter raffle");
for (uint256 i = 0; i < newPlayers.length; i++) {
require(!newPlayers[i].isContract(), "Contracts are not permited in the raffle");
players.push(newPlayers[i]);
}
address[] memory tmpPlayers = players;
// Check for duplicates
for (uint256 i = 0; i < tmpPlayers.length - 1; i++) {
for (uint256 j = i + 1; j < tmpPlayers.length; j++) {
require(tmpPlayers[i] != tmpPlayers[j], "PuppyRaffle: Duplicate player");
}
}
emit RaffleEnter(newPlayers);
}
Paste these functions in PuppyRaffleTest.t.sol
function testGasUseEnterRaffle() public {
addNumberPlayersToRaffle(puppyRaffle, 200);
}
function testGasUseEnterRaffleOptimized() public {
addNumberPlayersToRaffleOptimized(puppyRaffle, 200);
}
function addNumberPlayersToRaffleOptimized(PuppyRaffle _puppyRaffle, uint n) public {
address[] memory players = new address[](n);
for (uint i = 0; i < n; i++) {
players[i] = address(i + 10);
}
_puppyRaffle.enterRaffleOptimized{value: entranceFee * n}(players);
}
function addNumberPlayersToRaffle(PuppyRaffle _puppyRaffle, uint n) public {
address[] memory players = new address[](n);
for (uint i = 0; i < n; i++) {
players[i] = address(i + 10);
}
_puppyRaffle.enterRaffle{value: entranceFee * n}(players);
}

Run in the following command in the terminal at the root of the project:

forge snapshot --match-test testGasUseRaffle

We should have the following output:

Running 2 tests for test/PuppyRaffleTest.t.sol:PuppyRaffleTest
[PASS] testGasUseEnterRaffle() (gas: 20427396)
[PASS] testGasUseEnterRaffleOptimized() (gas: 9352736)
Test result: ok. 2 passed; 0 failed; 0 skipped; finished in 67.88ms

The optimized enterRaffle() consumes 45% of what the first enterRaffle() does. This disparity it increases when passing more players into the function, when passing 300 players, these are the outputs:

Running 2 tests for test/PuppyRaffleTest.t.sol:PuppyRaffleTest
[PASS] testGasUseEnterRaffle() (gas: 42457434)
[PASS] testGasUseEnterRaffleOptimized() (gas: 17100325)

Making that the gas consumption is so great in the first one that it won't be possible to run in the Ethereum blockchain, which at this time the gas limit of nodes is set to 30_000_000. We can check this with this command:

forge snapshot --match-test testGasUseEnterRaffle --gas-limit 30000000
Running 2 tests for test/PuppyRaffleTest.t.sol:PuppyRaffleTest
[FAIL. Reason: EvmError: Revert] testGasUseEnterRaffle() (gas: 29512007)
[PASS] testGasUseEnterRaffleOptimized() (gas: 17100325)
Test result: FAILED. 1 passed; 1 failed; 0 skipped; finished in 86.90ms
Ran 1 test suites: 1 tests passed, 1 failed, 0 skipped (2 total tests)
Failing tests:
Encountered 1 failing test in test/PuppyRaffleTest.t.sol:PuppyRaffleTest
[FAIL. Reason: EvmError: Revert] testGasUseEnterRaffle() (gas: 29512007)

And the EvmError if we inspect it, it's the error "EvmError: OutOfGas"

Updates

Lead Judging Commences

patrickalphac Lead Judge about 2 years ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

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

Give us feedback!