Found in line 118 at 2023-07-foundry-defi-stablecoin/src/DSCEngine.sol:
for (uint256 i = 0; i < tokenAddresses.length; i++) {
Found in line 353 at 2023-07-foundry-defi-stablecoin/src/DSCEngine.sol:
for (uint256 i = 0; i < s_collateralTokens.length; i++) {
++i/i++ should be unchecked{++i}/unchecked{i++} when it is not possible for them to overflow, as is the case when used in for and while-loops. Moreover ++i costs less gas than i++, especially when its used in for-loops (--i/i-- too).
Found in line 118 at 2023-07-foundry-defi-stablecoin/src/DSCEngine.sol:
for (uint256 i = 0; i < tokenAddresses.length; i++) {
Found in line 353 at 2023-07-foundry-defi-stablecoin/src/DSCEngine.sol:
for (uint256 i = 0; i < s_collateralTokens.length; i++) {
In such cases, initializing the variables with default values would be unnecessary and can be considered a waste of gas. Additionally, initializing variables with default values can sometimes lead to unnecessary storage operations, which can increase gas costs. For example, if you have a large array of variables, initializing them all with default values can result in a lot of unnecessary storage writes, which can increase the gas costs of your contract.
Found in line 118 at 2023-07-foundry-defi-stablecoin/src/DSCEngine.sol:
for (uint256 i = 0; i < tokenAddresses.length; i++) {
Found in line 353 at 2023-07-foundry-defi-stablecoin/src/DSCEngine.sol:
for (uint256 i = 0; i < s_collateralTokens.length; i++) {
If not cached, the solidity compiler will always read the length of the array during each iteration. That is, if it is a storage array, this is an extra sload operation (100 additional extra gas for each iteration except for the first) and if it is a memory array, this is an extra mload operation (3 additional gas for each iteration except for the first).
Found in line 103 at 2023-07-foundry-defi-stablecoin/src/DSCEngine.sol:
if (s_priceFeeds[token] == address(0)) {
Found in line 58 at 2023-07-foundry-defi-stablecoin/src/DecentralizedStableCoin.sol:
if (_to == address(0)) {
Using assembly to check for the zero address can result in significant gas savings compared to using a Solidity expression, especially if the check is performed frequently or in a loop. However, it's important to note that using assembly can make the code less readable and harder to maintain, so it should be used judiciously and with caution.
Found in line 46 at 2023-07-foundry-defi-stablecoin/src/DecentralizedStableCoin.sol:
function burn(uint256 _amount) public override onlyOwner {
The following functions could be set external to save gas and improve code quality. External call cost is less expensive than of public functions.
Found in line 155 at 2023-07-foundry-defi-stablecoin/src/DSCEngine.sol:
s_collateralDeposited[msg.sender][tokenCollateralAddress] += amountCollateral;
Found in line 198 at 2023-07-foundry-defi-stablecoin/src/DSCEngine.sol:
s_DSCMinted[msg.sender] += amountDscToMint;
Found in line 356 at 2023-07-foundry-defi-stablecoin/src/DSCEngine.sol:
totalCollateralValueInUsd += getUsdValue(token, amount);
When you use the += operator on a state variable, the EVM has to perform three operations: load the current value of the state variable, add the new value to it, and then store the result back in the state variable. On the other hand, when you use the = operator and then add the values separately, the EVM only needs to perform two operations: load the current value of the state variable and add the new value to it. Better use
Found in line 77 and 78 at 2023-07-foundry-defi-stablecoin/src/DSCEngine.sol:
mapping(address token => address priceFeed) private s_priceFeeds; // tokenToPriceFeed
mapping(address user => mapping(address token => uint256 amount)) private s_collateralDeposited;
Saves a storage slot for the mapping. Depending on the circumstances and sizes of types, can avoid a Gsset (20000 gas) per mapping combined. Reads and subsequent writes can also be cheaper when a function requires both values and they both fit in the same storage slot.
Found in line 157 at 2023-07-foundry-defi-stablecoin/src/DSCEngine.sol:
bool success = IERC20(tokenCollateralAddress).transferFrom(msg.sender, address(this), amountCollateral);
Found in line 274 at 2023-07-foundry-defi-stablecoin/src/DSCEngine.sol:
bool success = i_dsc.transferFrom(dscFrom, address(this), amountDscToBurn);
Instead of using address(this), it is more gas-efficient to pre-calculate and use the hardcoded address. Foundry’s script.sol and solmate’s LibRlp.sol contracts can help achieve this.
Found in line 57 at 2023-07-foundry-defi-stablecoin/src/DecentralizedStableCoin.sol:
function mint(address _to, uint256 _amount) external onlyOwner returns (bool) {
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.
Found in line 72 at 2023-07-foundry-defi-stablecoin/src/DSCEngine.sol:
uint256 private constant LIQUIDATION_THRESHOLD = 50; // 200% overcollateralized
Found in line 75 at 2023-07-foundry-defi-stablecoin/src/DSCEngine.sol:
uint256 private constant LIQUIDATION_BONUS = 10; // this means a 10% bonus
Found in line 19 at 2023-07-foundry-defi-stablecoin/src/libraries/OracleLib.sol:
uint256 private constant TIMEOUT = 3 hours; // 3 * 60 * 60 = 10800 seconds
Due to how constant variables are implemented (replacements at compile-time), an expression assigned to a constant variable is recomputed each time that the variable is used, which wastes some gas.
Found in line 44 at 2023-07-foundry-defi-stablecoin/src/DecentralizedStableCoin.sol:
constructor() ERC20("DecentralizedStableCoin", "DSC") {}
The code should be refactored such that they no longer exist, or the block should do something useful, such as emitting an event or reverting. If the contract is meant to be extended, the contract should be abstract and the function signatures be added without any default implementation. If the block is an empty if-statement block to avoid doing subsequent checks in the else-if/else conditions, the else-if/else conditions should be nested under the negation of the if-statement, because they involve different classes of checks, which may lead to the introduction of errors when the code is later modified (if(x){}else if(y){...}else{...} => if(!x){if(y){...}else{...}}).
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.