Asymmetry contest - ReyAdmirado's results

A protocol to help diversify and decentralize liquid staking derivatives.

General Information

Platform: Code4rena

Start Date: 24/03/2023

Pot Size: $49,200 USDC

Total HM: 20

Participants: 246

Period: 6 days

Judge: Picodes

Total Solo HM: 1

Id: 226

League: ETH

Asymmetry Finance

Findings Distribution

Researcher Performance

Rank: 208/246

Findings: 1

Award: $10.79

Gas:
grade-b

🌟 Selected for report: 0

🚀 Solo Findings: 0

1. state variables should be cached in stack variables rather than re-reading them from storage

The instances below point to the second+ access of a state variable within a function. 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.

derivatives[i].balance() is being read twice for each iteration. cache it at the start of the for loop to reduce a complex SLOAD per iteration.

derivativeCount is being read twice in #L71 and #L84 so it can be cached before #L71 to reduce one SLOAD

same for derivativeCount here in #L140 and #L147

totalWeight is being read every time in the loop but it is not changed in the loop so it is always the same while the loop is going. cache it before the loop to stop SLOADs on every iteration and only do one before the loop.

same for totalWeighthere in #L150

cache derivatives[i].balance() here because the if statement is usually true and inside it will be another complex SLOAD for it. even if the if statement be false we only risk losing 3 gas because of caching it and it is totally worth it. cache derivatives[i].balance() before the if statement. this will save lots of gas because it saves gas for every iteration of for loop

weights[i] can be cached to possibly reduce a complex SLOAD. it is read in both #L148 and #L149 and usually #L149 will happen so it is worth to risk losing 3 gas for caching to save huge amount of gas. saves gas for every iteration of for loop

derivativeCount is being read 4 times and it should be cached at the start of the function to reduce 3 extra SLOADs. with caching it we can stop 2 reads in #L186 and #L187 but for #L191 and #194 we can use derivativeCount + 1 or we can update the cached version as well as the statevar near #L188

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

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

weight

ethAmount

depositAmount

derivativeReceivedEthValue

derivativeAmount

3. Avoid a SLOAD optimistically

There is a chance that the first part will be true so the second part doesn’t need to be checked, so it is better to use the part that we have first instead of the part that needs to be called.

if (weights[i] == 0 || ethAmountToRebalance == 0) should be if (ethAmountToRebalance == 0 || weights[i] == 0) for a possible reduce of a complex SLOAD

4. using bool for storage incurs overhead

Booleans are more expensive than uint256 or any type that takes up a full word because each write operation emits an extra SLOAD to first read the slot's contents, replace the bits taken up by the boolean, and then write back. This is the compiler's defense against contract upgrades and pointer aliasing, and it cannot be disabled. Use uint256(1) and uint256(2) for true/false to avoid a Gwarmaccess (100 gas) for the extra SLOAD, and to avoid Gsset (20000 gas) when changing from ‘false’ to ‘true’, after having been ‘true’ in the past

pauseStaking and pauseUnstaking are inherited and both bool variables consider changing them because it has impact on current contracts in scope but the contract they are declared in is out of scope

5. Ternary over if ... else

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

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

name()

ethPerDerivative()

balance()

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

use _minAmount instead

use _maxAmount instead

use _pause instead

use _pause instead

8. Functions guaranteed to revert when called by normal users can be marked payable

If a function modifier or require such as onlyOwner-admin is used, the function will revert if a normal user tries to pay the function. Marking the function as payable will lower the gas cost for legitimate callers because the compiler will not include checks for whether a payment was provided. The extra opcodes avoided are CALLVALUE(2), DUP1(3), ISZERO(3), PUSH2(3), JUMPI(10), PUSH1(3), DUP1(3), REVERT(0), JUMPDEST(1), POP(2) which costs an average of about 21 gas per call to the function, in addition to the extra deployment cost.

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

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

11. part of the code can be pre calculated

these parts of code will use operations to calculate every time they are used, so instead just pre calculate them and use them as constants made in the contract

1 * 10 ** 16 and 10 ** 18 and 96 * 2 and 5 * 10 ** 17 and 200 * 10 ** 18

#0 - c4-sponsor

2023-04-10T19:43:03Z

toshiSat marked the issue as sponsor acknowledged

#1 - c4-judge

2023-04-23T19:06:44Z

Picodes marked the issue as grade-b

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