Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Gas Optimizations #273

Open
code423n4 opened this issue May 25, 2022 · 0 comments
Open

Gas Optimizations #273

code423n4 opened this issue May 25, 2022 · 0 comments
Labels
bug Something isn't working duplicate This issue or pull request already exists G (Gas Optimization)

Comments

@code423n4
Copy link
Contributor

Gas

[G-01] Use != 0 instead of > 0 for Unsigned Integer Comparison in require statements.

Impact

!= 0 is cheapear than > 0 when comparing unsigned integers in require statements.

Proof of Concept

  contracts/Aura.sol::68 => require(_amount > 0, "Must mint something");
  contracts/AuraBalRewardPool.sol::121 => require(_amount > 0, "RewardPool : Cannot stake 0");
  contracts/AuraBalRewardPool.sol::139 => require(_amount > 0, "RewardPool : Cannot stake 0");
  contracts/AuraBalRewardPool.sol::157 => require(amount > 0, "RewardPool : Cannot withdraw 0");
  contracts/AuraBalRewardPool.sol::210 => require(rewardsAvailable > 0, "!balance");
  contracts/AuraLocker.sol::210 => require(rewardData[_rewardsToken].lastUpdateTime > 0, "Reward does not exist");
  contracts/AuraLocker.sol::259 => require(_amount > 0, "Cannot stake 0");
  contracts/AuraLocker.sol::359 => require(amt > 0, "Nothing locked");
  contracts/AuraLocker.sol::385 => require(length > 0, "no locks");
  contracts/AuraLocker.sol::431 => require(locked > 0, "no exp locks");
  contracts/AuraLocker.sol::471 => require(len > 0, "Nothing to delegate");
  contracts/AuraLocker.sol::822 => require(_rewards > 0, "No reward");
  contracts/AuraLocker.sol::851 => require(_reward > 0, "No reward");
  contracts/AuraMerkleDrop.sol::122 => require(_amount > 0, "!amount");
  contracts/AuraPenaltyForwarder.sol::52 => require(bal > 0, "!empty");
  contracts/AuraVestedEscrow.sol::118 => require(totalLocked[_recipient] > 0, "!funding");
  contracts/BalLiquidityProvider.sol::57 => require(bal > 0 && bal == _request.maxAmountsIn[i], "!bal");
  contracts/BalLiquidityProvider.sol::70 => require(balAfter > 0, "!mint");
  contracts/ExtraRewardsDistributor.sol::171 => require(_index > 0 && _index < rewardEpochs[_token].length - 1, "!past");
  convesx-platform/BaseRewardPool.sol::211 => require(_amount > 0, 'RewardPool : Cannot stake 0');
  convesx-platform/BaseRewardPool.sol::227 => require(amount > 0, 'RewardPool : Cannot withdraw 0');
  convesx-platform/Booster.sol::223 => require(IFeeDistributor(_feeDistro).getTokenTimeCursor(_feeToken) > 0, "!distro");
  convesx-platform/CrvDepositor.sol::169 => require(_amount > 0,"!>0");
  convesx-platform/PoolManagerSecondaryProxy.sol::104 => require(weight > 0, "must have weight");
  convesx-platform/interfaces/BoringMath.sol::20 => require(b > 0, "BoringMath: division by zero");
  convesx-platform/interfaces/BoringMath.sol::102 => require(b > 0, "BoringMath: division by zero");
  convesx-platform/interfaces/BoringMath.sol::123 => require(b > 0, "BoringMath: division by zero");
  convesx-platform/interfaces/BoringMath.sol::143 => require(b > 0, "BoringMath: division by zero");

Recommendation

Use != 0 instead of > 0.

[G-02] Cache Array Length Outside of Loop.

Impact

Reading array length at each iteration of the loop takes 6 gas (3 for mload and 3 to place memory_offset) in the stack. Caching the array length in the stack saves around 3 gas per iteration.

