function setCurvePool(address _curvePool) external onlyOwner {
Because the external address is not verified against a registry (e.g. the curve registry 0x0000000022D53366457F9d5E68Ec105046FC4383), the validation could be sidestepped by a malicious owner.
Because of that setToAndFromCurve() could be replaced by just inputting the pool indexes, saving the STATICALL and SLOADS which, beside the extra small math, should save 2.1k 2 (SLOAD) + 100 2 (STATICALL) = 4400 gas
Make Cowswap Fields Constants - 2.1k * 2 = 4200 gas
Double SLOAD when you already have cached value in memory - 97 gas
In both isntances you check with _isClaimAvailable but you already cached Claim memory info = warmUpInfo[_recipient].
To avoid an additional SLOAD (100 gas), you could just pass the info to the function
Executive Summary
Below are listed gas savings refactorings along with the estimated gas saved.
Reducing SLOADS is by far the best way to save gas on this codebase, for that reason most of the advice is based on that
Minor gas savings are also listed, but reducing SLOADs should be prioritized especially as it will save gas for end users
Optimized
setCurvePool
- 4400 gashttps://github.com/code-423n4/2022-06-yieldy/blob/524f3b83522125fb7d4677fa7a7e5ba5a2c0fe67/src/contracts/Staking.sol#L157-L158
Because the external address is not verified against a registry (e.g. the curve registry
0x0000000022D53366457F9d5E68Ec105046FC4383
), the validation could be sidestepped by a malicious owner.Because of that
setToAndFromCurve()
could be replaced by just inputting the pool indexes, saving the STATICALL and SLOADS which, beside the extra small math, should save 2.1k 2 (SLOAD) + 100 2 (STATICALL) = 4400 gasMake Cowswap Fields Constants - 2.1k * 2 = 4200 gas
https://github.com/code-423n4/2022-06-yieldy/blob/524f3b83522125fb7d4677fa7a7e5ba5a2c0fe67/src/contracts/Staking.sol#L73-L74
These values are hardcoded in the initializer, it would be better to hardcode them as constants
Will save 2.1k each time you read them
Storage Read when function param is cheaper - 100 gas
https://github.com/code-423n4/2022-06-yieldy/blob/524f3b83522125fb7d4677fa7a7e5ba5a2c0fe67/src/contracts/LiquidityReserve.sol#L82
The function is receiving a new
_stakingContract
but using the storage value to set approvalsChange
To
Double SLOAD when MSTORE would be chaper (94 gas * 3) - 282 gas
stakingToken
stakingToken
stakingToken
Double SLOAD when you already have cached value in memory - 97 gas
In both isntances you check with
_isClaimAvailable
but you already cachedClaim memory info = warmUpInfo[_recipient]
. To avoid an additional SLOAD (100 gas), you could just pass the info to the functionhttps://github.com/code-423n4/2022-06-yieldy/blob/524f3b83522125fb7d4677fa7a7e5ba5a2c0fe67/src/contracts/Staking.sol#L465-L467
Also applies here https://github.com/code-423n4/2022-06-yieldy/blob/524f3b83522125fb7d4677fa7a7e5ba5a2c0fe67/src/contracts/Staking.sol#L425-L430
Refactor to
Double SLOAD - 94 gas
https://github.com/code-423n4/2022-06-yieldy/blob/524f3b83522125fb7d4677fa7a7e5ba5a2c0fe67/src/contracts/BatchRequests.sol#L50-L59
Would recommend refactoring to
Which will save 94 gas
Expensive read from storage - 191 gas per iteration
https://github.com/code-423n4/2022-06-yieldy/blob/524f3b83522125fb7d4677fa7a7e5ba5a2c0fe67/src/contracts/BatchRequests.sol#L14-L27
We could instead cache the value
Saving 94 gas on every iteration which returns false And saving another 97 gas when doing the
sendWithdrawalRequests
For a total of 191 gas per iteration because we use Memory intead of Storage
Same deal - reading
contracts
from storage instead of caching in memory - 94 gas per loophttps://github.com/code-423n4/2022-06-yieldy/blob/524f3b83522125fb7d4677fa7a7e5ba5a2c0fe67/src/contracts/BatchRequests.sol#L29-L44
We can save 94 gas per iteration here as well
Additional SLOAD when you already cached the value - 97 gas
https://github.com/code-423n4/2022-06-yieldy/blob/524f3b83522125fb7d4677fa7a7e5ba5a2c0fe67/src/contracts/Staking.sol#L319-L321
You can just use
tokePoolContract
at this point, saving 97 gasSimilarly you can use a memory cache here as well: https://github.com/code-423n4/2022-06-yieldy/blob/524f3b83522125fb7d4677fa7a7e5ba5a2c0fe67/src/contracts/Staking.sol#L144-L147
Unnecessary MSTORE - 6 gas * 2 = 12 gas
https://github.com/code-423n4/2022-06-yieldy/blob/524f3b83522125fb7d4677fa7a7e5ba5a2c0fe67/src/contracts/Staking.sol#L329-L345
You're storing the casted version of the address, but you could simply cast the storage value, avoiding the extra 6 gas
Change to:
Additional instance: https://github.com/code-423n4/2022-06-yieldy/blob/524f3b83522125fb7d4677fa7a7e5ba5a2c0fe67/src/contracts/Staking.sol#L120-L121
Avoid reading from storage if you have a memory copy - 97 * 11 = 1067 gas
All fields in
initialize
are being read from storage, each read costing an additional 97 gas over just reading from the memory parametershttps://github.com/code-423n4/2022-06-yieldy/blob/524f3b83522125fb7d4677fa7a7e5ba5a2c0fe67/src/contracts/Staking.sol#L77-L92
Can be changed to
_curvePool != address(0)
etc.. Each SLOAD is 100 gas vs the CALLDATALOAD which costs 3 gasThere's 11 ALL_CAPS storage vars, so the refactoring will save 1067 gas on the initializer call