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
Rank: 212/246
Findings: 1
Award: $10.79
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: Rolezn
Also found by: 0x3b, 0xGordita, 0xSmartContract, 0xhacksmithh, 0xnev, 0xpanicError, 4lulz, Angry_Mustache_Man, ArbitraryExecution, Aymen0909, Bason, BlueAlder, EvanW, Franfran, HHK, Haipls, IgorZuk, JCN, KrisApostolov, Madalad, MiksuJak, MiniGlome, RaymondFam, ReyAdmirado, Rickard, Sathish9098, Udsen, adriro, alexzoid, anodaram, arialblack14, c3phas, carlitox477, ch0bu, chaduke, codeslide, d3e4, dicethedev, ernestognw, fatherOfBlocks, georgits, hunter_w3b, inmarelibero, lukris02, mahdirostami, maxper, pavankv, pixpi, rotcivegaf, smaul, tank, tnevler, wen, yac
10.7864 USDC - $10.79
Issue | Instances | |
---|---|---|
GAS-1 | Store balance calls return values in memory instead of calling them multiple times in one function | 2 |
GAS-2 | Store derivative address in memory whenever it is read from storage more than once | 3 |
GAS-3 | Do not recalculate localTotalWeights when a weight is adjusted or added | 2 |
memory
instead of calling them multiple times in one functionStore <address>.balance()
in a memory
variable to save gas on addresses balance calls.
File: contracts/SafEth/SafEth.sol | stake | Lines: 71-75
for (uint i = 0; i < derivativeCount; i++) underlyingValue += (derivatives[i].ethPerDerivative(derivatives[i].balance()) * derivatives[i].balance()) / 10 ** 18;
Could be changed to:
for (uint i = 0; i < derivativeCount; i++) { uint256 derivativeBalance = derivatives[i].balance(); underlyingValue += (derivatives[i].ethPerDerivative(derivativeBalance) * derivativeBalance) / 10 ** 18; }
Saves 8145 gas per call for SafEth-Integration.test.ts:78 test.
File: contracts/SafEth/SafEth.sol | rebalanceToWeights | Lines: 140-143
for (uint i = 0; i < derivativeCount; i++) { if (derivatives[i].balance() > 0) derivatives[i].withdraw(derivatives[i].balance()); }
Could be changed to:
for (uint i = 0; i < derivativeCount; i++) { uint256 derivativeBalance = derivatives[i].balance(); if (derivativeBalance > 0) derivatives[i].withdraw(derivativeBalance); }
Saves 8154 gas for SafEth-Integration.test.ts:94 test. Saves 4760 gas for SafEth-Integration.test.ts:123 test.
memory
whenever it is read from storage more than onceThere are for
loops iterating over derivatives
and performing multiple calls on each derivative
in these loops. Store derivative[i]
in memory
whenever it is used more than once in a single iteration.
File: contracts/SafEth/SafEth.sol | stake | Lines: 71-75
for (uint i = 0; i < derivativeCount; i++) underlyingValue += (derivatives[i].ethPerDerivative(derivatives[i].balance()) * derivatives[i].balance()) / 10 ** 18;
Could be changed to:
for (uint i = 0; i < derivativeCount; i++) { IDerivative derivative = derivatives[i]; underlyingValue += (derivative.ethPerDerivative(derivative.balance()) * derivative.balance()) / 10 ** 18; }
Saves ~537 gas per call for SafEth-Integration.test.ts:78 test.
File: contracts/SafEth/SafEth.sol | unstake | Lines: 115-118
for (uint256 i = 0; i < derivativeCount; i++) { IDerivative derivative = derivatives[i]; // withdraw a percentage of each asset based on the amount of safETH uint256 derivativeAmount = (derivative.balance() * _safEthAmount) / safEthTotalSupply; if (derivativeAmount == 0) continue; // if derivative empty ignore derivative.withdraw(derivativeAmount); }
Could be changed to:
for (uint256 i = 0; i < derivativeCount; i++) { // withdraw a percentage of each asset based on the amount of safETH uint256 derivativeAmount = (derivatives[i].balance() * _safEthAmount) / safEthTotalSupply; if (derivativeAmount == 0) continue; // if derivative empty ignore derivatives[i].withdraw(derivativeAmount); }
Saves ~501 gas per call for SafEth-Integration.test.ts:86 test.
File: contracts/SafEth/SafEth.sol | rebalanceToWeights | Lines: 140-143
for (uint i = 0; i < derivativeCount; i++) { if (derivatives[i].balance() > 0) derivatives[i].withdraw(derivatives[i].balance()); }
Could be changed to:
for (uint i = 0; i < derivativeCount; i++) { if (derivatives[i].balance() > 0) derivatives[i].withdraw(derivatives[i].balance()); }
Saves 546 gas for SafEth-Integration.test.ts:94 test. Saves 353 gas for SafEth-Integration.test.ts:123 test.
totalWeights
when a weight
is adjusted or addedWhen a weight
is adjusted or a new one is added, localTotalWeight
are calculated iterating over weights
array. It is not needed since we know both the value of totalWeight
and a weight
to be adjusted/added. Moreover weights
array does not ever change without totalWeight
being updated, so we know that weights.sum()
is always equal to totalWeight
.
File: contracts/SafEth/SafEth.sol | adjustWeight | Lines: 169-173
weights[_derivativeIndex] = _weight; uint256 localTotalWeight = 0; for (uint256 i = 0; i < derivativeCount; i++) localTotalWeight += weights[i]; totalWeight = localTotalWeight;
Could be changed to:
totalWeight = totalWeight + _weight - weights[_derivativeIndex]; weights[_derivativeIndex] = _weight;
Saves 7284 gas per call.
File: contracts/SafEth/SafEth.sol | addDerivative | Lines: 169-173
weights[derivativeCount] = _weight; derivativeCount++; uint256 localTotalWeight = 0; for (uint256 i = 0; i < derivativeCount; i++) localTotalWeight += weights[i]; totalWeight = localTotalWeight;
Could be changed to:
weights[derivativeCount] = _weight; derivativeCount++; totalWeight += _weight;
Saves 506 gas + 2455 gas * weights.length
per call.
#0 - c4-sponsor
2023-04-07T21:42:41Z
toshiSat marked the issue as sponsor acknowledged
#1 - c4-judge
2023-04-23T14:51:38Z
Picodes marked the issue as grade-b