15,000 USDC
View results
Submission Details
Severity: gas
Valid

Use do/while loops instead of for loops

Summary

Do/While loops can be used within the DSCEngine.sol instad of for loops to reduce gas costs.

Vulnerability Details

For loops are used within the DSCEngine.sol contract. A known issue states the cacheing of array length and variable initialisation, however 2 additional optimisations can be made to make the loops more efficient whilst still maintaing passing tests; they can be rewritten to be do/while loops.

An example of the current for loop can be seen below:

DSCEngine.sol:getAccountCollateralValue()

for (uint256 i = 0; i < s_collateralTokens.length; i++) {
address token = s_collateralTokens[i];
uint256 amount = s_collateralDeposited[user][token];
totalCollateralValueInUsd += getUsdValue(token, amount);
}

The gas report of this current function can be seen in the table below:

| src/DSCEngine.sol:DSCEngine contract | | | | | |
|--------------------------------------|-----------------|--------|--------|--------|---------|
| Deployment Cost | Deployment Size | | | | |
| 1004332 | 5445 | | | | |
| Function Name | min | avg | median | max | # calls |
| burnDsc | 398 | 12101 | 2675 | 33232 | 3 |
| calculateHealthFactor | 719 | 719 | 719 | 719 | 2 |
| depositCollateral | 435 | 40698 | 52032 | 52032 | 12 |
| depositCollateralAndMintDsc | 67909 | 128763 | 154933 | 154933 | 23 |
| getAccountCollateralValue | 42356 | 42356 | 42356 | 42356 | 1 |
| getAccountInformation | 9156 | 23356 | 9156 | 44656 | 5 |
| getAdditionalFeedPrecision | 292 | 292 | 292 | 292 | 2 |
| getCollateralBalanceOfUser | 805 | 805 | 805 | 805 | 1 |
| getCollateralTokenPriceFeed | 2617 | 2617 | 2617 | 2617 | 1 |
| getCollateralTokens | 7358 | 7358 | 7358 | 7358 | 1 |
| getDsc | 257 | 257 | 257 | 257 | 1 |
| getHealthFactor | 9640 | 9640 | 9640 | 9640 | 6 |
| getLiquidationBonus | 204 | 204 | 204 | 204 | 2 |
| getLiquidationThreshold | 293 | 293 | 293 | 293 | 1 |
| getMinHealthFactor | 270 | 270 | 270 | 270 | 1 |
| getPrecision | 314 | 314 | 314 | 314 | 2 |
| getTokenAmountFromUsd | 3678 | 6178 | 3678 | 18678 | 6 |
| getUsdValue | 3728 | 6870 | 3728 | 18728 | 7 |
| liquidate | 12786 | 67874 | 74400 | 96860 | 6 |
| mintDsc | 310 | 61895 | 64864 | 117545 | 4 |
| redeemCollateral | 413 | 15772 | 3468 | 43436 | 3 |
| redeemCollateralForDsc | 33402 | 40761 | 40761 | 48120 | 2 |

Impact

Gas costs are higher for the caller

Tools Used

  • VS Code

  • Foundry

  • Manual reading

Recommendations

To save the user some gas, use a do/while loop similar to the following example:

uint256 length = s_collateralTokens.length;
uint256 i;
do {
address token = s_collateralTokens[i];
uint256 amount = s_collateralDeposited[user][token];
totalCollateralValueInUsd += getUsdValue(token, amount);
unchecked {
++i;
}
} while (i < length);

The gas report following the single loop change can be seen here:

| src/DSCEngine.sol:DSCEngine contract | | | | | |
|--------------------------------------|-----------------|--------|--------|--------|---------|
| Deployment Cost | Deployment Size | | | | |
| 997125 | 5409 | | | | |
| Function Name | min | avg | median | max | # calls |
| burnDsc | 398 | 12002 | 2675 | 32934 | 3 |
| calculateHealthFactor | 719 | 719 | 719 | 719 | 2 |
| depositCollateral | 435 | 40698 | 52032 | 52032 | 12 |
| depositCollateralAndMintDsc | 67752 | 128434 | 154560 | 154560 | 23 |
| getAccountCollateralValue | 41983 | 41983 | 41983 | 41983 | 1 |
| getAccountInformation | 8783 | 22983 | 8783 | 44283 | 5 |
| getAdditionalFeedPrecision | 292 | 292 | 292 | 292 | 2 |
| getCollateralBalanceOfUser | 805 | 805 | 805 | 805 | 1 |
| getCollateralTokenPriceFeed | 2617 | 2617 | 2617 | 2617 | 1 |
| getCollateralTokens | 7358 | 7358 | 7358 | 7358 | 1 |
| getDsc | 257 | 257 | 257 | 257 | 1 |
| getHealthFactor | 9267 | 9267 | 9267 | 9267 | 6 |
| getLiquidationBonus | 204 | 204 | 204 | 204 | 2 |
| getLiquidationThreshold | 293 | 293 | 293 | 293 | 1 |
| getMinHealthFactor | 270 | 270 | 270 | 270 | 1 |
| getPrecision | 314 | 314 | 314 | 314 | 2 |
| getTokenAmountFromUsd | 3678 | 6178 | 3678 | 18678 | 6 |
| getUsdValue | 3728 | 6870 | 3728 | 18728 | 7 |
| liquidate | 12413 | 67163 | 73505 | 96547 | 6 |
| mintDsc | 310 | 61616 | 64491 | 117172 | 4 |
| redeemCollateral | 413 | 15672 | 3468 | 43137 | 3 |
| redeemCollateralForDsc | 33104 | 40313 | 40313 | 47523 | 2 |

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.