Issue | Instances | |
---|---|---|
[GAS-01] | The result of function calls should be cached rather than re-calling the function | 2 |
[GAS-02] | For loop can be replace by simple addition | 1 |
[GAS-03] | Check should be done before For loop | 1 |
[GAS-04] | Check should be done beforehand | 1 |
[GAS-05] | Unnecessary calculations | 1 |
[GAS-06] | Functions guaranteed to revert when called by normal users can be marked payable |
14 |
[GAS-07] | Increments can be unchecked |
1 |
[GAS-08] | Setting the constructor to payable |
4 |
The instances below point to the second+ call of the function within a single function.
Instances (2):
File: contracts/SafEth/SafEth.sol
74: derivatives[i].balance()
142: derivatives[i].withdraw(derivatives[i].balance());
Consider storing the value of derivatives[i].balance()
in a local variable instead of calling this function twice.
In the following code, the for loop can be replaced by a simple addition because only the _weight
is to be added to the totalWeight
.
Instance (1):
File: contracts/SafEth/SafEth.sol
190: uint256 localTotalWeight = 0;
for (uint256 i = 0; i < derivativeCount; i++)
localTotalWeight += weights[i];
totalWeight = localTotalWeight;
Can be replaced by:
totalWeight = totalWeight + _weight;
The check of ethAmountToRebalance
should be done before the for loop.
Instance (1):
File: contracts/SafEth/SafEth.sol
148: for (uint i = 0; i < derivativeCount; i++) {
if (weights[i] == 0 || ethAmountToRebalance == 0) continue; // @audit edit this check
uint256 ethAmount = (ethAmountToRebalance * weights[i]) /
totalWeight;
// Price will change due to slippage
derivatives[i].deposit{value: ethAmount}();
}
Can be refactored as such:
if (ethAmountToRebalance != 0) { // @audit edit here
for (uint i = 0; i < derivativeCount; i++) {
if (weights[i] == 0) continue; // @audit edit here
uint256 ethAmount = (ethAmountToRebalance * weights[i]) /
totalWeight;
// Price will change due to slippage
derivatives[i].deposit{value: ethAmount}();
}
}
Value check of weight
could be done just after the initialization of the variable.
Instance (1):
File: contracts/SafEth/SafEth.sol
85: uint256 weight = weights[i];
86: IDerivative derivative = derivatives[i];
87: if (weight == 0) continue; // @audit check should be done beforehand
Line 86 and 87 should be swapped.
Multiplication then division by the same number (10 ** 18) is unnecessary as it does not change the initial value.
Instance (1):
File: contracts/SafEth/derivatives/Reth.sol
215: else return (poolPrice() * 10 ** 18) / (10 ** 18);
This line can be replaced by:
else return poolPrice();
If a function modifier or require such as onlyOwner/onlyX 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.
Instances (14):
File: contracts/SafEth/SafEth.sol
138: function rebalanceToWeights() external onlyOwner {
214: function setMinAmount(uint256 _minAmount) external onlyOwner {
223: function setMaxAmount(uint256 _maxAmount) external onlyOwner {
232: function setPauseStaking(bool _pause) external onlyOwner {
241: function setPauseUnstaking(bool _pause) external onlyOwner {
File: contracts/SafEth/derivatives/Reth.sol
58: function setMaxSlippage(uint256 _slippage) external onlyOwner {
107: function withdraw(uint256 amount) external onlyOwner {
156: function deposit() external payable onlyOwner returns (uint256) {
File: contracts/SafEth/derivatives/SfrxEth.sol
51: function setMaxSlippage(uint256 _slippage) external onlyOwner {
60: function withdraw(uint256 _amount) external onlyOwner {
94: function deposit() external payable onlyOwner returns (uint256) {
File: contracts/SafEth/derivatives/WstEth.sol
48: function setMaxSlippage(uint256 _slippage) external onlyOwner {
56: function withdraw(uint256 _amount) external onlyOwner {
73: function deposit() external payable onlyOwner returns (uint256) {
Increments for uint256 iterators cannot realistically overflow as this would require too many increments, so this can be unchecked
.
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.
Instances (1):
File: contracts/SafEth/SafEth.sol
188: derivativeCount++;
Saves ~13 gas per instance
Instances (4):
File: contracts/SafEth/SafEth.sol
38: constructor() {
File: contracts/SafEth/derivatives/Reth.sol
33: constructor() {
File: contracts/SafEth/derivatives/SfrxEth.sol
27: constructor() {
File: contracts/SafEth/derivatives/WstEth.sol
24: constructor() {