Proof of Concept

  contracts/AuraClaimZap.sol::143 => for (uint256 i = 0; i < rewardContracts.length; i++) {
  contracts/AuraClaimZap.sol::147 => for (uint256 i = 0; i < extraRewardContracts.length; i++) {
  contracts/AuraClaimZap.sol::151 => for (uint256 i = 0; i < tokenRewardContracts.length; i++) {
  contracts/AuraLocker.sol::410 => for (uint256 i = nextUnlockIndex; i < length; i++) {
  contracts/AuraLocker.sol::696 => for (uint256 i = nextUnlockIndex; i < locks.length; i++) {
  contracts/AuraVestedEscrow.sol::100 => for (uint256 i = 0; i < _recipient.length; i++) {
  convesx-platform/ArbitartorVault.sol::49 => for(uint256 i = 0; i < _toPids.length; i++){
  convesx-platform/BaseRewardPool.sol::214 => for(uint i=0; i < extraRewards.length; i++){
  convesx-platform/BaseRewardPool.sol::230 => for(uint i=0; i < extraRewards.length; i++){
  convesx-platform/BaseRewardPool.sol::262 => for(uint i=0; i < extraRewards.length; i++){
  convesx-platform/BaseRewardPool.sol::296 => for(uint i=0; i < extraRewards.length; i++){
  convesx-platform/Booster.sol::379 => for(uint i=0; i < poolInfo.length; i++){
  convesx-platform/Booster.sol::538 => for(uint256 i = 0; i < _gauge.length; i++){
  convesx-platform/ConvexMasterChef.sol::180 => for (uint256 pid = 0; pid < length; ++pid) {
  convesx-platform/PoolManagerSecondaryProxy.sol::69 => for(uint i=0; i < usedList.length; i++){

Recommendation

Store the array’s length in a variable before the for-loop.

[G-03] ++i costs less gas compared to i++ or i += 1

Impact

++i costs less gas compared to i++ or i += 1 for unsigned integer, as pre-increment is cheaper (about 5 gas per iteration). This statement is true even with the optimizer enabled.

Proof of Concept

  contracts/AuraClaimZap.sol::143 => for (uint256 i = 0; i < rewardContracts.length; i++) {
  contracts/AuraClaimZap.sol::147 => for (uint256 i = 0; i < extraRewardContracts.length; i++) {
  contracts/AuraClaimZap.sol::151 => for (uint256 i = 0; i < tokenRewardContracts.length; i++) {
  contracts/AuraLocker.sol::410 => for (uint256 i = nextUnlockIndex; i < length; i++) {
  contracts/AuraLocker.sol::696 => for (uint256 i = nextUnlockIndex; i < locks.length; i++) {
  contracts/AuraVestedEscrow.sol::100 => for (uint256 i = 0; i < _recipient.length; i++) {
  convesx-platform/ArbitartorVault.sol::49 => for(uint256 i = 0; i < _toPids.length; i++){
  convesx-platform/BaseRewardPool.sol::214 => for(uint i=0; i < extraRewards.length; i++){
  convesx-platform/BaseRewardPool.sol::230 => for(uint i=0; i < extraRewards.length; i++){
  convesx-platform/BaseRewardPool.sol::262 => for(uint i=0; i < extraRewards.length; i++){
  convesx-platform/BaseRewardPool.sol::296 => for(uint i=0; i < extraRewards.length; i++){
  convesx-platform/Booster.sol::379 => for(uint i=0; i < poolInfo.length; i++){
  convesx-platform/Booster.sol::538 => for(uint256 i = 0; i < _gauge.length; i++){
  convesx-platform/PoolManagerSecondaryProxy.sol::69 => for(uint i=0; i < usedList.length; i++){

Recommendation

Use ++i instead of i++ to increment the value of an uint variable.
Same thing for --i and i--.

[G-04] No need to initialize variables with default values

Impact

If a variable is not set/initialized, it is assumed to have the default value (0, false, 0x0 etc depending on the data type). Explicitly initializing it with its default value is an anti-pattern and wastes gas.

Proof of Concept

  contracts/AuraClaimZap.sol::143 => for (uint256 i = 0; i < rewardContracts.length; i++) {
  contracts/AuraClaimZap.sol::147 => for (uint256 i = 0; i < extraRewardContracts.length; i++) {
  contracts/AuraClaimZap.sol::151 => for (uint256 i = 0; i < tokenRewardContracts.length; i++) {
  contracts/AuraLocker.sol::174 => for (uint256 i = 0; i < rewardTokensLength; i++) {
  contracts/AuraLocker.sol::381 => uint256 reward = 0;
  contracts/AuraLocker.sol::485 => uint256 futureUnlocksSum = 0;
  contracts/AuraLocker.sol::540 => uint256 unlocksSinceLatestCkpt = 0;
  contracts/AuraLocker.sol::630 => uint256 low = 0;
  contracts/AuraLocker.sol::773 => for (uint256 i = 0; i < userRewardsLength; i++) {
  contracts/AuraVestedEscrow.sol::33 => bool public initialised = false;
  contracts/AuraVestedEscrow.sol::99 => uint256 totalAmount = 0;
  contracts/AuraVestedEscrow.sol::100 => for (uint256 i = 0; i < _recipient.length; i++) {
  contracts/BalLiquidityProvider.sol::51 => for (uint256 i = 0; i < 2; i++) {
  contracts/ExtraRewardsDistributor.sol::231 => uint256 claimableTokens = 0;
  convesx-platform/ArbitartorVault.sol::49 => for(uint256 i = 0; i < _toPids.length; i++){
  convesx-platform/BaseRewardPool.sol::214 => for(uint i=0; i < extraRewards.length; i++){
  convesx-platform/BaseRewardPool.sol::230 => for(uint i=0; i < extraRewards.length; i++){
  convesx-platform/BaseRewardPool.sol::262 => for(uint i=0; i < extraRewards.length; i++){
  convesx-platform/BaseRewardPool.sol::296 => for(uint i=0; i < extraRewards.length; i++){
  convesx-platform/Booster.sol::379 => for(uint i=0; i < poolInfo.length; i++){
  convesx-platform/Booster.sol::538 => for(uint256 i = 0; i < _gauge.length; i++){
  convesx-platform/BoosterOwner.sol::144 => for(uint256 i = 0; i < poolCount; i++){
  convesx-platform/ConvexMasterChef.sol::180 => for (uint256 pid = 0; pid < length; ++pid) {
  convesx-platform/ExtraRewardStashV3.sol::125 => for(uint256 i = 0; i < maxRewards; i++){
  convesx-platform/ExtraRewardStashV3.sol::199 => for(uint i=0; i < tCount; i++){
  convesx-platform/PoolManagerSecondaryProxy.sol::69 => for(uint i=0; i < usedList.length; i++){

Recommendation

Remove explicit default initializations.

[G-05] Non-strict inequalities are cheaper than strict ones

Impact

Strict inequalities add a check of non equality which costs around 3 gas.

Proof of Concept

Throughout codebase.

Recommendation

Use >= or <= instead of > and < when possible.

Tools used

c4udit, manual, slither

@code423n4 code423n4 added bug Something isn't working G (Gas Optimization) labels May 25, 2022
code423n4 added a commit that referenced this issue May 25, 2022
@0xMaharishi 0xMaharishi added the duplicate This issue or pull request already exists label May 28, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working duplicate This issue or pull request already exists G (Gas Optimization)
Projects
None yet
Development

No branches or pull requests

2 participants