Aragon Protocol contest - ReyAdmirado's results

The most user-friendly tech stack to launch your DAO.

General Information

Platform: Code4rena

Start Date: 03/03/2023

Pot Size: $90,500 USDC

Total HM: 4

Participants: 42

Period: 7 days

Judge: 0xean

Total Solo HM: 2

Id: 219

League: ETH

Aragon Protocol

Findings Distribution

Researcher Performance

Rank: 17/42

Findings: 1

Award: $575.19

Gas:
grade-a

🌟 Selected for report: 0

🚀 Solo Findings: 0

Awards

575.1851 USDC - $575.19

Labels

bug
G (Gas Optimization)
grade-a
sponsor acknowledged
G-09

External Links

1. State variables only set in the constructor should be declared immutable.

Avoids a Gsset (20000 gas) in the constructor, and replaces each Gwarmaccess (100 gas) with a PUSH32 (3 gas).

2. expressions for constant values such as a call to keccak256(), should use immutable rather than constant

3. state variables should be cached in stack variables rather than re-reading them from storage (ones not caught by C4udit)

Caching of a state variable replace each Gwarmaccess (100 gas) with a much cheaper stack read. Other less obvious fixes/optimizations include having local memory caches of state variable structs, or having local caches of state variable contracts/addresses.

example possible 97 gas save with risking 3 gas. if the check fails we save 97 for the second quitPeriod read and if it passes we just lose 3 gas. cache it before this line

node can be cached because it is used twice in L86 and L93. this will save 97 gas. cache it before L94

resolver can be cached at the start of the function because it is used twice in L94 and L95. this will save 97 gas

possible gas save with only risking 3 gas. if the check passes (usually passes) we save gas for the second multisigSettings.minApprovals read and if it passes we just lose 3 gas. cache it before the if statement

latestRelease is being checked at least twice in this function(if the first if succeeds second use is inside it, and if it fails the second if statement check is the second use) so we should cache latestRelease before L143 to reduce one storage read.

4. not using the named return variables when a function returns, wastes deployment gas

5. can make the variable outside the loop to save gas

make the variable outside and only give the value to variable inside

6. ++i/i++ should be unchecked{++i}/unchecked{i++} when it is not possible for them to overflow, as is the case when used in for-loop and while-loops

The unchecked keyword is new in solidity version 0.8.0, so this only applies to that version or higher, which these instances are. This saves 30-40 gas PER LOOP

7. require() or revert() statements that check input arguments should be at the top of the function

Checks that involve constants should come before checks that involve state variables, function calls, and calculations. By doing these checks first, the function is able to revert before wasting a Gcoldsload (2100 gas*) in a function that may ultimately revert in the unhappy case.

swap the position of the third require with the first one because its gonna be cheaper checks first

swap these two requires

8. internal functions only called once can be inlined to save gas

Not inlining costs 20 to 40 gas because of two extra JUMP instructions and additional stack operations needed for function calls. following are the ones that makes sense to be inlined

9. abi.encode() is less efficient than abi.encodepacked()

10. usage of uint/int smaller than 32 bytes (256 bits) incurs overhead

When using elements that are smaller than 32 bytes, your contract’s gas usage may be higher. This is because the EVM operates on 32 bytes at a time. Therefore, if the element is smaller than that, the EVM must use more operations in order to reduce the size of the element from 32 bytes to the desired size. Each operation involving a uint8 costs an extra 22-28 gas (depending on whether the other operand is also a variable of type uint8) as compared to ones involving uint256, due to the compiler having to clear the higher bits of the memory word before operating on the uint8, as well as the associated stack operations of doing so. Use a larger size then downcast where needed https://docs.soliditylang.org/en/v0.8.11/internals/layout_in_storage.html Use a larger size then downcast where needed

buildsPerRelease can be made into 256 bit. if the state var is not being put in the same slot with another small statevar to in one slot, it makes sense to make them into 256 bit variables so it doesnt waste gas when doing operations

same with latestRelease

11. Ternary over if ... else

Using ternary operator instead of the if else statement saves gas.

12. public functions not called by the contract should be declared external instead

Contracts are allowed to override their parents’ functions and change the visibility from external to public and can save gas by doing so.

13. should use arguments instead of state variable

This will save 100 gas because it gets rid of a storage read and instead uses a argument that we already have which gives the same result

switch ens.resolver(_node) with _ens.resolver(_node) to save gas

14. before some functions we should check some variables for possible gas save

before transfer we should check for amount being 0 so the function doesnt run when its not gonna do anything

15. instead of calculating a statevar with keccak256() every time the contract is made pre calculate them before and only give the result to a constant

16. Optimize names to save gas

Contracts most called functions could simply save gas by function ordering via Method ID. Calling a function at runtime will be cheaper if the function is positioned earlier in the order (has a relatively lower Method ID) because 22 gas are added to the cost of a function for every position that came before it. The caller can save on gas if you prioritize most called functions.

See more here. you can use this tool to get the optimized version for function and properties signitures

many functions in MajorityVotingBase which makes it very wasteful if the names dont be optimzied.(its inherited many times too which makes it even more important)

17. Non-strict inequalities are cheaper than strict ones

In the EVM, there is no opcode for non-strict inequalities (>=, <=) and two operations are performed (> + = or < + =). consider replacing >= with the strict counterpart > and add - 1 to the second side

18. Setting the constructor to payable

You can cut out 10 opcodes in the creation-time EVM bytecode if you declare a constructor payable. Making the constructor payable eliminates the need for an initial check of msg.value == 0 and saves 13 gas on deployment with no security risks.

19. part of the code can be pre calculated

just pre calculate the answer of this part of code and use the answer inside the code instead to avoid unnecessary gas usage. use a comment to show what it was to the readers

RATIO_BASE - 1 can be calculated and defined as a constant to stop a operation each time the function runs.(2 instances in L528 and L530)

bytes4(keccak256("initialize(address,address,uint256)")) can be pre calculated and saved as a constant or a immutable and used that way to save gas

same with bytes4(keccak256("setNewVariable(uint256)")

same here keccak256("EXECUTE_PERMISSION")

bytes4(keccak256("initialize(address,address,uint256)"))

keccak256("EXECUTE_PERMISSION")

20. avoid an unnecessary initialization and do not write a default value for addresses

Address x = address(0)

#0 - c4-judge

2023-03-12T18:26:30Z

0xean marked the issue as grade-a

#1 - c4-sponsor

2023-03-22T13:11:10Z

novaknole20 marked the issue as sponsor acknowledged

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