Popcorn contest - ReyAdmirado's results

A multi-chain regenerative yield-optimizing protocol.

General Information

Platform: Code4rena

Start Date: 31/01/2023

Pot Size: $90,500 USDC

Total HM: 47

Participants: 169

Period: 7 days

Judge: LSDan

Total Solo HM: 9

Id: 211

League: ETH

Popcorn

Findings Distribution

Researcher Performance

Rank: 24/169

Findings: 1

Award: $1,023.26

Gas:
grade-a

🌟 Selected for report: 0

🚀 Solo Findings: 0

Awards

1023.2634 USDC - $1,023.26

Labels

bug
G (Gas Optimization)
grade-a
edited-by-warden
G-16

External Links

issue
1State variables only set in the constructor should be declared immutable.
2Structs can be packed into fewer storage slots
3state variables can be packed into fewer storage slots
4Multiple address/ID mappings can be combined into a single mapping of an address/ID to a struct, where appropriate
5state variables should be cached in stack variables rather than re-reading them from storage
6Add unchecked {} for subtractions where the operands cannot underflow because of a previous require() or if statement
7<x> += <y> costs more gas than <x> = <x> + <y> for state variables
8not using the named return variables when a function returns, wastes deployment gas
9can make the variable outside the loop to save gas
10++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
11use a more recent version of solidity
12internal functions only called once can be inlined to save gas
13abi.encode() is less efficient than abi.encodepacked()
14usage of uint/int smaller than 32 bytes (256 bits) incurs overhead
15 Ternary over if ... else
16public functions not called by the contract should be declared external instead
17should use arguments instead of state variable
18instead of calculating a statevar with keccak256() every time the contract is made pre calculate them before and only give the result to a constant
19use existing cached version of state var
20Optimize names to save gas
21Non-strict inequalities are cheaper than strict ones
22Setting the constructor to payable
23instead of assigning to zero use delete
24part of the code can be pre calculated

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).

feeRecipient can be declared immutable

adminProxy

vaultRegistry

permissionRegistry

escrow

2. Structs can be packed into fewer storage slots

Each slot saved can avoid an extra Gsset (20000 gas) for the first setting of the struct. Subsequent reads as well as writes have smaller gas savings

put account near the start so the 3 uint32 variables(12 byte) and the address variable(20 bytes) be in the same slot(32byte). this will save one slot usage

3. state variables can be packed into fewer storage slots

If variables occupying the same slot are both written the same function or by the constructor, avoids a separate Gsset (20000 gas). Reads of the variables are also cheaper.

_decimals(#L38) and feeRecipient(#L510) can be put together in the same slot if they be declared near each other. there is no reads that uses both variable so mainly saves Gsset of 20000 for a slot. bring the feeRecipient near _decimals

4. Multiple address/ID mappings can be combined into a single mapping of an address/ID to a struct, where appropriate

Saves a storage slot for the mapping. Depending on the circumstances and sizes of types, can avoid a Gsset (20000 gas) per mapping combined. Reads and subsequent writes can also be cheaper when a function requires both values and they both fit in the same storage slot. Finally, if both fields are accessed in the same function, can save ~42 gas per access due to not having to recalculate the key’s keccak256 hash (Gkeccak256 - 30 gas) and that calculation’s associated stack operations.

templateExists and templateCategoryExists can be simplified to use less slots. used together once so it will save a bit gas there too.

5. 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.

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

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

caching deploymentController will save 97 gas. its being used twice in #L837 and #L840 and can be cached before it.

cache yVault.totalSupply() before the if statement because it will usually be false and we will save big gas for a risk of losing 3 gas if the check be true. used twice in #L90 and #L95. should be cached before this line

cache VaultAPI(IYearnRegistry(externalRegistry).latestVault(_asset)) and assign the cached version to yVault in #L45 so we can use the cached version in #L54 to save gas.

(the next two will be the complete version of the c4audit finding because its not completely marked there)

caching adapter will save 97 gas. adapter is being used twice in #L604 and #L606, we can reduce one SLOAD with caching it before #L604.(it changes after #L608 so the #L610 adapter should be cached version of proposedAdapter that I explain after this one)

the proposedAdapter is being used in both #L606 and #L608 and can be cached before to save gas as c4udit found, but adapter in line 610 can be the cached version of proposedAdapter instead. this will save 100 more gas. cache before #L606

6. Add unchecked {} for subtractions where the operands cannot underflow because of a previous require() or if statement

require(a <= b); x = b - a => require(a <= b); unchecked { x = b - a } if(a <= b); x = b - a => if(a <= b); unchecked { x = b - a } this will stop the check for overflow and underflow so it will save gas

7. <x> += <y> costs more gas than <x> = <x> + <y> for state variables

Using the addition operator instead of plus-equals saves gas

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

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

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

success and returnData

7 varibles here

escrowId and escrow and claimable

rewardAmount and escrowInfo

rewardToken and rewards

10. ++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

11. use a more recent version of solidity

use a strict version of solidity

Use a solidity version of at least 0.8.17 to get prevention of the incorrect removal of storage writes before calls to Yul functions that conditionally terminate the external EVM call; Simplify the starting offset of zero-length operations to zero. More efficient overflow checks for multiplication.

12. 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.

_registerCreatedVault

_handleVaultStakingRewards

__deployAdapter

_encodeAdapterData

_deployStrategy

_registerVault

_verifyAdapterConfiguration

_shareValue

_freeFunds

_yTotalAssets

_calculateLockedProfit

_lockToken

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

14. 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

when using smaller versions of types like uint or bytes wouldnt help us to send stuff in one slot(like for a struct) its better to just use the 256 bits version of types to not waste gas.

many places for len and i in

15. Ternary over if ... else

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

16. 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.

17. should use arguments instead of state variable

This will save near 97 gas

instead of asset asset_ can be used

18. 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 or immutable

bytes4(keccak256("deploy(bytes32,bytes32,bytes)")) always has the same answer so it can be pre calculated and only the answer should be given to the immutable or constant so it doesnt get calculated every time the contract is made.

19. use existing cached version of state var

saves 97 gas each time

instead of highWaterMark use the cached version highWaterMark_ in these lines. 2 instances

20. 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

vault.sol has lots of external and public function and lots of properties and it would be much more efficient if the functions and properties been sorted by the most used functions and properties.

21. 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

4 instances here

22. 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.

23. instead of assigning to zero use delete

assigning to zero uses more gas than using delete , and they both assign variable to default value. so it is encouraged if the data is no longer needed use delete instead.

24. part of the code can be pre calculated

the keccak256() used here will always be the same so there is no need to calculate it inside the function. just pre calculate the answer to it and use the answer inside the code instead. use a comment to show what it was to the readers

keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"),

keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),

keccak256("1"),

keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)")

keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),

keccak256("1"),

#0 - c4-judge

2023-03-01T00:01:39Z

dmvt marked the issue as grade-a

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