code-423n4 / 2022-09-frax-findings

2 stars 1 forks source link

Gas Optimizations #276

Open code423n4 opened 2 years ago

code423n4 commented 2 years ago

https://github.com/code-423n4/2022-09-frax/blob/55ea6b1ef3857a277e2f47d42029bc0f3d6f9173/src/frxETHMinter.sol#L129 https://github.com/code-423n4/2022-09-frax/blob/55ea6b1ef3857a277e2f47d42029bc0f3d6f9173/src/OperatorRegistry.sol#L62 https://github.com/code-423n4/2022-09-frax/blob/55ea6b1ef3857a277e2f47d42029bc0f3d6f9173/src/OperatorRegistry.sol#L84 https://github.com/code-423n4/2022-09-frax/blob/55ea6b1ef3857a277e2f47d42029bc0f3d6f9173/src/OperatorRegistry.sol#L114 These increment operations never need to be checked for over/underflow because the variable will never reach the max number of uint256 (will run out of gas long before that happens). Every for loop can be rewritten as follows:

for(uint256 i ; i < x){
      //loop logic
      unchecked {++i;} }

https://github.com/code-423n4/2022-09-frax/blob/55ea6b1ef3857a277e2f47d42029bc0f3d6f9173/src/OperatorRegistry.sol#L114 original_validators.length shall be cached before for cycle

https://github.com/corddry/ERC4626/blob/643cd044fac34bcbf64e1c3790a5126fec0dbec1/src/xERC4626.sol#L78 function syncRewards can be rewritten as follows, which will save around 150 gas at each call

function syncRewards() public virtual {
    uint192 lastRewardAmount_ = lastRewardAmount;
    uint32 timestamp = block.timestamp.safeCastTo32();

    if (timestamp < rewardsCycleEnd) revert SyncError();

    uint256 nextRewards = asset.balanceOf(address(this)) - storedTotalAssets;

    uint32 end = ((timestamp + rewardsCycleLength) / rewardsCycleLength) * rewardsCycleLength;

    // Combined single SSTORE
    lastRewardAmount = nextRewards.safeCastTo192();
    lastSync = timestamp;
    rewardsCycleEnd = end;

    emit NewRewardsCycle(end, nextRewards);
}

https://github.com/code-423n4/2022-09-frax/blob/55ea6b1ef3857a277e2f47d42029bc0f3d6f9173/src/frxETHMinter.sol#L38 and 39 Use private instead of public for constants, it saves gas

https://github.com/code-423n4/2022-09-frax/blob/55ea6b1ef3857a277e2f47d42029bc0f3d6f9173/src/frxETHMinter.sol#L97 X += Y costs more gas than X = X + Y for state variables currentWithheldETH = currentWithheldETH + withheld_amt is more efficient then currentWithheldETH += withheld_amt

https://github.com/code-423n4/2022-09-frax/blob/55ea6b1ef3857a277e2f47d42029bc0f3d6f9173/src/frxETHMinter.sol#L79 and 126 != 0 costs less gas compared to > 0 for unsigned integers in require statements with the optimizer enabled

https://github.com/code-423n4/2022-09-frax/blob/55ea6b1ef3857a277e2f47d42029bc0f3d6f9173/src/OperatorRegistry.sol#L93 it's better to verify at function begininng if remove_idx exists in order to save gas

https://github.com/code-423n4/2022-09-frax/blob/55ea6b1ef3857a277e2f47d42029bc0f3d6f9173/src/OperatorRegistry.sol#L82 it's better to verify at function begininng if times < validators.length