Skip to content

Instantly share code, notes, and snippets.

@ChaseTheLight01
Created May 10, 2024 15:21
Show Gist options
  • Save ChaseTheLight01/66625ecfb9a2c07744a1c0c3050c560b to your computer and use it in GitHub Desktop.
Save ChaseTheLight01/66625ecfb9a2c07744a1c0c3050c560b to your computer and use it in GitHub Desktop.
LightChaserV3_Cantina_Aave_V3

LightChaser-V3

Generated for: Cantina : Aave V3

Generated on: 2024-05-10

Total findings: 67

Total Medium findings: 3

Total Low findings: 13

Total Gas findings: 25

Total NonCritical findings: 26

Summary for Medium findings

Number Details Instances
[Medium-1] isContract is not a reliable way to determine if a address is a EOA or contract 1
[Medium-2] Bps variable not checked that they are below 1e4 1
[Medium-3] Privileged functions can create points of failure 45

Summary for Low findings

Number Details Instances
[Low-1] ERC20 Permit try statement doesn't include backup approval 1
[Low-2] Use encodeCall rather than encodeWithSelector 5
[Low-3] Solidity version 0.8.20 won't work on all chains due to PUSH0 2
[Low-4] Low level calls in solidity versions preceding 0.8.14 can result in an optimiser bug 1
[Low-5] Upgradable contracts should have a __gap variable 2
[Low-6] Initializer function can be front run 2
[Low-7] The function decimals() is not part of the ERC20 standard 1
[Low-8] Revert on Transfer to the Zero Address 1
[Low-9] Prefer skip over revert model in iteration 2
[Low-10] Constructors missing validation 1
[Low-11] Consider a uptime feed on L2 deployments to prevent issues caused by downtime 3
[Low-12] No equate comparison checks between to and from address parameters 1
[Low-13] Events may be emitted out of order due to code not follow the best practice of check-effects-interaction 2

Summary for NonCritical findings

Number Details Instances
[NonCritical-1] Superfluous parameter can only be one value 2
[NonCritical-2] Unnecessary struct attribute prefix 4
[NonCritical-3] The call abi.encodeWithSelector is not type safe 4
[NonCritical-4] Library has public/external functions 7
[NonCritical-5] Floating pragma should be avoided 2
[NonCritical-6] Enum values should be used in place of constant array indexes 3
[NonCritical-7] Default bool values are manually set 1
[NonCritical-8] Default int values are manually set 8
[NonCritical-9] Contract lines should not be longer than 120 characters for readability 53
[NonCritical-10] Old Solidity version 2
[NonCritical-11] Functions within contracts are not ordered according to the solidity style guide 2
[NonCritical-12] All interfaces used within a project should be imported 4
[NonCritical-13] Unused state variables present 17
[NonCritical-14] Constants should be on the left side of the comparison 27
[NonCritical-15] Initialize functions do not emit an event 2
[NonCritical-16] Use of non-named numeric constants 3
[NonCritical-17] Long powers of ten should use scientific notation 1eX 1
[NonCritical-18] Redundant else statement 2
[NonCritical-19] Missing events in sensitive functions 40
[NonCritical-20] Non constant/immutable state variables are missing a setter post deployment 2
[NonCritical-21] Long numbers should include underscores to improve readability and prevent typos 9
[NonCritical-22] Use 'using' keyword when using specific imports rather than calling the specific import directly 355
[NonCritical-23] Try catch statement without human readable error 1
[NonCritical-24] Simplify complex require statements 4
[NonCritical-25] Constructors should emit an event 2
[NonCritical-26] Avoid arithmetic directly within array indices 1

Summary for Gas findings

Number Details Instances Gas
[Gas-1] The result of a function call should be cached rather than re-calling the function 1 200
[Gas-2] Usage of smaller uint/int types causes overhead 43 101695
[Gas-3] Use != 0 instead of > 0 2 12
[Gas-4] Default int values are manually reset 4 0.0
[Gas-5] Function calls within for loops 14 0.0
[Gas-6] Use assembly to check for the zero address 11 0.0
[Gas-7] Use assembly to emit events 58 127832
[Gas-8] Use assembly in place of abi.decode to extract calldata values more efficiently 1 0.0
[Gas-9] Using private rather than public for constants and immutables, saves gas 111 0.0
[Gas-10] Lack of unchecked in loops 18 21600
[Gas-11] Use assembly to validate msg.sender 4 0.0
[Gas-12] Simple checks for zero uint can be done using assembly to save gas 11 726
[Gas-13] Using nested if to save gas 18 1944
[Gas-14] Solidity versions 0.8.19 and above are more gas efficient 2 4000
[Gas-15] Variable declared within iteration 1 0.0
[Gas-16] Calling .length in a for loop wastes gas 14 19012
[Gas-17] Internal functions only used once can be inlined to save gas 57 97470
[Gas-18] Constructors can be marked as payable to save deployment gas 4 0.0
[Gas-19] Assigning to structs can be more efficient 2 2080
[Gas-20] Only emit event in setter function if the state variable was changed 16 0.0
[Gas-21] It is a waste of GAS to emit variable literals 2 48
[Gas-22] Use OZ Array.unsafeAccess() to avoid repeated array length checks 13 354900
[Gas-23] Use uint256(1)/uint256(2) instead of true/false to save gas for changes 1 34000
[Gas-24] Avoid emitting events in loops 10 37500
[Gas-25] Use constants instead of type(uint).max 3 0.0

[Medium-1] isContract is not a reliable way to determine if a address is a EOA or contract

Resolution

Using isContract to distinguish between Externally Owned Accounts (EOAs) and contracts in Ethereum is no longer reliable due to proxy contracts and contract creation during transaction execution. This method may inaccurately classify contracts as EOAs or vice versa, especially post-transaction. OpenZeppelin's Address library deprecated isContract recognizing these limitations. For security and accuracy, alternatives or additional checks should be used for distinguishing account types, aligning with current best practices and avoiding false assumptions based on outdated or unreliable methods.

Num of instances: 1

Findings

Click to show findings

['43']

43:     require(Address.isContract(params.asset), Errors.NOT_CONTRACT); // <= FOUND

[Medium-2] Bps variable not checked that they are below 1e4

Resolution

When handling basis points (bps) in smart contracts, it's essential to validate that their values do not exceed 10,000, as 1 bps equals 0.01%, and 10,000 bps equate to 100%. Failing to check that bps values stay within this range can lead to calculations that mistakenly exceed intended limits, causing issues such as excessive fees or incorrect interest rates. Implementing a simple validation check to ensure bps do not surpass 10,000 will safeguard against such errors, maintaining the integrity of financial computations and preventing potential overcharges or contract misbehaviors.

Num of instances: 1

Findings

Click to show findings

['116']

116:   function executeBackUnbacked(
117:     DataTypes.ReserveData storage reserve,
118:     address asset,
119:     uint256 amount,
120:     uint256 fee,
121:     uint256 protocolFeeBps // <= FOUND
122:   ) external returns (uint256) {
123:     DataTypes.ReserveCache memory reserveCache = reserve.cache();
124: 
125:     reserve.updateState(reserveCache);
126: 
127:     uint256 backingAmount = (amount < reserve.unbacked) ? amount : reserve.unbacked;
128: 
129:     uint256 feeToProtocol = fee.percentMul(protocolFeeBps); // <= FOUND
130:     uint256 feeToLP = fee - feeToProtocol;
131:     uint256 added = backingAmount + fee;
132: 
133:     reserveCache.nextLiquidityIndex = reserve.cumulateToLiquidityIndex(
134:       IERC20(reserveCache.aTokenAddress).totalSupply() +
135:         uint256(reserve.accruedToTreasury).rayMul(reserveCache.nextLiquidityIndex),
136:       feeToLP
137:     );
138: 
139:     reserve.accruedToTreasury += feeToProtocol.rayDiv(reserveCache.nextLiquidityIndex).toUint128();
140: 
141:     reserve.unbacked -= backingAmount.toUint128();
142:     reserve.updateInterestRatesAndVirtualBalance(reserveCache, asset, added, 0);
143: 
144:     IERC20(asset).safeTransferFrom(msg.sender, reserveCache.aTokenAddress, added);
145: 
146:     emit BackUnbacked(asset, msg.sender, backingAmount, fee);
147: 
148:     return backingAmount;
149:   }

[Medium-3] Privileged functions can create points of failure

Resolution

Ensure such accounts are protected and consider implementing multi sig to prevent a single point of failure

Num of instances: 45

Findings

Click to show findings

['785']

785:   function rescueTokens(
786:     address token,
787:     address to,
788:     uint256 amount
789:   ) external virtual override onlyPoolAdmin  // <= FOUND

['80']

80:   function initReserves(
81:     ConfiguratorInputTypes.InitReserveInput[] calldata input
82:   ) external override onlyAssetListingOrPoolAdmins  // <= FOUND

['97']

97:   function dropReserve(address asset) external override onlyPoolAdmin  // <= FOUND

['103']

103:   function updateAToken(
104:     ConfiguratorInputTypes.UpdateATokenInput calldata input
105:   ) external override onlyPoolAdmin  // <= FOUND

['110']

110:   function updateStableDebtToken(
111:     ConfiguratorInputTypes.UpdateDebtTokenInput calldata input
112:   ) external override onlyPoolAdmin  // <= FOUND

['117']

117:   function updateVariableDebtToken(
118:     ConfiguratorInputTypes.UpdateDebtTokenInput calldata input
119:   ) external override onlyPoolAdmin  // <= FOUND

['124']

124:   function setReserveBorrowing(address asset, bool enabled) external override onlyRiskOrPoolAdmins  // <= FOUND

['135']

135:   function configureReserveAsCollateral(
136:     address asset,
137:     uint256 ltv,
138:     uint256 liquidationThreshold,
139:     uint256 liquidationBonus
140:   ) external override onlyRiskOrPoolAdmins  // <= FOUND

['185']

185:   function setReserveStableRateBorrowing(
186:     address asset,
187:     bool enabled
188:   ) external override onlyRiskOrPoolAdmins  // <= FOUND

['199']

199:   function setReserveFlashLoaning(
200:     address asset,
201:     bool enabled
202:   ) external override onlyRiskOrPoolAdmins  // <= FOUND

['211']

211:   function setReserveActive(address asset, bool active) external override onlyPoolAdmin  // <= FOUND

['220']

220:   function setReserveFreeze(
221:     address asset,
222:     bool freeze
223:   ) external override onlyRiskOrPoolOrEmergencyAdmins  // <= FOUND

['248']

248:   function setBorrowableInIsolation(
249:     address asset,
250:     bool borrowable
251:   ) external override onlyRiskOrPoolAdmins  // <= FOUND

['259']

259:   function setReservePause(
260:     address asset,
261:     bool paused,
262:     uint40 gracePeriod
263:   ) public override onlyEmergencyOrPoolAdmin  // <= FOUND

['279']

279:   function setReservePause(address asset, bool paused) external override onlyEmergencyOrPoolAdmin  // <= FOUND

['284']

284:   function setReserveFactor(
285:     address asset,
286:     uint256 newReserveFactor
287:   ) external override onlyRiskOrPoolAdmins  // <= FOUND

['302']

302:   function setDebtCeiling(
303:     address asset,
304:     uint256 newDebtCeiling
305:   ) external override onlyRiskOrPoolAdmins  // <= FOUND

['323']

323:   function setSiloedBorrowing(
324:     address asset,
325:     bool newSiloed
326:   ) external override onlyRiskOrPoolAdmins  // <= FOUND

['342']

342:   function setBorrowCap(
343:     address asset,
344:     uint256 newBorrowCap
345:   ) external override onlyRiskOrPoolAdmins  // <= FOUND

['354']

354:   function setSupplyCap(
355:     address asset,
356:     uint256 newSupplyCap
357:   ) external override onlyRiskOrPoolAdmins  // <= FOUND

['366']

366:   function setLiquidationProtocolFee(
367:     address asset,
368:     uint256 newFee
369:   ) external override onlyRiskOrPoolAdmins  // <= FOUND

['379']

379:   function setEModeCategory(
380:     uint8 categoryId,
381:     uint16 ltv,
382:     uint16 liquidationThreshold,
383:     uint16 liquidationBonus,
384:     address oracle,
385:     string calldata label
386:   ) external override onlyRiskOrPoolAdmins  // <= FOUND

['433']

433:   function setAssetEModeCategory(
434:     address asset,
435:     uint8 newCategoryId
436:   ) external override onlyRiskOrPoolAdmins  // <= FOUND

['453']

453:   function setUnbackedMintCap(
454:     address asset,
455:     uint256 newUnbackedMintCap
456:   ) external override onlyRiskOrPoolAdmins  // <= FOUND

['465']

465:   function setReserveInterestRateData(
466:     address asset,
467:     bytes calldata rateData
468:   ) external onlyRiskOrPoolAdmins  // <= FOUND

['474']

474:   function setReserveInterestRateStrategyAddress(
475:     address asset,
476:     address rateStrategyAddress,
477:     bytes calldata rateData
478:   ) external override onlyRiskOrPoolAdmins  // <= FOUND

['484']

484:   function setPoolPause(bool paused, uint40 gracePeriod) public override onlyEmergencyOrPoolAdmin  // <= FOUND

['495']

495:   function setPoolPause(bool paused) external override onlyEmergencyOrPoolAdmin  // <= FOUND

['500']

500:   function updateBridgeProtocolFee(uint256 newBridgeProtocolFee) external override onlyPoolAdmin  // <= FOUND

['511']

511:   function updateFlashloanPremiumTotal(
512:     uint128 newFlashloanPremiumTotal
513:   ) external override onlyPoolAdmin  // <= FOUND

['524']

524:   function updateFlashloanPremiumToProtocol(
525:     uint128 newFlashloanPremiumToProtocol
526:   ) external override onlyPoolAdmin  // <= FOUND

['758']

758:   function validateAutomaticUseAsCollateral(
759:     mapping(address => DataTypes.ReserveData) storage reservesData,
760:     mapping(uint256 => address) storage reservesList,
761:     DataTypes.UserConfigurationMap storage userConfig,
762:     DataTypes.ReserveConfigurationMap memory reserveConfig,
763:     address aTokenAddress
764:   ) internal view returns (bool) {
765:     if (reserveConfig.getDebtCeiling() != 0) {
766:       
767:       IPoolAddressesProvider addressesProvider = IncentivizedERC20(aTokenAddress)
768:         .POOL()
769:         .ADDRESSES_PROVIDER();
770:       if (
771:         !IAccessControl(addressesProvider.getACLManager()).hasRole( // <= FOUND
772:           ISOLATED_COLLATERAL_SUPPLIER_ROLE,
773:           msg.sender
774:         )
775:       ) return false;
776:     }
777:     return validateUseAsCollateral(reservesData, reservesList, userConfig, reserveConfig);
778:   }

['57']

57:   function setInterestRateParams(
58:     address reserve,
59:     bytes calldata rateData
60:   ) external onlyPoolConfigurator  // <= FOUND

['65']

65:   function setInterestRateParams(
66:     address reserve,
67:     InterestRateData calldata rateData
68:   ) external onlyPoolConfigurator  // <= FOUND

['641']

641:   function initReserve(
642:     address asset,
643:     address aTokenAddress,
644:     address stableDebtAddress,
645:     address variableDebtAddress,
646:     address interestRateStrategyAddress
647:   ) external virtual override onlyPoolConfigurator  // <= FOUND

['668']

668:   function dropReserve(address asset) external virtual override onlyPoolConfigurator  // <= FOUND

['673']

673:   function setReserveInterestRateStrategyAddress(
674:     address asset,
675:     address rateStrategyAddress
676:   ) external virtual override onlyPoolConfigurator  // <= FOUND

['684']

684:   function syncIndexesState(address asset) external virtual override onlyPoolConfigurator  // <= FOUND

['692']

692:   function syncRatesState(address asset) external virtual override onlyPoolConfigurator  // <= FOUND

['700']

700:   function setConfiguration(
701:     address asset,
702:     DataTypes.ReserveConfigurationMap calldata configuration
703:   ) external virtual override onlyPoolConfigurator  // <= FOUND

['710']

710:   function updateBridgeProtocolFee(
711:     uint256 protocolFee
712:   ) external virtual override onlyPoolConfigurator  // <= FOUND

['717']

717:   function updateFlashloanPremiums(
718:     uint128 flashLoanPremiumTotal,
719:     uint128 flashLoanPremiumToProtocol
720:   ) external virtual override onlyPoolConfigurator  // <= FOUND

['726']

726:   function configureEModeCategory(
727:     uint8 id,
728:     DataTypes.EModeCategory memory category
729:   ) external virtual override onlyPoolConfigurator  // <= FOUND

['764']

764:   function resetIsolationModeTotalDebt(
765:     address asset
766:   ) external virtual override onlyPoolConfigurator  // <= FOUND

['776']

776:   function setLiquidationGracePeriod(
777:     address asset,
778:     uint40 until
779:   ) external virtual override onlyPoolConfigurator  // <= FOUND

[Low-1] ERC20 Permit try statement doesn't include backup approval

Resolution

The ERC20 Permit feature, as detailed in EIP-2612, is vulnerable to frontrunning because transactions can be observed in the mempool, allowing malicious actors to duplicate and preempt the transaction. This can be particularly harmful when the permit() is part of a larger contract call sequence, leading to Denial of Service (DOS) by making the subsequent intended contract functionality fail. A workaround includes attempting the permit() call and, if it fails due to frontrunning, continuing with the intended logic if the allowance check passes. However in the instances found below, there is no approval taking place if the permit attempt fails. Source trust-security

Num of instances: 1

Findings

Click to show findings

['165']

165:     try
166:       IERC20WithPermit(asset).permit( // <= FOUND
167:         msg.sender,
168:         address(this),
169:         amount,
170:         deadline,
171:         permitV,
172:         permitR,
173:         permitS
174:       )
175:     {} catch {}

[Low-2] Use encodeCall rather than encodeWithSelector

Resolution

Unlike encodeCall, encodeWithSelector does not perform checks to verify the params passed are compatible with a call, as such it is safer to use encodeCall to prevent potential issues.

Num of instances: 5

Findings

Click to show findings

['55']

55:     address aTokenProxyAddress = _initTokenWithProxy(
56:       input.aTokenImpl,
57:       abi.encodeWithSelector( // <= FOUND
58:         IInitializableAToken.initialize.selector,
59:         pool,
60:         input.treasury,
61:         input.underlyingAsset,
62:         input.incentivesController,
63:         input.underlyingAssetDecimals,
64:         input.aTokenName,
65:         input.aTokenSymbol,
66:         input.params
67:       )
68:     );

['70']

70:     address stableDebtTokenProxyAddress = _initTokenWithProxy(
71:       input.stableDebtTokenImpl,
72:       abi.encodeWithSelector( // <= FOUND
73:         IInitializableDebtToken.initialize.selector,
74:         pool,
75:         input.underlyingAsset,
76:         input.incentivesController,
77:         input.underlyingAssetDecimals,
78:         input.stableDebtTokenName,
79:         input.stableDebtTokenSymbol,
80:         input.params
81:       )
82:     );

['84']

84:     address variableDebtTokenProxyAddress = _initTokenWithProxy(
85:       input.variableDebtTokenImpl,
86:       abi.encodeWithSelector( // <= FOUND
87:         IInitializableDebtToken.initialize.selector,
88:         pool,
89:         input.underlyingAsset,
90:         input.incentivesController,
91:         input.underlyingAssetDecimals,
92:         input.variableDebtTokenName,
93:         input.variableDebtTokenSymbol,
94:         input.params
95:       )
96:     );

['145']

145:     bytes memory encodedCall = abi.encodeWithSelector( // <= FOUND
146:       IInitializableAToken.initialize.selector,
147:       cachedPool,
148:       input.treasury,
149:       input.asset,
150:       input.incentivesController,
151:       decimals,
152:       input.name,
153:       input.symbol,
154:       input.params
155:     );

['176']

176:     bytes memory encodedCall = abi.encodeWithSelector( // <= FOUND
177:       IInitializableDebtToken.initialize.selector,
178:       cachedPool,
179:       input.asset,
180:       input.incentivesController,
181:       decimals,
182:       input.name,
183:       input.symbol,
184:       input.params
185:     );

[Low-3] Solidity version 0.8.20 won't work on all chains due to PUSH0

Resolution

Solidity version 0.8.20 uses the new Shanghai EVM which introduces the PUSH0 opcode, this may not be implemented on all chains and L2 thus reducing the portability and compatability of the code. Consider using a earlier solidity version.

Num of instances: 2

Findings

Click to show findings

['2']

2: pragma solidity ^0.8.10; // <= FOUND

['2']

2: pragma solidity ^0.8.0; // <= FOUND

[Low-4] Low level calls in solidity versions preceding 0.8.14 can result in an optimiser bug

Resolution

In Solidity versions 0.8.13 and 0.8.14, a known optimizer bug presents potential risks when a variable is used in a separate assembly block from the one in which it was stored. Specifically, the 'mstore' operation could be optimized out due to this bug, leading to the use of uninitialized memory. Although the current code does not exhibit this risky pattern of execution, it does utilize 'mstore' within assembly blocks, which introduces a vulnerability risk for future code modifications. As a preventative measure, it is advisable to avoid the usage of the afflicted Solidity versions, 0.8.13 and 0.8.14. Instead, consider utilizing a version that is not impacted by this optimizer bug to prevent potential memory initialization issues in your smart contract.

Num of instances: 1

Findings

Click to show findings

['570']

570:     assembly { // <= FOUND
571:       mstore(reservesList, sub(reservesListCount, droppedReservesCount))
572:     }

[Low-5] Upgradable contracts should have a __gap variable

Resolution

This is to ensure the team can add new state variables without compromising compatability.

Num of instances: 2

Findings

Click to show findings

['39']

39: abstract contract Pool is VersionedInitializable, PoolStorage, IPool 

['25']

25: abstract contract PoolConfigurator is VersionedInitializable, IPoolConfigurator 

[Low-6] Initializer function can be front run

Resolution

In Solidity contract deployment, not making the initialize() function call atomic with the contract creation can leave a vulnerability window. A malicious actor could exploit this time gap and call initialize() before the intended initialization. This action could disrupt the contract's setup, potentially necessitating a full contract re-deployment to ensure proper initialization. To mitigate such risks, it's advised to use a factory contract. This factory contract can be programmed to deploy and initialize a new contract in a single atomic transaction, closing the window of vulnerability and ensuring correct and secure contract initialization.

Num of instances: 2

Findings

Click to show findings

['14']

14:   function initialize(IPoolAddressesProvider provider) public virtual override initializer  // <= FOUND

['20']

20:   function initialize(IPoolAddressesProvider provider) external virtual override initializer  // <= FOUND

[Low-7] The function decimals() is not part of the ERC20 standard

Resolution

The decimals() function in an ERC20 token contract is used to specify how many decimal places the token can be divided into. However, it should be used with caution because not all ERC20 token contracts implement decimals(), and the function isn't required by the ERC20 standard. Calling decimals() on a contract that doesn't implement it will result in a runtime error. Moreover, even when implemented, the returned value can be manipulated or artificially set, which may cause unexpected behavior. Therefore, always verify the decimal count independently if precision is crucial for your contract logic. When interacting with other ERC20 tokens, consider implementing safeguards or checks to handle potential errors from calling decimals().

Num of instances: 1

Findings

Click to show findings

['85']

85:       require(IERC20Detailed(input[i].underlyingAsset).decimals() > 5, Errors.INVALID_DECIMALS); // <= FOUND

[Low-8] Revert on Transfer to the Zero Address

Resolution

Many ERC-20 and ERC-721 token contracts implement a safeguard that reverts transactions which attempt to transfer tokens to the zero address. This is because such transfers are often the result of programming errors. The OpenZeppelin library, a popular choice for implementing these standards, includes this safeguard. For token contract developers who want to avoid unintentional transfers to the zero address, it's good practice to include a condition that reverts the transaction if the recipient's address is the zero address.

Num of instances: 1

Findings

Click to show findings

['75']

75:   function executeRescueTokens(address token, address to, uint256 amount) external { // <= FOUND
76:     IERC20(token).safeTransfer(to, amount); // <= FOUND
77:   }

[Low-9] Prefer skip over revert model in iteration

Resolution

It is preferable to skip operations on an array index when a condition is not met rather than reverting the whole transaction as reverting can introduce the possiblity of malicous actors purposefully introducing array objects which fail conditional checks within for/while loops so group operations fail. As such it is recommended to simply skip such array indices over reverting unless there is a valid security or logic reason behind not doing so.

Num of instances: 2

Findings

Click to show findings

['84']

84:    for (uint256 i = 0; i < input.length; i++) { // <= FOUND
85:       require(IERC20Detailed(input[i].underlyingAsset).decimals() > 5, Errors.INVALID_DECIMALS); // <= FOUND
86: 
87:       ConfiguratorLogic.executeInitReserve(cachedPool, input[i]);
88:       emit ReserveInterestRateDataChanged(
89:         input[i].underlyingAsset,
90:         input[i].interestRateStrategyAddress,
91:         input[i].interestRateData
92:       );
93:     }

['84']

84:     for (uint256 i = 0; i < input.length; i++) { // <= FOUND
85:       require(IERC20Detailed(input[i].underlyingAsset).decimals() > 5, Errors.INVALID_DECIMALS); // <= FOUND
86: 
87:       ConfiguratorLogic.executeInitReserve(cachedPool, input[i]);
88:       emit ReserveInterestRateDataChanged(
89:         input[i].underlyingAsset,
90:         input[i].interestRateStrategyAddress,
91:         input[i].interestRateData
92:       );
93:     }

[Low-10] Constructors missing validation

Resolution

In Solidity, when values are being assigned in constructors to unsigned or integer variables, it's crucial to ensure the provided values adhere to the protocol's specific operational boundaries as laid out in the project specifications and documentation. If the constructors lack appropriate validation checks, there's a risk of setting state variables with values that could cause unexpected and potentially detrimental behavior within the contract's operations, violating the intended logic of the protocol. This can compromise the contract's security and impact the maintainability and reliability of the system. In order to avoid such issues, it is recommended to incorporate rigorous validation checks in constructors. These checks should align with the project's defined rules and constraints, making use of Solidity's built-in require function to enforce these conditions. If the validation checks fail, the require function will cause the transaction to revert, ensuring the integrity and adherence to the protocol's expected behavior.

Num of instances: 1

Findings

Click to show findings

['93']

93:   constructor(IPoolAddressesProvider provider) {
94:     ADDRESSES_PROVIDER = provider; // <= FOUND
95:   }

[Low-11] Consider a uptime feed on L2 deployments to prevent issues caused by downtime

Resolution

In L2 deployments, incorporating an uptime feed is crucial to mitigate issues arising from sequencer downtime. Downtime can disrupt services, leading to transaction failures or incorrect data readings, affecting overall system reliability. By integrating an uptime feed, you gain insight into the operational status of the L2 network, enabling proactive measures like halting sensitive operations or alerting users. This approach ensures that your contract behaves predictably and securely during network outages, enhancing the robustness and reliability of your decentralized application, which is especially important in mission-critical or high-stakes environments.

Num of instances: 3

Findings

Click to show findings

['15']

15: abstract contract L2Pool is Pool, IL2Pool  // <= FOUND

['39']

39: abstract contract Pool is VersionedInitializable, PoolStorage, IPool  // <= FOUND

['25']

25: abstract contract PoolConfigurator is VersionedInitializable, IPoolConfigurator  // <= FOUND

[Low-12] No equate comparison checks between to and from address parameters

Resolution

The function lacks a standard check: it does not validate if the 'to' and 'from' addresses are identical. This omission can lead to unintended outcomes if the same address is used in both parameters. To rectify this, we recommend implementing a comparison check at the beginning of the function. In the context of Solidity, the command require(to != from, "To and From addresses can't be the same"); could be utilized. This addition will generate an error if the 'to' and 'from' addresses are the same, thereby fortifying the function's robustness and security.

Num of instances: 1

Findings

Click to show findings

['612']

612:   function finalizeTransfer(
613:     address asset,
614:     address from, // <= FOUND
615:     address to, // <= FOUND
616:     uint256 amount,
617:     uint256 balanceFromBefore,
618:     uint256 balanceToBefore
619:   ) external virtual override {
620:     require(msg.sender == _reserves[asset].aTokenAddress, Errors.CALLER_NOT_ATOKEN);
621:     SupplyLogic.executeFinalizeTransfer(
622:       _reserves,
623:       _reservesList,
624:       _eModeCategories,
625:       _usersConfig,
626:       DataTypes.FinalizeTransferParams({
627:         asset: asset,
628:         from: from,
629:         to: to,
630:         amount: amount,
631:         balanceFromBefore: balanceFromBefore,
632:         balanceToBefore: balanceToBefore,
633:         reservesCount: _reservesCount,
634:         oracle: ADDRESSES_PROVIDER.getPriceOracle(),
635:         fromEModeCategory: _usersEModeCategory[from]
636:       })
637:     );
638:   }

[Low-13] Events may be emitted out of order due to code not follow the best practice of check-effects-interaction

Resolution

The "check-effects-interaction" pattern also impacts event ordering. When a contract doesn't adhere to this pattern, events might be emitted in a sequence that doesn't reflect the actual logical flow of operations. This can cause confusion during event tracking, potentially leading to erroneous off-chain interpretations. To rectify this, always ensure that checks are performed first, state modifications come next, and interactions with external contracts or addresses are done last. This will ensure events are emitted in a logical, consistent manner, providing a clear and accurate chronological record of on-chain actions for off-chain systems and observers.

Num of instances: 2

Findings

Click to show findings

['116']

116:   function executeBackUnbacked(
117:     DataTypes.ReserveData storage reserve,
118:     address asset,
119:     uint256 amount,
120:     uint256 fee,
121:     uint256 protocolFeeBps
122:   ) external returns (uint256) {
123:     DataTypes.ReserveCache memory reserveCache = reserve.cache();
124: 
125:     reserve.updateState(reserveCache);
126: 
127:     uint256 backingAmount = (amount < reserve.unbacked) ? amount : reserve.unbacked;
128: 
129:     uint256 feeToProtocol = fee.percentMul(protocolFeeBps);
130:     uint256 feeToLP = fee - feeToProtocol;
131:     uint256 added = backingAmount + fee;
132: 
133:     reserveCache.nextLiquidityIndex = reserve.cumulateToLiquidityIndex(
134:       IERC20(reserveCache.aTokenAddress).totalSupply() +
135:         uint256(reserve.accruedToTreasury).rayMul(reserveCache.nextLiquidityIndex),
136:       feeToLP
137:     );
138: 
139:     reserve.accruedToTreasury += feeToProtocol.rayDiv(reserveCache.nextLiquidityIndex).toUint128();
140: 
141:     reserve.unbacked -= backingAmount.toUint128();
142:     reserve.updateInterestRatesAndVirtualBalance(reserveCache, asset, added, 0);
143: 
144:     IERC20(asset).safeTransferFrom(msg.sender, reserveCache.aTokenAddress, added); // <= FOUND
145: 
146:     emit BackUnbacked(asset, msg.sender, backingAmount, fee); // <= FOUND
147: 
148:     return backingAmount;
149:   }

['549']

549:   function _updateInterestRateStrategy(
550:     address asset,
551:     DataTypes.ReserveDataLegacy memory reserve,
552:     address newRateStrategyAddress,
553:     bytes calldata rateData
554:   ) internal {
555:     address oldRateStrategyAddress = reserve.interestRateStrategyAddress;
556: 
557:     _pool.syncIndexesState(asset);
558: 
559:     IDefaultInterestRateStrategyV2(newRateStrategyAddress).setInterestRateParams(asset, rateData); // <= FOUND
560:     emit ReserveInterestRateDataChanged(asset, newRateStrategyAddress, rateData); // <= FOUND
561: 
562:     if (oldRateStrategyAddress != newRateStrategyAddress) {
563:       _pool.setReserveInterestRateStrategyAddress(asset, newRateStrategyAddress);
564:       emit ReserveInterestRateStrategyChanged( // <= FOUND
565:         asset,
566:         oldRateStrategyAddress,
567:         newRateStrategyAddress
568:       );
569:     }
570: 
571:     _pool.syncRatesState(asset);
572:   }

[NonCritical-1] Superfluous parameter can only be one value

Resolution

Using redundant parameters in smart contracts can lead to unnecessary complexity and potential vulnerabilities. When a function parameter is always constrained to a specific value due to an if or require statement, it renders the parameter superfluous. Including such parameters can be misleading to developers or users, suggesting a flexibility that doesn't exist in reality. Additionally, unnecessary parameters increase the gas cost for transactions. Resolution: Analyze the contract to identify parameters that are rendered static by conditional checks. Remove these parameters from the function signature and update the function logic accordingly. This simplifies the code, reduces gas costs, and enhances clarity and security.

Num of instances: 2

Findings

Click to show findings

['20']

20:   function initialize(IPoolAddressesProvider provider) external virtual override initializer { // <= FOUND
21:     require(provider == ADDRESSES_PROVIDER, Errors.INVALID_ADDRESSES_PROVIDER); // <= FOUND
22:     _maxStableRateBorrowSizePercent = 0.25e4;
23:   }

['140']

140:   function init(
141:     DataTypes.ReserveData storage reserve,
142:     address aTokenAddress,
143:     address stableDebtTokenAddress,
144:     address variableDebtTokenAddress,
145:     address interestRateStrategyAddress
146:   ) internal {
147:     require(reserve.aTokenAddress == address(0), Errors.RESERVE_ALREADY_INITIALIZED); // <= FOUND
148: 
149:     reserve.liquidityIndex = uint128(WadRayMath.RAY);
150:     reserve.variableBorrowIndex = uint128(WadRayMath.RAY);
151:     reserve.aTokenAddress = aTokenAddress;
152:     reserve.stableDebtTokenAddress = stableDebtTokenAddress;
153:     reserve.variableDebtTokenAddress = variableDebtTokenAddress;
154:     reserve.interestRateStrategyAddress = interestRateStrategyAddress;
155:   }

[NonCritical-2] Unnecessary struct attribute prefix

Resolution

In struct definitions, using redundant prefixes for attributes is unnecessary. For instance, in a struct named Employee, attributes like employeeName, employeeID, and employeeEmail can be simplified to name, ID, and email respectively, since they are already inherently associated with Employee. By removing these repetitive prefixes, the code becomes more concise and easier to read, maintaining its contextual clarity.

Num of instances: 4

Findings

Click to show findings

['130']

130:   struct ReserveCache { // <= FOUND
131:     uint256 currScaledVariableDebt;
132:     uint256 nextScaledVariableDebt;
133:     uint256 currPrincipalStableDebt;
134:     uint256 currAvgStableBorrowRate;
135:     uint256 currTotalStableDebt;
136:     uint256 nextAvgStableBorrowRate;
137:     uint256 nextTotalStableDebt;
138:     uint256 currLiquidityIndex;
139:     uint256 nextLiquidityIndex;
140:     uint256 currVariableBorrowIndex;
141:     uint256 nextVariableBorrowIndex;
142:     uint256 currLiquidityRate;
143:     uint256 currVariableBorrowRate;
144:     uint256 reserveFactor; // <= FOUND
145:     ReserveConfigurationMap reserveConfiguration; // <= FOUND
146:     address aTokenAddress;
147:     address stableDebtTokenAddress;
148:     address variableDebtTokenAddress;
149:     uint40 reserveLastUpdateTimestamp; // <= FOUND
150:     uint40 stableDebtLastUpdateTimestamp;
151:   }

['250']

250:   struct FlashLoanRepaymentParams { // <= FOUND
251:     uint256 amount;
252:     uint256 totalPremium;
253:     uint256 flashLoanPremiumToProtocol; // <= FOUND
254:     address asset;
255:     address receiverAddress;
256:     uint16 referralCode;
257:   }

['48']

48:   struct FlashLoanLocalVars { // <= FOUND
49:     IFlashLoanReceiver receiver;
50:     uint256 i;
51:     address currentAsset;
52:     uint256 currentAmount;
53:     uint256[] totalPremiums;
54:     uint256 flashloanPremiumTotal; // <= FOUND
55:     uint256 flashloanPremiumToProtocol; // <= FOUND
56:   }

['70']

70:   struct LiquidationCallLocalVars { // <= FOUND
71:     uint256 userCollateralBalance;
72:     uint256 userVariableDebt;
73:     uint256 userTotalDebt;
74:     uint256 actualDebtToLiquidate;
75:     uint256 actualCollateralToLiquidate;
76:     uint256 liquidationBonus; // <= FOUND
77:     uint256 healthFactor;
78:     uint256 liquidationProtocolFeeAmount; // <= FOUND
79:     address collateralPriceSource;
80:     address debtPriceSource;
81:     IAToken collateralAToken;
82:     DataTypes.ReserveCache debtReserveCache;
83:   }

[NonCritical-3] The call abi.encodeWithSelector is not type safe

Resolution

In Solidity, abi.encodeWithSelector is a function used for encoding data along with a function selector, but it is not type-safe. This means it does not enforce type checking at compile time, potentially leading to errors if arguments do not match the expected types. Starting from version 0.8.13, Solidity introduced abi.encodeCall, which offers a safer alternative. abi.encodeCall ensures type safety by performing a full type check, aligning the types of the arguments with the function signature. This reduces the risk of bugs caused by typographical errors or mismatched types. Using abi.encodeCall enhances the reliability and security of the code by ensuring that the encoded data strictly conforms to the specified types, making it a preferable choice in Solidity versions 0.8.13 and above.

Num of instances: 4

Findings

Click to show findings

['51']

51:   function executeInitReserve(
52:     IPool pool,
53:     ConfiguratorInputTypes.InitReserveInput calldata input
54:   ) external {
55:     address aTokenProxyAddress = _initTokenWithProxy(
56:       input.aTokenImpl,
57:       abi.encodeWithSelector( // <= FOUND
58:         IInitializableAToken.initialize.selector,
59:         pool,
60:         input.treasury,
61:         input.underlyingAsset,
62:         input.incentivesController,
63:         input.underlyingAssetDecimals,
64:         input.aTokenName,
65:         input.aTokenSymbol,
66:         input.params
67:       )
68:     );
69: 
70:     address stableDebtTokenProxyAddress = _initTokenWithProxy(
71:       input.stableDebtTokenImpl,
72:       abi.encodeWithSelector( // <= FOUND
73:         IInitializableDebtToken.initialize.selector,
74:         pool,
75:         input.underlyingAsset,
76:         input.incentivesController,
77:         input.underlyingAssetDecimals,
78:         input.stableDebtTokenName,
79:         input.stableDebtTokenSymbol,
80:         input.params
81:       )
82:     );
83: 
84:     address variableDebtTokenProxyAddress = _initTokenWithProxy(
85:       input.variableDebtTokenImpl,
86:       abi.encodeWithSelector( // <= FOUND
87:         IInitializableDebtToken.initialize.selector,
88:         pool,
89:         input.underlyingAsset,
90:         input.incentivesController,
91:         input.underlyingAssetDecimals,
92:         input.variableDebtTokenName,
93:         input.variableDebtTokenSymbol,
94:         input.params
95:       )
96:     );
97: 
98:     pool.initReserve(
99:       input.underlyingAsset,
100:       aTokenProxyAddress,
101:       stableDebtTokenProxyAddress,
102:       variableDebtTokenProxyAddress,
103:       input.interestRateStrategyAddress
104:     );
105: 
106:     DataTypes.ReserveConfigurationMap memory currentConfig = DataTypes.ReserveConfigurationMap(0);
107: 
108:     currentConfig.setDecimals(input.underlyingAssetDecimals);
109: 
110:     currentConfig.setActive(true);
111:     currentConfig.setPaused(false);
112:     currentConfig.setFrozen(false);
113:     currentConfig.setVirtualAccActive(input.useVirtualBalance);
114: 
115:     pool.setConfiguration(input.underlyingAsset, currentConfig);
116: 
117:     IReserveInterestRateStrategy(input.interestRateStrategyAddress).setInterestRateParams(
118:       input.underlyingAsset,
119:       input.interestRateData
120:     );
121: 
122:     emit ReserveInitialized(
123:       input.underlyingAsset,
124:       aTokenProxyAddress,
125:       stableDebtTokenProxyAddress,
126:       variableDebtTokenProxyAddress,
127:       input.interestRateStrategyAddress
128:     );
129:   }

['137']

137:   function executeUpdateAToken(
138:     IPool cachedPool,
139:     ConfiguratorInputTypes.UpdateATokenInput calldata input
140:   ) external {
141:     DataTypes.ReserveDataLegacy memory reserveData = cachedPool.getReserveData(input.asset);
142: 
143:     (, , , uint256 decimals, , ) = cachedPool.getConfiguration(input.asset).getParams();
144: 
145:     bytes memory encodedCall = abi.encodeWithSelector( // <= FOUND
146:       IInitializableAToken.initialize.selector,
147:       cachedPool,
148:       input.treasury,
149:       input.asset,
150:       input.incentivesController,
151:       decimals,
152:       input.name,
153:       input.symbol,
154:       input.params
155:     );
156: 
157:     _upgradeTokenImplementation(reserveData.aTokenAddress, input.implementation, encodedCall);
158: 
159:     emit ATokenUpgraded(input.asset, reserveData.aTokenAddress, input.implementation);
160:   }

['168']

168:   function executeUpdateStableDebtToken(
169:     IPool cachedPool,
170:     ConfiguratorInputTypes.UpdateDebtTokenInput calldata input
171:   ) external {
172:     DataTypes.ReserveDataLegacy memory reserveData = cachedPool.getReserveData(input.asset);
173: 
174:     (, , , uint256 decimals, , ) = cachedPool.getConfiguration(input.asset).getParams();
175: 
176:     bytes memory encodedCall = abi.encodeWithSelector( // <= FOUND
177:       IInitializableDebtToken.initialize.selector,
178:       cachedPool,
179:       input.asset,
180:       input.incentivesController,
181:       decimals,
182:       input.name,
183:       input.symbol,
184:       input.params
185:     );
186: 
187:     _upgradeTokenImplementation(
188:       reserveData.stableDebtTokenAddress,
189:       input.implementation,
190:       encodedCall
191:     );
192: 
193:     emit StableDebtTokenUpgraded(
194:       input.asset,
195:       reserveData.stableDebtTokenAddress,
196:       input.implementation
197:     );
198:   }

['206']

206:   function executeUpdateVariableDebtToken(
207:     IPool cachedPool,
208:     ConfiguratorInputTypes.UpdateDebtTokenInput calldata input
209:   ) external {
210:     DataTypes.ReserveDataLegacy memory reserveData = cachedPool.getReserveData(input.asset);
211: 
212:     (, , , uint256 decimals, , ) = cachedPool.getConfiguration(input.asset).getParams();
213: 
214:     bytes memory encodedCall = abi.encodeWithSelector( // <= FOUND
215:       IInitializableDebtToken.initialize.selector,
216:       cachedPool,
217:       input.asset,
218:       input.incentivesController,
219:       decimals,
220:       input.name,
221:       input.symbol,
222:       input.params
223:     );
224: 
225:     _upgradeTokenImplementation(
226:       reserveData.variableDebtTokenAddress,
227:       input.implementation,
228:       encodedCall
229:     );
230: 
231:     emit VariableDebtTokenUpgraded(
232:       input.asset,
233:       reserveData.variableDebtTokenAddress,
234:       input.implementation
235:     );
236:   }

[NonCritical-4] Library has public/external functions

Resolution

Libraries in Solidity are meant to be static collections of functions. They are deployed once and their code is reused by contracts through DELEGATECALL, which executes the library's code in the context of the calling contract. Public or external functions in libraries can be misleading because libraries are not supposed to maintain state or have external interactions in the way contracts do. Designing libraries with these kinds of functions goes against their intended purpose and can lead to confusion or misuse. For state management or external interactions, using contracts instead of libraries is more appropriate. Libraries should focus on utility functions that can operate on the data passed to them without side effects, enhancing code reuse and gas efficiency.

Num of instances: 7

Findings

Click to show findings

['23']

23: library BorrowLogic { // <= FOUND
24:   using 

['17']

17: library BridgeLogic { // <= FOUND
18:   using 

['18']

18: library ConfiguratorLogic { // <= FOUND
19:   

['27']

27: library FlashLoanLogic { // <= FOUND
28:   usi

['27']

27: library LiquidationLogic { // <= FOUND
28:   u

['21']

21: library PoolLogic { // <= FOUND
22:   using GP

['21']

21: library SupplyLogic { // <= FOUND
22:   using 

[NonCritical-5] Floating pragma should be avoided

Num of instances: 2

Findings

Click to show findings

['2']

2: pragma solidity ^0.8.10; // <= FOUND

['2']

2: pragma solidity ^0.8.0; // <= FOUND

[NonCritical-6] Enum values should be used in place of constant array indexes

Resolution

Create a commented enum value to use in place of constant array indexes, this makes the code far easier to understand

Num of instances: 3

Findings

Click to show findings

['678']

678:     require(_reserves[asset].id != 0 || _reservesList[0] == asset, Errors.ASSET_NOT_LISTED); // <= FOUND

['51']

51:     bool reserveAlreadyAdded = reservesData[params.asset].id != 0 ||
52:       reservesList[0] == params.asset; // <= FOUND

['664']

664:     require(reserve.id != 0 || reservesList[0] == asset, Errors.ASSET_NOT_LISTED); // <= FOUND

[NonCritical-7] Default bool values are manually set

Resolution

In instances where a new variable is defined, there is no need to set it to it's default value.

Num of instances: 1

Findings

Click to show findings

['109']

109:     bool isFirstBorrowing = false; // <= FOUND

[NonCritical-8] Default int values are manually set

Resolution

In instances where a new variable is defined, there is no need to set it to it's default value.

Num of instances: 8

Findings

Click to show findings

['108']

108:     uint256 currentStableRate = 0; // <= FOUND

['558']

558:     uint256 droppedReservesCount = 0; // <= FOUND

['561']

561:     for (uint256 i = 0; i < reservesListCount; i++) { // <= FOUND

['84']

84:     for (uint256 i = 0; i < input.length; i++) { // <= FOUND

['408']

408:     for (uint256 i = 0; i < reserves.length; i++) { // <= FOUND

['55']

55:     for (uint16 i = 0; i < params.reservesCount; i++) { // <= FOUND

['473']

473:     for (uint256 i = 0; i < assets.length; i++) { // <= FOUND

['708']

708:         for (uint256 i = 0; i < reservesCount; i++) { // <= FOUND

[NonCritical-9] Contract lines should not be longer than 120 characters for readability

Resolution

Consider spreading these lines over multiple lines to aid in readability and the support of VIM users everywhere.

Num of instances: 53

Findings

Click to show findings

['165']

165:    * @notice Updates the reserve current stable borrow rate, the current variable borrow rate and the current liquidity rate. // <= FOUND

['12']

12:   string public constant CALLER_NOT_POOL_OR_EMERGENCY_ADMIN = '3'; // 'The caller of the function is not a pool or emergency admin' // <= FOUND

['13']

13:   string public constant CALLER_NOT_RISK_OR_POOL_ADMIN = '4'; // 'The caller of the function is not a risk or pool admin' // <= FOUND

['14']

14:   string public constant CALLER_NOT_ASSET_LISTING_OR_POOL_ADMIN = '5'; // 'The caller of the function is not an asset listing or pool admin' // <= FOUND

['19']

19:   string public constant CALLER_NOT_POOL_CONFIGURATOR = '10'; // 'The caller of the function is not the pool configurator' // <= FOUND

['22']

22:   string public constant INVALID_FLASHLOAN_EXECUTOR_RETURN = '13'; // 'Invalid return value of the flashloan executor function' // <= FOUND

['25']

25:   string public constant EMODE_CATEGORY_RESERVED = '16'; // 'Zero eMode category is reserved for volatile heterogeneous assets' // <= FOUND

['41']

41:   string public constant NOT_ENOUGH_AVAILABLE_USER_BALANCE = '32'; // 'User cannot withdraw more than the available balance' // <= FOUND

['44']

44:   string public constant HEALTH_FACTOR_LOWER_THAN_LIQUIDATION_THRESHOLD = '35'; // 'Health factor is lesser than the liquidation threshold' // <= FOUND

['45']

45:   string public constant COLLATERAL_CANNOT_COVER_NEW_BORROW = '36'; // 'There is not enough collateral to cover a new borrow' // <= FOUND

['46']

46:   string public constant COLLATERAL_SAME_AS_BORROWING_CURRENCY = '37'; // 'Collateral is (mostly) the same currency that is being borrowed' // <= FOUND

['47']

47:   string public constant AMOUNT_BIGGER_THAN_MAX_LOAN_SIZE_STABLE = '38'; // 'The requested amount is greater than the max loan size in stable rate mode' // <= FOUND

['48']

48:   string public constant NO_DEBT_OF_SELECTED_TYPE = '39'; // 'For repayment of a specific type of debt, the user needs to have debt that type' // <= FOUND

['49']

49:   string public constant NO_EXPLICIT_AMOUNT_TO_REPAY_ON_BEHALF = '40'; // 'To repay on behalf of a user an explicit amount to repay is needed' // <= FOUND

['50']

50:   string public constant NO_OUTSTANDING_STABLE_DEBT = '41'; // 'User does not have outstanding stable rate debt on this reserve' // <= FOUND

['51']

51:   string public constant NO_OUTSTANDING_VARIABLE_DEBT = '42'; // 'User does not have outstanding variable rate debt on this reserve' // <= FOUND

['53']

53:   string public constant INTEREST_RATE_REBALANCE_CONDITIONS_NOT_MET = '44'; // 'Interest rate rebalance conditions were not met' // <= FOUND

['62']

62:   string public constant UNDERLYING_CLAIMABLE_RIGHTS_NOT_ZERO = '54'; // 'Claimable rights over underlying not zero (aToken supply or accruedToTreasury)' // <= FOUND

['92']

92:   string public constant INVALID_OPTIMAL_STABLE_TO_TOTAL_DEBT_RATIO = '84'; // 'Invalid optimal stable to total debt ratio' // <= FOUND

['95']

95:   string public constant POOL_ADDRESSES_DO_NOT_MATCH = '87'; // 'The token implementation pool address and the pool address provided by the initializing pool do not match' // <= FOUND

['97']

97:   string public constant SILOED_BORROWING_VIOLATION = '89'; // 'User is trying to borrow multiple assets including a siloed one' // <= FOUND

['103']

103:   string public constant SLOPE_2_MUST_BE_GTE_SLOPE_1 = '95'; // Variable interest rate slope 2 can not be lower than slope 1 // <= FOUND

['104']

104:   string public constant CALLER_NOT_RISK_OR_POOL_OR_EMERGENCY_ADMIN = '96'; // 'The caller of the function is not a risk, pool or emergency admin' // <= FOUND

['105']

105:   string public constant LIQUIDATION_GRACE_SENTINEL_CHECK_FAILED = '97'; // 'Liquidation grace sentinel validation failed' // <= FOUND

['60']

60:    * @param liquidationThreshold The threshold at which loans using this asset as collateral will be considered undercollateralized // <= FOUND

['403']

403:    * @dev Rebalancing is accepted when depositors are earning <= 90% of their earnings in pure supply/demand market (variable rate only) // <= FOUND

['404']

404:    * For this to be the case, there has to be quite large stable debt with an interest rate below the current variable rate. // <= FOUND

['169']

169:    * @param collateralAsset The address of the underlying asset used as collateral, to receive as result of the liquidation // <= FOUND

['460']

460:    * @param receiverAddress The address of the contract receiving the funds, implementing IFlashLoanSimpleReceiver interface // <= FOUND

['658']

658:    * @notice Returns the address of the underlying asset of a reserve by the reserve id as stored in the DataTypes.ReserveData struct // <= FOUND

['13']

13:   uint256 internal constant LTV_MASK =                       0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000; // prettier-ignore // <= FOUND

['14']

14:   uint256 internal constant LIQUIDATION_THRESHOLD_MASK =     0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFF; // prettier-ignore // <= FOUND

['15']

15:   uint256 internal constant LIQUIDATION_BONUS_MASK =         0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFFFFFF; // prettier-ignore // <= FOUND

['16']

16:   uint256 internal constant DECIMALS_MASK =                  0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFF; // prettier-ignore // <= FOUND

['17']

17:   uint256 internal constant ACTIVE_MASK =                    0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFF; // prettier-ignore // <= FOUND

['18']

18:   uint256 internal constant FROZEN_MASK =                    0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDFFFFFFFFFFFFFF; // prettier-ignore // <= FOUND

['19']

19:   uint256 internal constant BORROWING_MASK =                 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBFFFFFFFFFFFFFF; // prettier-ignore // <= FOUND

['20']

20:   uint256 internal constant STABLE_BORROWING_MASK =          0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFFFFF; // prettier-ignore // <= FOUND

['21']

21:   uint256 internal constant PAUSED_MASK =                    0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFF; // prettier-ignore // <= FOUND

['22']

22:   uint256 internal constant BORROWABLE_IN_ISOLATION_MASK =   0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDFFFFFFFFFFFFFFF; // prettier-ignore // <= FOUND

['23']

23:   uint256 internal constant SILOED_BORROWING_MASK =          0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBFFFFFFFFFFFFFFF; // prettier-ignore // <= FOUND

['24']

24:   uint256 internal constant FLASHLOAN_ENABLED_MASK =         0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFFFFFF; // prettier-ignore // <= FOUND

['25']

25:   uint256 internal constant RESERVE_FACTOR_MASK =            0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFFFFFFFFFFFFFF; // prettier-ignore // <= FOUND

['26']

26:   uint256 internal constant BORROW_CAP_MASK =                0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000FFFFFFFFFFFFFFFFFFFF; // prettier-ignore // <= FOUND

['27']

27:   uint256 internal constant SUPPLY_CAP_MASK =                0xFFFFFFFFFFFFFFFFFFFFFFFFFF000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFF; // prettier-ignore // <= FOUND

['28']

28:   uint256 internal constant LIQUIDATION_PROTOCOL_FEE_MASK =  0xFFFFFFFFFFFFFFFFFFFFFF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; // prettier-ignore // <= FOUND

['29']

29:   uint256 internal constant EMODE_CATEGORY_MASK =            0xFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; // prettier-ignore // <= FOUND

['30']

30:   uint256 internal constant UNBACKED_MINT_CAP_MASK =         0xFFFFFFFFFFF000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; // prettier-ignore // <= FOUND

['31']

31:   uint256 internal constant DEBT_CEILING_MASK =              0xF0000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; // prettier-ignore // <= FOUND

['32']

32:   uint256 internal constant VIRTUAL_ACC_ACTIVE =             0xEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; // prettier-ignore // <= FOUND

['356']

356:    * @dev If the Health Factor is below CLOSE_FACTOR_HF_THRESHOLD, the close factor is increased to MAX_LIQUIDATION_CLOSE_FACTOR // <= FOUND

['463']

463:    * @return The maximum amount that is possible to liquidate given all the liquidation constraints (user balance, close factor) // <= FOUND

['276']

276:    * @dev The rules that define if a position can be rebalanced are implemented in `ValidationLogic.validateRebalanceStableBorrowRate()` // <= FOUND

[NonCritical-10] Old Solidity version

Resolution

Using outdated Solidity versions can lead to security risks and inefficiencies. It's recommended to adopt newer versions, ideally the latest, which as of now is 0.8.24. This ensures access to the latest bug fixes, features, and optimizations, particularly crucial for Layer 2 deployments. Regular updates to versions like 0.8.19 or later, up to 0.8.24, enhance contract security and performance.

Num of instances: 2

Findings

Click to show findings

['2']

2: pragma solidity ^0.8.0; // <= FOUND

['2']

2: pragma solidity ^0.8.10;

[NonCritical-11] Functions within contracts are not ordered according to the solidity style guide

Resolution

The following order should be used within contracts

constructor

receive function (if exists)

fallback function (if exists)

external

public

internal

private

Rearrange the contract functions and contructors to fit this ordering

Num of instances: 2

Findings

Click to show findings

['39']

39: abstract contract Pool is VersionedInitializable, PoolStorage, IPool  // <= FOUND

['25']

25: abstract contract PoolConfigurator is VersionedInitializable, IPoolConfigurator  // <= FOUND

[NonCritical-12] All interfaces used within a project should be imported

Num of instances: 4

Findings

Click to show findings

['12']

12: interface IPoolConfigurator  // <= FOUND

['11']

11: interface IReserveInterestRateStrategy  // <= FOUND

['12']

12: interface IPool  // <= FOUND

['12']

12: interface IDefaultInterestRateStrategyV2 is IReserveInterestRateStrategy  // <= FOUND

[NonCritical-13] Unused state variables present

Resolution

If these serve no purpose, they should be safely removed

Num of instances: 17

Findings

Click to show findings

['11']

11:   string public constant CALLER_NOT_EMERGENCY_ADMIN = '2';  // <= FOUND

['16']

16:   string public constant ADDRESSES_PROVIDER_NOT_REGISTERED = '7';  // <= FOUND

['17']

17:   string public constant INVALID_ADDRESSES_PROVIDER_ID = '8';  // <= FOUND

['32']

32:   string public constant CALLER_MUST_BE_POOL = '23';  // <= FOUND

['33']

33:   string public constant INVALID_MINT_AMOUNT = '24';  // <= FOUND

['34']

34:   string public constant INVALID_BURN_AMOUNT = '25';  // <= FOUND

['82']

82:   string public constant INVALID_RESERVE_INDEX = '74';  // <= FOUND

['83']

83:   string public constant ACL_ADMIN_CANNOT_BE_ZERO = '75';  // <= FOUND

['84']

84:   string public constant INCONSISTENT_PARAMS_LENGTH = '76';  // <= FOUND

['86']

86:   string public constant INVALID_EXPIRATION = '78';  // <= FOUND

['87']

87:   string public constant INVALID_SIGNATURE = '79';  // <= FOUND

['88']

88:   string public constant OPERATION_NOT_SUPPORTED = '80';  // <= FOUND

['92']

92:   string public constant INVALID_OPTIMAL_STABLE_TO_TOTAL_DEBT_RATIO = '84';  // <= FOUND

['93']

93:   string public constant UNDERLYING_CANNOT_BE_RESCUED = '85';  // <= FOUND

['94']

94:   string public constant ADDRESSES_PROVIDER_ALREADY_ADDED = '86';  // <= FOUND

['95']

95:   string public constant POOL_ADDRESSES_DO_NOT_MATCH = '87';  // <= FOUND

['58']

58:   bytes32 public constant ISOLATED_COLLATERAL_SUPPLIER_ROLE =
59:     keccak256('ISOLATED_COLLATERAL_SUPPLIER'); // <= FOUND

[NonCritical-14] Constants should be on the left side of the comparison

Resolution

Putting constants on the left side of a comparison operator like == or < is a best practice known as "Yoda conditions", which can help prevent accidental assignment instead of comparison. In some programming languages, if a variable is mistakenly put on the left with a single = instead of ==, it assigns the constant's value to the variable without any compiler error. However, doing this with the constant on the left would generate an error, as constants cannot be assigned values. Although Solidity's static typing system prevents accidental assignments within conditionals, adopting this practice enhances code readability and consistency, especially when developers are working across multiple languages that support this convention.

Num of instances: 27

Findings

Click to show findings

['235']

235:     if (stableDebt + variableDebt - paybackAmount == 0)  // <= FOUND

['255']

255:       if (IAToken(reserveCache.aTokenAddress).scaledBalanceOf(msg.sender) == 0)  // <= FOUND

['133']

133:     if (vars.totalDebt != 0)  // <= FOUND

['301']

301:     if (liquidatorPreviousATokenBalance == 0)  // <= FOUND

['338']

338:       if (vars.userVariableDebt != 0)  // <= FOUND

['221']

221:     if (params.userEModeCategory != 0)  // <= FOUND

['510']

510:     if (vars.liquidationProtocolFeePercentage != 0)  // <= FOUND

['148']

148:     if (liquidationThreshold != 0)  // <= FOUND

['264']

264:    if (!paused && gracePeriod != 0)  // <= FOUND

['309']

309:     if (currentConfig.getLiquidationThreshold() != 0 && oldDebtCeiling == 0)  // <= FOUND

['315']

315:     if (newDebtCeiling == 0)  // <= FOUND

['439']

439:     if (newCategoryId != 0)  // <= FOUND

['249']

249:     if (reserveCache.reserveFactor == 0)  // <= FOUND

['283']

283:     if (vars.amountToMint != 0)  // <= FOUND

['303']

303:     if (reserveCache.currLiquidityRate != 0)  // <= FOUND

['318']

318:     if (reserveCache.currScaledVariableDebt != 0)  // <= FOUND

['193']

193:     if (params.from != params.to && scaledAmount != 0)  // <= FOUND

['221']

221:     if (params.userEModeCategory != 0)  // <= FOUND

['737']

737:    if (reserveConfig.getLtv() == 0)  // <= FOUND

['765']

765:    if (reserveConfig.getDebtCeiling() != 0)  // <= FOUND

['204']

204:     if (vars.liquidationProtocolFeeAmount != 0)  // <= FOUND

['100']

100:       if (accruedToTreasury != 0)  // <= FOUND

['216']

216:       if (params.balanceToBefore == 0)  // <= FOUND

['188']

188:     if (vars.borrowCap != 0)  // <= FOUND

['216']

216:       if (params.balanceToBefore == 0)  // <= FOUND

['210']

210:      if (liquidityAdded > 0)  // <= FOUND

['213']

213:       if (liquidityTaken > 0)  // <= FOUND

[NonCritical-15] Initialize functions do not emit an event

Resolution

Emitting an event within initializer functions in Solidity is a best practice for providing transparency and traceability. Initializer functions set the initial state and values of an upgradeable contract. Emitting an event during initialization allows anyone to verify and audit the initial state of the contract via the transaction logs. This can be particularly useful for verifying the parameters set during initialization, tracking the contract's deployment, and troubleshooting or debugging. Therefore, developers should include an event emission in their initializer functions, providing a clear record of the contract's initialization and enhancing the contract's transparency and security.

Num of instances: 2

Findings

Click to show findings

['14']

14:   function initialize(IPoolAddressesProvider provider) public virtual override initializer { // <= FOUND
15:     _addressesProvider = provider;
16:     _pool = IPool(_addressesProvider.getPool());
17:   }

['20']

20:   function initialize(IPoolAddressesProvider provider) external virtual override initializer { // <= FOUND
21:     require(provider == ADDRESSES_PROVIDER, Errors.INVALID_ADDRESSES_PROVIDER);
22:     _maxStableRateBorrowSizePercent = 0.25e4;
23:   }

[NonCritical-16] Use of non-named numeric constants

Resolution

Magic numbers should be avoided in Solidity code to enhance readability, maintainability, and reduce the likelihood of errors. Magic numbers are hard-coded values with no clear meaning or context, which can create confusion and make the code harder to understand for developers. Using well-defined constants or variables with descriptive names instead of magic numbers not only clarifies the purpose and significance of the value but also simplifies code updates and modifications.

Num of instances: 3

Findings

Click to show findings

['135']

135:       uint256 nextIsolationModeTotalDebt = reservesData[isolationModeCollateralAddress]
136:         .isolationModeTotalDebt += (params.amount /
137:         10 ** // <= FOUND
138:           (reserveCache.reserveConfiguration.getDecimals() -
139:             ReserveConfiguration.DEBT_CEILING_DECIMALS)).toUint128();

['211']

211:       require(
212:         reservesData[params.isolationModeCollateralAddress].isolationModeTotalDebt +
213:           (params.amount /
214:             10 ** (vars.reserveDecimals - ReserveConfiguration.DEBT_CEILING_DECIMALS)) // <= FOUND
215:             .toUint128() <=
216:           params.isolationModeDebtCeiling,
217:         Errors.DEBT_CEILING_EXCEEDED
218:       );

['85']

85:       require(IERC20Detailed(input[i].underlyingAsset).decimals() > 5, Errors.INVALID_DECIMALS); // <= FOUND

[NonCritical-17] Long powers of ten should use scientific notation 1eX

Resolution

A large number such as 1000000 is far more readable as 1e6, this will help prevent unintended bugs in the code

Num of instances: 1

Findings

Click to show findings

['29']

29:   
30:   uint256 public constant MAX_BORROW_RATE = 1000_00; // <= FOUND

[NonCritical-18] Redundant else statement

Num of instances: 2

Findings

Click to show findings

[]

47:   function getNormalizedIncome(
48:     DataTypes.ReserveData storage reserve
49:   ) internal view returns (uint256) {
50:     uint40 timestamp = reserve.lastUpdateTimestamp;
51: 
53:     if (timestamp == block.timestamp) {
54:       
55:       return reserve.liquidityIndex;
56:     } else {
57:       return
58:         MathUtils.calculateLinearInterest(reserve.currentLiquidityRate, timestamp).rayMul(
59:           reserve.liquidityIndex
60:         );
61:     }
62:   }

[]

71:   function getNormalizedDebt(
72:     DataTypes.ReserveData storage reserve
73:   ) internal view returns (uint256) {
74:     uint40 timestamp = reserve.lastUpdateTimestamp;
75: 
77:     if (timestamp == block.timestamp) {
78:       
79:       return reserve.variableBorrowIndex;
80:     } else {
81:       return
82:         MathUtils.calculateCompoundedInterest(reserve.currentVariableBorrowRate, timestamp).rayMul(
83:           reserve.variableBorrowIndex
84:         );
85:     }
86:   }

[NonCritical-19] Missing events in sensitive functions

Resolution

Sensitive setter functions in smart contracts often alter critical state variables. Without events emitted in these functions, external observers or dApps cannot easily track or react to these state changes. Missing events can obscure contract activity, hampering transparency and making integration more challenging. To resolve this, incorporate appropriate event emissions within these functions. Events offer an efficient way to log crucial changes, aiding in real-time tracking and post-transaction verification.

Num of instances: 40

Findings

Click to show findings

['57']

57:   function setInterestRateParams( // <= FOUND
58:     address reserve,
59:     bytes calldata rateData
60:   ) external onlyPoolConfigurator {
61:     _setInterestRateParams(reserve, abi.decode(rateData, (InterestRateData)));
62:   }

['65']

65:   function setInterestRateParams( // <= FOUND
66:     address reserve,
67:     InterestRateData calldata rateData
68:   ) external onlyPoolConfigurator {
69:     _setInterestRateParams(reserve, rateData);
70:   }

['101']

101:   function setUserUseReserveAsCollateral(bytes32 args) external override { // <= FOUND
102:     (address asset, bool useAsCollateral) = CalldataLogic.decodeSetUserUseReserveAsCollateralParams(
103:       _reservesList,
104:       args
105:     );
106:     setUserUseReserveAsCollateral(asset, useAsCollateral);
107:   }

['348']

348:   function setUserUseReserveAsCollateral( // <= FOUND
349:     address asset,
350:     bool useAsCollateral
351:   ) public virtual override {
352:     SupplyLogic.executeUseReserveAsCollateral(
353:       _reserves,
354:       _reservesList,
355:       _eModeCategories,
356:       _usersConfig[msg.sender],
357:       asset,
358:       useAsCollateral,
359:       _reservesCount,
360:       ADDRESSES_PROVIDER.getPriceOracle(),
361:       _usersEModeCategory[msg.sender]
362:     );
363:   }

['673']

673:   function setReserveInterestRateStrategyAddress( // <= FOUND
674:     address asset,
675:     address rateStrategyAddress
676:   ) external virtual override onlyPoolConfigurator {
677:     require(asset != address(0), Errors.ZERO_ADDRESS_NOT_VALID);
678:     require(_reserves[asset].id != 0 || _reservesList[0] == asset, Errors.ASSET_NOT_LISTED);
679: 
680:     _reserves[asset].interestRateStrategyAddress = rateStrategyAddress;
681:   }

['700']

700:   function setConfiguration( // <= FOUND
701:     address asset,
702:     DataTypes.ReserveConfigurationMap calldata configuration
703:   ) external virtual override onlyPoolConfigurator {
704:     require(asset != address(0), Errors.ZERO_ADDRESS_NOT_VALID);
705:     require(_reserves[asset].id != 0 || _reservesList[0] == asset, Errors.ASSET_NOT_LISTED);
706:     _reserves[asset].configuration = configuration;
707:   }

['743']

743:   function setUserEMode(uint8 categoryId) external virtual override { // <= FOUND
744:     EModeLogic.executeSetUserEMode(
745:       _reserves,
746:       _reservesList,
747:       _eModeCategories,
748:       _usersEModeCategory,
749:       _usersConfig[msg.sender],
750:       DataTypes.ExecuteSetUserEModeParams({
751:         reservesCount: _reservesCount,
752:         oracle: ADDRESSES_PROVIDER.getPriceOracle(),
753:         categoryId: categoryId
754:       })
755:     );
756:   }

['776']

776:   function setLiquidationGracePeriod( // <= FOUND
777:     address asset,
778:     uint40 until
779:   ) external virtual override onlyPoolConfigurator {
780:     require(_reserves[asset].id != 0 || _reservesList[0] == asset, Errors.ASSET_NOT_LISTED);
781:     PoolLogic.executeSetLiquidationGracePeriod(_reserves, asset, until);
782:   }

['279']

279:   function setReservePause(address asset, bool paused) external override onlyEmergencyOrPoolAdmin { // <= FOUND
280:     setReservePause(asset, paused, 0);
281:   }

['465']

465:   function setReserveInterestRateData( // <= FOUND
466:     address asset,
467:     bytes calldata rateData
468:   ) external onlyRiskOrPoolAdmins {
469:     DataTypes.ReserveDataLegacy memory reserve = _pool.getReserveData(asset);
470:     _updateInterestRateStrategy(asset, reserve, reserve.interestRateStrategyAddress, rateData);
471:   }

['474']

474:   function setReserveInterestRateStrategyAddress( // <= FOUND
475:     address asset,
476:     address rateStrategyAddress,
477:     bytes calldata rateData
478:   ) external override onlyRiskOrPoolAdmins {
479:     DataTypes.ReserveDataLegacy memory reserve = _pool.getReserveData(asset);
480:     _updateInterestRateStrategy(asset, reserve, rateStrategyAddress, rateData);
481:   }

['484']

484:   function setPoolPause(bool paused, uint40 gracePeriod) public override onlyEmergencyOrPoolAdmin { // <= FOUND
485:     address[] memory reserves = _pool.getReservesList();
486: 
487:     for (uint256 i = 0; i < reserves.length; i++) {
488:       if (reserves[i] != address(0)) {
489:         setReservePause(reserves[i], paused, gracePeriod);
490:       }
491:     }
492:   }

['495']

495:   function setPoolPause(bool paused) external override onlyEmergencyOrPoolAdmin { // <= FOUND
496:     setPoolPause(paused, 0);
497:   }

['75']

75:   function setLtv(DataTypes.ReserveConfigurationMap memory self, uint256 ltv) internal pure { // <= FOUND
76:     require(ltv <= MAX_VALID_LTV, Errors.INVALID_LTV);
77: 
78:     self.data = (self.data & LTV_MASK) | ltv;
79:   }

['95']

95:   function setLiquidationThreshold( // <= FOUND
96:     DataTypes.ReserveConfigurationMap memory self,
97:     uint256 threshold
98:   ) internal pure {
99:     require(threshold <= MAX_VALID_LIQUIDATION_THRESHOLD, Errors.INVALID_LIQ_THRESHOLD);
100: 
101:     self.data =
102:       (self.data & LIQUIDATION_THRESHOLD_MASK) |
103:       (threshold << LIQUIDATION_THRESHOLD_START_BIT_POSITION);
104:   }

['122']

122:   function setLiquidationBonus( // <= FOUND
123:     DataTypes.ReserveConfigurationMap memory self,
124:     uint256 bonus
125:   ) internal pure {
126:     require(bonus <= MAX_VALID_LIQUIDATION_BONUS, Errors.INVALID_LIQ_BONUS);
127: 
128:     self.data =
129:       (self.data & LIQUIDATION_BONUS_MASK) |
130:       (bonus << LIQUIDATION_BONUS_START_BIT_POSITION);
131:   }

['149']

149:   function setDecimals( // <= FOUND
150:     DataTypes.ReserveConfigurationMap memory self,
151:     uint256 decimals
152:   ) internal pure {
153:     require(decimals <= MAX_VALID_DECIMALS, Errors.INVALID_DECIMALS);
154: 
155:     self.data = (self.data & DECIMALS_MASK) | (decimals << RESERVE_DECIMALS_START_BIT_POSITION);
156:   }

['174']

174:   function setActive(DataTypes.ReserveConfigurationMap memory self, bool active) internal pure { // <= FOUND
175:     self.data =
176:       (self.data & ACTIVE_MASK) |
177:       (uint256(active ? 1 : 0) << IS_ACTIVE_START_BIT_POSITION);
178:   }

['194']

194:   function setFrozen(DataTypes.ReserveConfigurationMap memory self, bool frozen) internal pure { // <= FOUND
195:     self.data =
196:       (self.data & FROZEN_MASK) |
197:       (uint256(frozen ? 1 : 0) << IS_FROZEN_START_BIT_POSITION);
198:   }

['214']

214:   function setPaused(DataTypes.ReserveConfigurationMap memory self, bool paused) internal pure { // <= FOUND
215:     self.data =
216:       (self.data & PAUSED_MASK) |
217:       (uint256(paused ? 1 : 0) << IS_PAUSED_START_BIT_POSITION);
218:   }

['238']

238:   function setBorrowableInIsolation( // <= FOUND
239:     DataTypes.ReserveConfigurationMap memory self,
240:     bool borrowable
241:   ) internal pure {
242:     self.data =
243:       (self.data & BORROWABLE_IN_ISOLATION_MASK) |
244:       (uint256(borrowable ? 1 : 0) << BORROWABLE_IN_ISOLATION_START_BIT_POSITION);
245:   }

['268']

268:   function setSiloedBorrowing( // <= FOUND
269:     DataTypes.ReserveConfigurationMap memory self,
270:     bool siloed
271:   ) internal pure {
272:     self.data =
273:       (self.data & SILOED_BORROWING_MASK) |
274:       (uint256(siloed ? 1 : 0) << SILOED_BORROWING_START_BIT_POSITION);
275:   }

['294']

294:   function setBorrowingEnabled( // <= FOUND
295:     DataTypes.ReserveConfigurationMap memory self,
296:     bool enabled
297:   ) internal pure {
298:     self.data =
299:       (self.data & BORROWING_MASK) |
300:       (uint256(enabled ? 1 : 0) << BORROWING_ENABLED_START_BIT_POSITION);
301:   }

['319']

319:   function setStableRateBorrowingEnabled( // <= FOUND
320:     DataTypes.ReserveConfigurationMap memory self,
321:     bool enabled
322:   ) internal pure {
323:     self.data =
324:       (self.data & STABLE_BORROWING_MASK) |
325:       (uint256(enabled ? 1 : 0) << STABLE_BORROWING_ENABLED_START_BIT_POSITION);
326:   }

['344']

344:   function setReserveFactor( // <= FOUND
345:     DataTypes.ReserveConfigurationMap memory self,
346:     uint256 reserveFactor
347:   ) internal pure {
348:     require(reserveFactor <= MAX_VALID_RESERVE_FACTOR, Errors.INVALID_RESERVE_FACTOR);
349: 
350:     self.data =
351:       (self.data & RESERVE_FACTOR_MASK) |
352:       (reserveFactor << RESERVE_FACTOR_START_BIT_POSITION);
353:   }

['371']

371:   function setBorrowCap( // <= FOUND
372:     DataTypes.ReserveConfigurationMap memory self,
373:     uint256 borrowCap
374:   ) internal pure {
375:     require(borrowCap <= MAX_VALID_BORROW_CAP, Errors.INVALID_BORROW_CAP);
376: 
377:     self.data = (self.data & BORROW_CAP_MASK) | (borrowCap << BORROW_CAP_START_BIT_POSITION);
378:   }

['396']

396:   function setSupplyCap( // <= FOUND
397:     DataTypes.ReserveConfigurationMap memory self,
398:     uint256 supplyCap
399:   ) internal pure {
400:     require(supplyCap <= MAX_VALID_SUPPLY_CAP, Errors.INVALID_SUPPLY_CAP);
401: 
402:     self.data = (self.data & SUPPLY_CAP_MASK) | (supplyCap << SUPPLY_CAP_START_BIT_POSITION);
403:   }

['421']

421:   function setDebtCeiling( // <= FOUND
422:     DataTypes.ReserveConfigurationMap memory self,
423:     uint256 ceiling
424:   ) internal pure {
425:     require(ceiling <= MAX_VALID_DEBT_CEILING, Errors.INVALID_DEBT_CEILING);
426: 
427:     self.data = (self.data & DEBT_CEILING_MASK) | (ceiling << DEBT_CEILING_START_BIT_POSITION);
428:   }

['446']

446:   function setLiquidationProtocolFee( // <= FOUND
447:     DataTypes.ReserveConfigurationMap memory self,
448:     uint256 liquidationProtocolFee
449:   ) internal pure {
450:     require(
451:       liquidationProtocolFee <= MAX_VALID_LIQUIDATION_PROTOCOL_FEE,
452:       Errors.INVALID_LIQUIDATION_PROTOCOL_FEE
453:     );
454: 
455:     self.data =
456:       (self.data & LIQUIDATION_PROTOCOL_FEE_MASK) |
457:       (liquidationProtocolFee << LIQUIDATION_PROTOCOL_FEE_START_BIT_POSITION);
458:   }

['477']

477:   function setUnbackedMintCap( // <= FOUND
478:     DataTypes.ReserveConfigurationMap memory self,
479:     uint256 unbackedMintCap
480:   ) internal pure {
481:     require(unbackedMintCap <= MAX_VALID_UNBACKED_MINT_CAP, Errors.INVALID_UNBACKED_MINT_CAP);
482: 
483:     self.data =
484:       (self.data & UNBACKED_MINT_CAP_MASK) |
485:       (unbackedMintCap << UNBACKED_MINT_CAP_START_BIT_POSITION);
486:   }

['504']

504:   function setEModeCategory( // <= FOUND
505:     DataTypes.ReserveConfigurationMap memory self,
506:     uint256 category
507:   ) internal pure {
508:     require(category <= MAX_VALID_EMODE_CATEGORY, Errors.INVALID_EMODE_CATEGORY);
509: 
510:     self.data = (self.data & EMODE_CATEGORY_MASK) | (category << EMODE_CATEGORY_START_BIT_POSITION);
511:   }

['529']

529:   function setFlashLoanEnabled( // <= FOUND
530:     DataTypes.ReserveConfigurationMap memory self,
531:     bool flashLoanEnabled
532:   ) internal pure {
533:     self.data =
534:       (self.data & FLASHLOAN_ENABLED_MASK) |
535:       (uint256(flashLoanEnabled ? 1 : 0) << FLASHLOAN_ENABLED_START_BIT_POSITION);
536:   }

['554']

554:   function setVirtualAccActive( // <= FOUND
555:     DataTypes.ReserveConfigurationMap memory self,
556:     bool active
557:   ) internal pure {
558:     self.data =
559:       (self.data & VIRTUAL_ACC_ACTIVE) |
560:       (uint256(active ? 1 : 0) << VIRTUAL_ACC_START_BIT_POSITION);
561:   }

['710']

710:   function updateBridgeProtocolFee( // <= FOUND
711:     uint256 protocolFee
712:   ) external virtual override onlyPoolConfigurator {
713:     _bridgeProtocolFee = protocolFee;
714:   }

['717']

717:   function updateFlashloanPremiums( // <= FOUND
718:     uint128 flashLoanPremiumTotal,
719:     uint128 flashLoanPremiumToProtocol
720:   ) external virtual override onlyPoolConfigurator {
721:     _flashLoanPremiumTotal = flashLoanPremiumTotal;
722:     _flashLoanPremiumToProtocol = flashLoanPremiumToProtocol;
723:   }

['103']

103:   function updateAToken( // <= FOUND
104:     ConfiguratorInputTypes.UpdateATokenInput calldata input
105:   ) external override onlyPoolAdmin {
106:     ConfiguratorLogic.executeUpdateAToken(_pool, input);
107:   }

['110']

110:   function updateStableDebtToken( // <= FOUND
111:     ConfiguratorInputTypes.UpdateDebtTokenInput calldata input
112:   ) external override onlyPoolAdmin {
113:     ConfiguratorLogic.executeUpdateStableDebtToken(_pool, input);
114:   }

['117']

117:   function updateVariableDebtToken( // <= FOUND
118:     ConfiguratorInputTypes.UpdateDebtTokenInput calldata input
119:   ) external override onlyPoolAdmin {
120:     ConfiguratorLogic.executeUpdateVariableDebtToken(_pool, input);
121:   }

['93']

93:   function updateState( // <= FOUND
94:     DataTypes.ReserveData storage reserve,
95:     DataTypes.ReserveCache memory reserveCache
96:   ) internal {
97:     
99:     if (reserve.lastUpdateTimestamp == uint40(block.timestamp)) {
100:       return;
101:     }
102: 
103:     _updateIndexes(reserve, reserveCache);
104:     _accrueToTreasury(reserve, reserveCache);
105: 
107:     reserve.lastUpdateTimestamp = uint40(block.timestamp);
108:   }

['296']

296:   function _updateIndexes( // <= FOUND
297:     DataTypes.ReserveData storage reserve,
298:     DataTypes.ReserveCache memory reserveCache
299:   ) internal {
300:     
303:     if (reserveCache.currLiquidityRate != 0) {
304:       uint256 cumulatedLiquidityInterest = MathUtils.calculateLinearInterest(
305:         reserveCache.currLiquidityRate,
306:         reserveCache.reserveLastUpdateTimestamp
307:       );
308:       reserveCache.nextLiquidityIndex = cumulatedLiquidityInterest.rayMul(
309:         reserveCache.currLiquidityIndex
310:       );
311:       reserve.liquidityIndex = reserveCache.nextLiquidityIndex.toUint128();
312:     }
313: 
318:     if (reserveCache.currScaledVariableDebt != 0) {
319:       uint256 cumulatedVariableBorrowInterest = MathUtils.calculateCompoundedInterest(
320:         reserveCache.currVariableBorrowRate,
321:         reserveCache.reserveLastUpdateTimestamp
322:       );
323:       reserveCache.nextVariableBorrowIndex = cumulatedVariableBorrowInterest.rayMul(
324:         reserveCache.currVariableBorrowIndex
325:       );
326:       reserve.variableBorrowIndex = reserveCache.nextVariableBorrowIndex.toUint128();
327:     }
328:   }

[NonCritical-20] Non constant/immutable state variables are missing a setter post deployment

Resolution

Non-constant or non-immutable state variables lacking a setter function can create inflexibility in contract operations. If there's no way to update these variables post-deployment, the contract might not adapt to changing conditions or requirements, which can be a significant drawback, especially in upgradable or long-lived contracts. To resolve this, implement setter functions guarded by appropriate access controls, like onlyOwner or similar modifiers, so that these variables can be updated as required while maintaining security. This enables smoother contract maintenance and feature upgrades.

Num of instances: 2

Findings

Click to show findings

['29']

29:   IPoolAddressesProvider internal _addressesProvider;

['30']

30:   IPool internal _pool;

[NonCritical-21] Long numbers should include underscores to improve readability and prevent typos

Resolution

A large number such as 2000000 is far more readable as 2_000_000, this will help prevent unintended bugs in the code

Num of instances: 9

Findings

Click to show findings

['55']

55:   uint256 internal constant MAX_VALID_LTV = 65535; // <= FOUND

['56']

56:   uint256 internal constant MAX_VALID_LIQUIDATION_THRESHOLD = 65535; // <= FOUND

['57']

57:   uint256 internal constant MAX_VALID_LIQUIDATION_BONUS = 65535; // <= FOUND

['59']

59:   uint256 internal constant MAX_VALID_RESERVE_FACTOR = 65535; // <= FOUND

['60']

60:   uint256 internal constant MAX_VALID_BORROW_CAP = 68719476735; // <= FOUND

['61']

61:   uint256 internal constant MAX_VALID_SUPPLY_CAP = 68719476735; // <= FOUND

['62']

62:   uint256 internal constant MAX_VALID_LIQUIDATION_PROTOCOL_FEE = 65535; // <= FOUND

['64']

64:   uint256 internal constant MAX_VALID_UNBACKED_MINT_CAP = 68719476735; // <= FOUND

['65']

65:   uint256 internal constant MAX_VALID_DEBT_CEILING = 1099511627775; // <= FOUND

[NonCritical-22] Use 'using' keyword when using specific imports rather than calling the specific import directly

Resolution

In Solidity, the using keyword can streamline the use of library functions for specific types. Instead of calling library functions directly with their full import paths, you can declare a library once with using for a specific type. This approach makes your code more readable and concise. For example, instead of LibraryName.functionName(variable), you would first declare using LibraryName for TypeName; at the contract level. After this, you can call library functions directly on variables of TypeName like variable.functionName(). This method not only enhances code clarity but also promotes cleaner and more organized code, especially when multiple functions from the same library are used frequently.

Num of instances: 355

Findings

Click to show findings

['145']

145:         
146:         
147:         BorrowLogic.executeBorrow( // <= FOUND 'BorrowLogic.'
148:           reservesData,
149:           reservesList,
150:           eModeCategories,
151:           userConfig,
152:           DataTypes.ExecuteBorrowParams({ // <= FOUND 'DataTypes.'
153:             asset: vars.currentAsset,
154:             user: msg.sender,
155:             onBehalfOf: params.onBehalfOf,
156:             amount: vars.currentAmount,
157:             interestRateMode: DataTypes.InterestRateMode(params.interestRateModes[vars.i]), // <= FOUND 'DataTypes.'
158:             referralCode: params.referralCode,
159:             releaseUnderlying: false,
160:             maxStableRateBorrowSizePercent: IPool(params.pool)
161:               .MAX_STABLE_RATE_BORROW_SIZE_PERCENT(),
162:             reservesCount: IPool(params.pool).getReservesCount(),
163:             oracle: IPoolAddressesProvider(params.addressesProvider).getPriceOracle(),
164:             userEModeCategory: IPool(params.pool).getUserEMode(params.onBehalfOf).toUint8(),
165:             priceOracleSentinel: IPoolAddressesProvider(params.addressesProvider)
166:               .getPriceOracleSentinel()
167:           })

['220']

220:     BorrowLogic.executeBorrow( // <= FOUND 'BorrowLogic.'
221:       _reserves,
222:       _reservesList,
223:       _eModeCategories,
224:       _usersConfig[onBehalfOf],
225:       DataTypes.ExecuteBorrowParams({ // <= FOUND 'DataTypes.'
226:         asset: asset,
227:         user: msg.sender,
228:         onBehalfOf: onBehalfOf,
229:         amount: amount,
230:         interestRateMode: DataTypes.InterestRateMode(interestRateMode), // <= FOUND 'DataTypes.'
231:         referralCode: referralCode,
232:         releaseUnderlying: true,
233:         maxStableRateBorrowSizePercent: _maxStableRateBorrowSizePercent,
234:         reservesCount: _reservesCount,
235:         oracle: ADDRESSES_PROVIDER.getPriceOracle(),
236:         userEModeCategory: _usersEModeCategory[onBehalfOf],
237:         priceOracleSentinel: ADDRESSES_PROVIDER.getPriceOracleSentinel()
238:       })

['249']

249:     return
250:       BorrowLogic.executeRepay( // <= FOUND 'BorrowLogic.'
251:         _reserves,
252:         _reservesList,
253:         _usersConfig[onBehalfOf],
254:         DataTypes.ExecuteRepayParams({ // <= FOUND 'DataTypes.'
255:           asset: asset,
256:           amount: amount,
257:           interestRateMode: DataTypes.InterestRateMode(interestRateMode), // <= FOUND 'DataTypes.'
258:           onBehalfOf: onBehalfOf,
259:           useATokens: false
260:         })

['295']

295:       return BorrowLogic.executeRepay(_reserves, _reservesList, _usersConfig[onBehalfOf], params); // <= FOUND 'BorrowLogic.'

['305']

305:     return
306:       BorrowLogic.executeRepay( // <= FOUND 'BorrowLogic.'
307:         _reserves,
308:         _reservesList,
309:         _usersConfig[msg.sender],
310:         DataTypes.ExecuteRepayParams({ // <= FOUND 'DataTypes.'
311:           asset: asset,
312:           amount: amount,
313:           interestRateMode: DataTypes.InterestRateMode(interestRateMode), // <= FOUND 'DataTypes.'
314:           onBehalfOf: msg.sender,
315:           useATokens: true
316:         })

['322']

322:     BorrowLogic.executeSwapBorrowRateMode( // <= FOUND 'BorrowLogic.'
323:       _reserves[asset],
324:       _usersConfig[msg.sender],
325:       asset,
326:       msg.sender,
327:       DataTypes.InterestRateMode(interestRateMode) // <= FOUND 'DataTypes.'
328:     );

['333']

333:     BorrowLogic.executeSwapBorrowRateMode( // <= FOUND 'BorrowLogic.'
334:       _reserves[asset],
335:       _usersConfig[user],
336:       asset,
337:       user,
338:       DataTypes.InterestRateMode.STABLE // <= FOUND 'DataTypes.'
339:     );

['344']

344:     BorrowLogic.executeRebalanceStableBorrowRate(_reserves[asset], asset, user); // <= FOUND 'BorrowLogic.'

['113']

113:     BridgeLogic.executeMintUnbacked( // <= FOUND 'BridgeLogic.'
114:       _reserves,
115:       _reservesList,
116:       _usersConfig[onBehalfOf],
117:       asset,
118:       amount,
119:       onBehalfOf,
120:       referralCode
121:     );

['130']

130:     return
131:       BridgeLogic.executeBackUnbacked(_reserves[asset], asset, amount, fee, _bridgeProtocolFee); // <= FOUND 'BridgeLogic.'

['51']

51:   
57:   function executeInitReserve(
58:     IPool pool,
59:     ConfiguratorInputTypes.InitReserveInput calldata input // <= FOUND 'ConfiguratorInputTypes.'
60:   ) external {

['137']

137:   
143:   function executeUpdateAToken(
144:     IPool cachedPool,
145:     ConfiguratorInputTypes.UpdateATokenInput calldata input // <= FOUND 'ConfiguratorInputTypes.'
146:   ) external {

['168']

168:   
174:   function executeUpdateStableDebtToken(
175:     IPool cachedPool,
176:     ConfiguratorInputTypes.UpdateDebtTokenInput calldata input // <= FOUND 'ConfiguratorInputTypes.'
177:   ) external {

['206']

206:   
212:   function executeUpdateVariableDebtToken(
213:     IPool cachedPool,
214:     ConfiguratorInputTypes.UpdateDebtTokenInput calldata input // <= FOUND 'ConfiguratorInputTypes.'
215:   ) external {

['294']

294:   
298:   function initReserves(ConfiguratorInputTypes.InitReserveInput[] calldata input) external; // <= FOUND 'ConfiguratorInputTypes.'

['300']

300:   
304:   function updateAToken(ConfiguratorInputTypes.UpdateATokenInput calldata input) external; // <= FOUND 'ConfiguratorInputTypes.'

['306']

306:   
310:   function updateStableDebtToken(
311:     ConfiguratorInputTypes.UpdateDebtTokenInput calldata input // <= FOUND 'ConfiguratorInputTypes.'
312:   ) external;

['314']

314:   
318:   function updateVariableDebtToken(
319:     ConfiguratorInputTypes.UpdateDebtTokenInput calldata input // <= FOUND 'ConfiguratorInputTypes.'
320:   ) external;

['80']

80:   
81:   function initReserves(
82:     ConfiguratorInputTypes.InitReserveInput[] calldata input // <= FOUND 'ConfiguratorInputTypes.'
83:   ) external override onlyAssetListingOrPoolAdmins {

['103']

103:   
104:   function updateAToken(
105:     ConfiguratorInputTypes.UpdateATokenInput calldata input // <= FOUND 'ConfiguratorInputTypes.'
106:   ) external override onlyPoolAdmin {

['110']

110:   
111:   function updateStableDebtToken(
112:     ConfiguratorInputTypes.UpdateDebtTokenInput calldata input // <= FOUND 'ConfiguratorInputTypes.'
113:   ) external override onlyPoolAdmin {

['117']

117:   
118:   function updateVariableDebtToken(
119:     ConfiguratorInputTypes.UpdateDebtTokenInput calldata input // <= FOUND 'ConfiguratorInputTypes.'
120:   ) external override onlyPoolAdmin {

['87']

87:       ConfiguratorLogic.executeInitReserve(cachedPool, input[i]); // <= FOUND 'ConfiguratorLogic.'

['106']

106:     ConfiguratorLogic.executeUpdateAToken(_pool, input); // <= FOUND 'ConfiguratorLogic.'

['113']

113:     ConfiguratorLogic.executeUpdateStableDebtToken(_pool, input); // <= FOUND 'ConfiguratorLogic.'

['120']

120:     ConfiguratorLogic.executeUpdateVariableDebtToken(_pool, input); // <= FOUND 'ConfiguratorLogic.'

['30']

30:   using ReserveLogic for DataTypes.ReserveCache; // <= FOUND 'DataTypes.'

['27']

27:   using ReserveLogic for DataTypes.ReserveData; // <= FOUND 'DataTypes.'

['38']

38:   using UserConfiguration for DataTypes.UserConfigurationMap; // <= FOUND 'DataTypes.'

['28']

28:   using ReserveConfiguration for DataTypes.ReserveConfigurationMap; // <= FOUND 'DataTypes.'

['74']

74:   
75:   event Borrow(
76:     address indexed reserve,
77:     address user,
78:     address indexed onBehalfOf,
79:     uint256 amount,
80:     DataTypes.InterestRateMode interestRateMode, // <= FOUND 'DataTypes.'
81:     uint256 borrowRate,
82:     uint16 indexed referralCode
83:   );

['106']

106:   event SwapBorrowRateMode(
107:     address indexed reserve,
108:     address indexed user,
109:     DataTypes.InterestRateMode interestRateMode // <= FOUND 'DataTypes.'
110:   );

['68']

68:   
79:   function executeBorrow(
80:     mapping(address => DataTypes.ReserveData) storage reservesData, // <= FOUND 'DataTypes.'
81:     mapping(uint256 => address) storage reservesList,
82:     mapping(uint8 => DataTypes.EModeCategory) storage eModeCategories, // <= FOUND 'DataTypes.'
83:     DataTypes.UserConfigurationMap storage userConfig, // <= FOUND 'DataTypes.'
84:     DataTypes.ExecuteBorrowParams memory params // <= FOUND 'DataTypes.'
85:   ) external {

['58']

58:     DataTypes.ReserveData storage reserve = reservesData[params.asset]; // <= FOUND 'DataTypes.'

['686']

686:     DataTypes.ReserveCache memory reserveCache = reserve.cache(); // <= FOUND 'DataTypes.'

['86']

86:     ValidationLogic.validateBorrow( // <= FOUND 'ValidationLogic.'
87:       reservesData,
88:       reservesList,
89:       eModeCategories,
90:       DataTypes.ValidateBorrowParams({ // <= FOUND 'DataTypes.'
91:         reserveCache: reserveCache,
92:         userConfig: userConfig,
93:         asset: params.asset,
94:         userAddress: params.onBehalfOf,
95:         amount: params.amount,
96:         interestRateMode: params.interestRateMode,
97:         maxStableLoanPercent: params.maxStableRateBorrowSizePercent,
98:         reservesCount: params.reservesCount,
99:         oracle: params.oracle,
100:         userEModeCategory: params.userEModeCategory,
101:         priceOracleSentinel: params.priceOracleSentinel,
102:         isolationModeActive: isolationModeActive,
103:         isolationModeCollateralAddress: isolationModeCollateralAddress,
104:         isolationModeDebtCeiling: isolationModeDebtCeiling
105:       })

['283']

283:     if (params.interestRateMode == DataTypes.InterestRateMode.STABLE) { // <= FOUND 'DataTypes.'

['157']

157:     emit Borrow(
158:       params.asset,
159:       params.user,
160:       params.onBehalfOf,
161:       params.amount,
162:       params.interestRateMode,
163:       params.interestRateMode == DataTypes.InterestRateMode.STABLE // <= FOUND 'DataTypes.'
164:         ? currentStableRate
165:         : reserve.currentVariableBorrowRate,
166:       params.referralCode
167:     );

['181']

181:   
192:   function executeRepay(
193:     mapping(address => DataTypes.ReserveData) storage reservesData, // <= FOUND 'DataTypes.'
194:     mapping(uint256 => address) storage reservesList,
195:     DataTypes.UserConfigurationMap storage userConfig, // <= FOUND 'DataTypes.'
196:     DataTypes.ExecuteRepayParams memory params // <= FOUND 'DataTypes.'
197:   ) external returns (uint256) {

['205']

205:     uint256 paybackAmount = params.interestRateMode == DataTypes.InterestRateMode.STABLE // <= FOUND 'DataTypes.'
206:       ? stableDebt
207:       : variableDebt;

['282']

282:   
291:   function executeRebalanceStableBorrowRate(
292:     DataTypes.ReserveData storage reserve, // <= FOUND 'DataTypes.'
293:     address asset,
294:     address user
295:   ) external {

['313']

313:   
321:   function executeSwapBorrowRateMode(
322:     DataTypes.ReserveData storage reserve, // <= FOUND 'DataTypes.'
323:     DataTypes.UserConfigurationMap storage userConfig, // <= FOUND 'DataTypes.'
324:     address asset,
325:     address user,
326:     DataTypes.InterestRateMode interestRateMode // <= FOUND 'DataTypes.'
327:   ) external {

['335']

335:     if (interestRateMode == DataTypes.InterestRateMode.STABLE) { // <= FOUND 'DataTypes.'

['52']

52:   
66:   function executeMintUnbacked(
67:     mapping(address => DataTypes.ReserveData) storage reservesData, // <= FOUND 'DataTypes.'
68:     mapping(uint256 => address) storage reservesList,
69:     DataTypes.UserConfigurationMap storage userConfig, // <= FOUND 'DataTypes.'
70:     address asset,
71:     uint256 amount,
72:     address onBehalfOf,
73:     uint16 referralCode
74:   ) external {

['151']

151:     DataTypes.ReserveData storage reserve = reservesData[asset]; // <= FOUND 'DataTypes.'

['116']

116:   
127:   function executeBackUnbacked(
128:     DataTypes.ReserveData storage reserve, // <= FOUND 'DataTypes.'
129:     address asset,
130:     uint256 amount,
131:     uint256 fee,
132:     uint256 protocolFeeBps
133:   ) external returns (uint256) {

['106']

106:     DataTypes.ReserveConfigurationMap memory currentConfig = DataTypes.ReserveConfigurationMap(0); // <= FOUND 'DataTypes.'

['141']

141:     DataTypes.ReserveDataLegacy memory reserveData = cachedPool.getReserveData(input.asset); // <= FOUND 'DataTypes.'

['115']

115:   
116:   function calculateInterestRates(
117:     DataTypes.CalculateInterestRatesParams memory params // <= FOUND 'DataTypes.'
118:   ) external view virtual override returns (uint256, uint256, uint256) {

['157']

157:   
158:   event FlashLoan(
159:     address indexed target,
160:     address initiator,
161:     address indexed asset,
162:     uint256 amount,
163:     DataTypes.InterestRateMode interestRateMode, // <= FOUND 'DataTypes.'
164:     uint256 premium,
165:     uint16 indexed referralCode
166:   );

['71']

71:   
84:   function executeFlashLoan(
85:     mapping(address => DataTypes.ReserveData) storage reservesData, // <= FOUND 'DataTypes.'
86:     mapping(uint256 => address) storage reservesList,
87:     mapping(uint8 => DataTypes.EModeCategory) storage eModeCategories, // <= FOUND 'DataTypes.'
88:     DataTypes.UserConfigurationMap storage userConfig, // <= FOUND 'DataTypes.'
89:     DataTypes.FlashloanParams memory params // <= FOUND 'DataTypes.'
90:   ) external {

['95']

95:       vars.totalPremiums[vars.i] = DataTypes.InterestRateMode(params.interestRateModes[vars.i]) == // <= FOUND 'DataTypes.'
96:         DataTypes.InterestRateMode.NONE // <= FOUND 'DataTypes.'
97:         ? vars.currentAmount.percentMul(vars.flashloanPremiumTotal)
98:         : 0;

['127']

127:       if (
128:         DataTypes.InterestRateMode(params.interestRateModes[vars.i]) == // <= FOUND 'DataTypes.'
129:         DataTypes.InterestRateMode.NONE // <= FOUND 'DataTypes.'
130:       ) {

['131']

131:         _handleFlashLoanRepayment(
132:           reservesData[vars.currentAsset],
133:           DataTypes.FlashLoanRepaymentParams({ // <= FOUND 'DataTypes.'
134:             asset: vars.currentAsset,
135:             receiverAddress: params.receiverAddress,
136:             amount: vars.currentAmount,
137:             totalPremium: vars.totalPremiums[vars.i],
138:             flashLoanPremiumToProtocol: vars.flashloanPremiumToProtocol,
139:             referralCode: params.referralCode
140:           })

['168']

168:         
169:         emit FlashLoan(
170:           params.receiverAddress,
171:           msg.sender,
172:           vars.currentAsset,
173:           vars.currentAmount,
174:           DataTypes.InterestRateMode(params.interestRateModes[vars.i]), // <= FOUND 'DataTypes.'
175:           0,
176:           params.referralCode
177:         );

['191']

191:   
201:   function executeFlashLoanSimple(
202:     DataTypes.ReserveData storage reserve, // <= FOUND 'DataTypes.'
203:     DataTypes.FlashloanSimpleParams memory params // <= FOUND 'DataTypes.'
204:   ) external {

['221']

221:     _handleFlashLoanRepayment(
222:       reserve,
223:       DataTypes.FlashLoanRepaymentParams({ // <= FOUND 'DataTypes.'
224:         asset: params.asset,
225:         receiverAddress: params.receiverAddress,
226:         amount: params.amount,
227:         totalPremium: totalPremium,
228:         flashLoanPremiumToProtocol: params.flashLoanPremiumToProtocol,
229:         referralCode: params.referralCode
230:       })

['240']

240:   
246:   function _handleFlashLoanRepayment(
247:     DataTypes.ReserveData storage reserve, // <= FOUND 'DataTypes.'
248:     DataTypes.FlashLoanRepaymentParams memory params // <= FOUND 'DataTypes.'
249:   ) internal {

['274']

274:     emit FlashLoan(
275:       params.receiverAddress,
276:       msg.sender,
277:       params.asset,
278:       params.amount,
279:       DataTypes.InterestRateMode(0), // <= FOUND 'DataTypes.'
280:       params.totalPremium,
281:       params.referralCode
282:     );

['74']

74:   
85:   event Borrow(
86:     address indexed reserve,
87:     address user,
88:     address indexed onBehalfOf,
89:     uint256 amount,
90:     DataTypes.InterestRateMode interestRateMode, // <= FOUND 'DataTypes.'
91:     uint256 borrowRate,
92:     uint16 indexed referralCode
93:   );

['106']

106:   
112:   event SwapBorrowRateMode(
113:     address indexed reserve,
114:     address indexed user,
115:     DataTypes.InterestRateMode interestRateMode // <= FOUND 'DataTypes.'
116:   );

['157']

157:   
167:   event FlashLoan(
168:     address indexed target,
169:     address initiator,
170:     address indexed asset,
171:     uint256 amount,
172:     DataTypes.InterestRateMode interestRateMode, // <= FOUND 'DataTypes.'
173:     uint256 premium,
174:     uint16 indexed referralCode
175:   );

['557']

557:   
563:   function setConfiguration(
564:     address asset,
565:     DataTypes.ReserveConfigurationMap calldata configuration // <= FOUND 'DataTypes.'
566:   ) external;

['567']

567:   
572:   function getConfiguration(
573:     address asset
574:   ) external view returns (DataTypes.ReserveConfigurationMap memory); // <= FOUND 'DataTypes.'

['576']

576:   
581:   function getUserConfiguration(
582:     address user
583:   ) external view returns (DataTypes.UserConfigurationMap memory); // <= FOUND 'DataTypes.'

['606']

606:   
611:   function getReserveData(address asset) external view returns (DataTypes.ReserveDataLegacy memory); // <= FOUND 'DataTypes.'

['613']

613:   
618:   function getReserveDataExtended(
619:     address asset
620:   ) external view returns (DataTypes.ReserveData memory); // <= FOUND 'DataTypes.'

['698']

698:   
705:   function configureEModeCategory(uint8 id, DataTypes.EModeCategory memory config) external; // <= FOUND 'DataTypes.'

['705']

705:   
710:   function getEModeCategoryData(uint8 id) external view returns (DataTypes.EModeCategory memory); // <= FOUND 'DataTypes.'

['27']

27:   
34:   function calculateInterestRates(
35:     DataTypes.CalculateInterestRatesParams memory params // <= FOUND 'DataTypes.'
36:   ) external view returns (uint256, uint256, uint256);

['82']

82:     DataTypes.ReserveCache debtReserveCache; // <= FOUND 'DataTypes.'

['96']

96:   
107:   function executeLiquidationCall(
108:     mapping(address => DataTypes.ReserveData) storage reservesData, // <= FOUND 'DataTypes.'
109:     mapping(uint256 => address) storage reservesList,
110:     mapping(address => DataTypes.UserConfigurationMap) storage usersConfig, // <= FOUND 'DataTypes.'
111:     mapping(uint8 => DataTypes.EModeCategory) storage eModeCategories, // <= FOUND 'DataTypes.'
112:     DataTypes.ExecuteLiquidationCallParams memory params // <= FOUND 'DataTypes.'
113:   ) external {

['105']

105:     DataTypes.ReserveData storage collateralReserve = reservesData[params.collateralAsset]; // <= FOUND 'DataTypes.'

['106']

106:     DataTypes.ReserveData storage debtReserve = reservesData[params.debtAsset]; // <= FOUND 'DataTypes.'

['107']

107:     DataTypes.UserConfigurationMap storage userConfig = usersConfig[params.user]; // <= FOUND 'DataTypes.'

['111']

111:     (, , , , vars.healthFactor, ) = GenericLogic.calculateUserAccountData(
112:       reservesData,
113:       reservesList,
114:       eModeCategories,
115:       DataTypes.CalculateUserAccountDataParams({ // <= FOUND 'DataTypes.'
116:         userConfig: userConfig,
117:         reservesCount: params.reservesCount,
118:         user: params.user,
119:         oracle: params.priceOracle,
120:         userEModeCategory: params.userEModeCategory
121:       })

['130']

130:     ValidationLogic.validateLiquidationCall( // <= FOUND 'ValidationLogic.'
131:       userConfig,
132:       collateralReserve,
133:       debtReserve,
134:       DataTypes.ValidateLiquidationCallParams({ // <= FOUND 'DataTypes.'
135:         debtReserveCache: vars.debtReserveCache,
136:         totalDebt: vars.userTotalDebt,
137:         healthFactor: vars.healthFactor,
138:         priceOracleSentinel: params.priceOracleSentinel
139:       })

['252']

252:   
259:   function _burnCollateralATokens(
260:     DataTypes.ReserveData storage collateralReserve, // <= FOUND 'DataTypes.'
261:     DataTypes.ExecuteLiquidationCallParams memory params, // <= FOUND 'DataTypes.'
262:     LiquidationCallLocalVars memory vars
263:   ) internal {

['257']

257:     DataTypes.ReserveCache memory collateralReserveCache = collateralReserve.cache(); // <= FOUND 'DataTypes.'

['286']

286:   
297:   function _liquidateATokens(
298:     mapping(address => DataTypes.ReserveData) storage reservesData, // <= FOUND 'DataTypes.'
299:     mapping(uint256 => address) storage reservesList,
300:     mapping(address => DataTypes.UserConfigurationMap) storage usersConfig, // <= FOUND 'DataTypes.'
301:     DataTypes.ReserveData storage collateralReserve, // <= FOUND 'DataTypes.'
302:     DataTypes.ExecuteLiquidationCallParams memory params, // <= FOUND 'DataTypes.'
303:     LiquidationCallLocalVars memory vars
304:   ) internal {

['302']

302:       DataTypes.UserConfigurationMap storage liquidatorConfig = usersConfig[msg.sender]; // <= FOUND 'DataTypes.'

['324']

324:   
330:   function _burnDebtTokens(
331:     DataTypes.ExecuteLiquidationCallParams memory params, // <= FOUND 'DataTypes.'
332:     LiquidationCallLocalVars memory vars
333:   ) internal {

['364']

364:   
375:   function _calculateDebt(
376:     DataTypes.ReserveCache memory debtReserveCache, // <= FOUND 'DataTypes.'
377:     DataTypes.ExecuteLiquidationCallParams memory params, // <= FOUND 'DataTypes.'
378:     uint256 healthFactor
379:   ) internal view returns (uint256, uint256, uint256) {

['399']

399:   
409:   function _getConfigurationData(
410:     mapping(uint8 => DataTypes.EModeCategory) storage eModeCategories, // <= FOUND 'DataTypes.'
411:     DataTypes.ReserveData storage collateralReserve, // <= FOUND 'DataTypes.'
412:     DataTypes.ExecuteLiquidationCallParams memory params // <= FOUND 'DataTypes.'
413:   ) internal view returns (IAToken, address, address, uint256) {

['467']

467:   
483:   function _calculateAvailableCollateralToLiquidate(
484:     DataTypes.ReserveData storage collateralReserve, // <= FOUND 'DataTypes.'
485:     DataTypes.ReserveCache memory debtReserveCache, // <= FOUND 'DataTypes.'
486:     address collateralAsset,
487:     address debtAsset,
488:     uint256 debtToCover,
489:     uint256 userCollateralBalance,
490:     uint256 liquidationBonus,
491:     IPriceOracleGetter oracle
492:   ) internal view returns (uint256, uint256, uint256) {

['141']

141:     SupplyLogic.executeSupply( // <= FOUND 'SupplyLogic.'
142:       _reserves,
143:       _reservesList,
144:       _usersConfig[onBehalfOf],
145:       DataTypes.ExecuteSupplyParams({ // <= FOUND 'DataTypes.'
146:         asset: asset,
147:         amount: amount,
148:         onBehalfOf: onBehalfOf,
149:         referralCode: referralCode
150:       })

['195']

195:     return
196:       SupplyLogic.executeWithdraw( // <= FOUND 'SupplyLogic.'
197:         _reserves,
198:         _reservesList,
199:         _eModeCategories,
200:         _usersConfig[msg.sender],
201:         DataTypes.ExecuteWithdrawParams({ // <= FOUND 'DataTypes.'
202:           asset: asset,
203:           amount: amount,
204:           to: to,
205:           reservesCount: _reservesCount,
206:           oracle: ADDRESSES_PROVIDER.getPriceOracle(),
207:           userEModeCategory: _usersEModeCategory[msg.sender]
208:         })

['288']

288:       DataTypes.ExecuteRepayParams memory params = DataTypes.ExecuteRepayParams({ // <= FOUND 'DataTypes.'
289:         asset: asset,
290:         amount: amount,
291:         interestRateMode: DataTypes.InterestRateMode(interestRateMode), // <= FOUND 'DataTypes.'
292:         onBehalfOf: onBehalfOf,
293:         useATokens: false
294:       });

['373']

373:     LiquidationLogic.executeLiquidationCall( // <= FOUND 'LiquidationLogic.'
374:       _reserves,
375:       _reservesList,
376:       _usersConfig,
377:       _eModeCategories,
378:       DataTypes.ExecuteLiquidationCallParams({ // <= FOUND 'DataTypes.'
379:         reservesCount: _reservesCount,
380:         debtToCover: debtToCover,
381:         collateralAsset: collateralAsset,
382:         debtAsset: debtAsset,
383:         user: user,
384:         receiveAToken: receiveAToken,
385:         priceOracle: ADDRESSES_PROVIDER.getPriceOracle(),
386:         userEModeCategory: _usersEModeCategory[user],
387:         priceOracleSentinel: ADDRESSES_PROVIDER.getPriceOracleSentinel()
388:       })

['402']

402:     DataTypes.FlashloanParams memory flashParams = DataTypes.FlashloanParams({ // <= FOUND 'DataTypes.'
403:       receiverAddress: receiverAddress,
404:       assets: assets,
405:       amounts: amounts,
406:       interestRateModes: interestRateModes,
407:       onBehalfOf: onBehalfOf,
408:       params: params,
409:       referralCode: referralCode,
410:       flashLoanPremiumToProtocol: _flashLoanPremiumToProtocol,
411:       flashLoanPremiumTotal: _flashLoanPremiumTotal,
412:       maxStableRateBorrowSizePercent: _maxStableRateBorrowSizePercent,
413:       reservesCount: _reservesCount,
414:       addressesProvider: address(ADDRESSES_PROVIDER),
415:       pool: address(this),
416:       userEModeCategory: _usersEModeCategory[onBehalfOf],
417:       isAuthorizedFlashBorrower: IACLManager(ADDRESSES_PROVIDER.getACLManager()).isFlashBorrower(
418:         msg.sender
419:       )
420:     });

['439']

439:     DataTypes.FlashloanSimpleParams memory flashParams = DataTypes.FlashloanSimpleParams({ // <= FOUND 'DataTypes.'
440:       receiverAddress: receiverAddress,
441:       asset: asset,
442:       amount: amount,
443:       params: params,
444:       referralCode: referralCode,
445:       flashLoanPremiumToProtocol: _flashLoanPremiumToProtocol,
446:       flashLoanPremiumTotal: _flashLoanPremiumTotal
447:     });

['457']

457:   
458:   function getReserveDataExtended(
459:     address asset
460:   ) external view returns (DataTypes.ReserveData memory) { // <= FOUND 'DataTypes.'

['464']

464:   
465:   function getReserveData(
466:     address asset
467:   ) external view virtual override returns (DataTypes.ReserveDataLegacy memory) { // <= FOUND 'DataTypes.'

['467']

467:     DataTypes.ReserveData memory reserve = _reserves[asset]; // <= FOUND 'DataTypes.'

['468']

468:     DataTypes.ReserveDataLegacy memory res; // <= FOUND 'DataTypes.'

['512']

512:     return
513:       PoolLogic.executeGetUserAccountData( // <= FOUND 'PoolLogic.'
514:         _reserves,
515:         _reservesList,
516:         _eModeCategories,
517:         DataTypes.CalculateUserAccountDataParams({ // <= FOUND 'DataTypes.'
518:           userConfig: _usersConfig[user],
519:           reservesCount: _reservesCount,
520:           user: user,
521:           oracle: ADDRESSES_PROVIDER.getPriceOracle(),
522:           userEModeCategory: _usersEModeCategory[user]
523:         })

['528']

528:   
529:   function getConfiguration(
530:     address asset
531:   ) external view virtual override returns (DataTypes.ReserveConfigurationMap memory) { // <= FOUND 'DataTypes.'

['535']

535:   
536:   function getUserConfiguration(
537:     address user
538:   ) external view virtual override returns (DataTypes.UserConfigurationMap memory) { // <= FOUND 'DataTypes.'

['621']

621:     SupplyLogic.executeFinalizeTransfer( // <= FOUND 'SupplyLogic.'
622:       _reserves,
623:       _reservesList,
624:       _eModeCategories,
625:       _usersConfig,
626:       DataTypes.FinalizeTransferParams({ // <= FOUND 'DataTypes.'
627:         asset: asset,
628:         from: from,
629:         to: to,
630:         amount: amount,
631:         balanceFromBefore: balanceFromBefore,
632:         balanceToBefore: balanceToBefore,
633:         reservesCount: _reservesCount,
634:         oracle: ADDRESSES_PROVIDER.getPriceOracle(),
635:         fromEModeCategory: _usersEModeCategory[from]
636:       })

['648']

648:     if (
649:       PoolLogic.executeInitReserve( // <= FOUND 'PoolLogic.'
650:         _reserves,
651:         _reservesList,
652:         DataTypes.InitReserveParams({ // <= FOUND 'DataTypes.'
653:           asset: asset,
654:           aTokenAddress: aTokenAddress,
655:           stableDebtAddress: stableDebtAddress,
656:           variableDebtAddress: variableDebtAddress,
657:           interestRateStrategyAddress: interestRateStrategyAddress,
658:           reservesCount: _reservesCount,
659:           maxNumberReserves: MAX_NUMBER_RESERVES()
660:         })

['685']

685:     DataTypes.ReserveData storage reserve = _reserves[asset]; // <= FOUND 'DataTypes.'

['700']

700:   
701:   function setConfiguration(
702:     address asset,
703:     DataTypes.ReserveConfigurationMap calldata configuration // <= FOUND 'DataTypes.'
704:   ) external virtual override onlyPoolConfigurator {

['726']

726:   
727:   function configureEModeCategory(
728:     uint8 id,
729:     DataTypes.EModeCategory memory category // <= FOUND 'DataTypes.'
730:   ) external virtual override onlyPoolConfigurator {

['736']

736:   
737:   function getEModeCategoryData(
738:     uint8 id
739:   ) external view virtual override returns (DataTypes.EModeCategory memory) { // <= FOUND 'DataTypes.'

['744']

744:     EModeLogic.executeSetUserEMode(
745:       _reserves,
746:       _reservesList,
747:       _eModeCategories,
748:       _usersEModeCategory,
749:       _usersConfig[msg.sender],
750:       DataTypes.ExecuteSetUserEModeParams({ // <= FOUND 'DataTypes.'
751:         reservesCount: _reservesCount,
752:         oracle: ADDRESSES_PROVIDER.getPriceOracle(),
753:         categoryId: categoryId
754:       })

['125']

125:     DataTypes.ReserveConfigurationMap memory currentConfig = _pool.getConfiguration(asset); // <= FOUND 'DataTypes.'

['409']

409:       DataTypes.ReserveConfigurationMap memory currentConfig = _pool.getConfiguration(reserves[i]); // <= FOUND 'DataTypes.'

['419']

419:     _pool.configureEModeCategory(
420:       categoryId,
421:       DataTypes.EModeCategory({ // <= FOUND 'DataTypes.'
422:         ltv: ltv,
423:         liquidationThreshold: liquidationThreshold,
424:         liquidationBonus: liquidationBonus,
425:         priceSource: oracle,
426:         label: label
427:       })

['440']

440:       DataTypes.EModeCategory memory categoryData = _pool.getEModeCategoryData(newCategoryId); // <= FOUND 'DataTypes.'

['469']

469:     DataTypes.ReserveDataLegacy memory reserve = _pool.getReserveData(asset); // <= FOUND 'DataTypes.'

['549']

549:   function _updateInterestRateStrategy(
550:     address asset,
551:     DataTypes.ReserveDataLegacy memory reserve, // <= FOUND 'DataTypes.'
552:     address newRateStrategyAddress,
553:     bytes calldata rateData
554:   ) internal {

['575']

575:     DataTypes.ReserveDataLegacy memory reserveData = _pool.getReserveData(asset); // <= FOUND 'DataTypes.'

['38']

38:   
45:   function executeInitReserve(
46:     mapping(address => DataTypes.ReserveData) storage reservesData, // <= FOUND 'DataTypes.'
47:     mapping(uint256 => address) storage reservesList,
48:     DataTypes.InitReserveParams memory params // <= FOUND 'DataTypes.'
49:   ) external returns (bool) {

['84']

84:   
89:   function executeMintToTreasury(
90:     mapping(address => DataTypes.ReserveData) storage reservesData, // <= FOUND 'DataTypes.'
91:     address[] calldata assets
92:   ) external {

['91']

91:       DataTypes.ReserveData storage reserve = reservesData[assetAddress]; // <= FOUND 'DataTypes.'

['117']

117:   
123:   function executeResetIsolationModeTotalDebt(
124:     mapping(address => DataTypes.ReserveData) storage reservesData, // <= FOUND 'DataTypes.'
125:     address asset
126:   ) external {

['132']

132:   
138:   function executeSetLiquidationGracePeriod(
139:     mapping(address => DataTypes.ReserveData) storage reservesData, // <= FOUND 'DataTypes.'
140:     address asset,
141:     uint40 until
142:   ) external {

['146']

146:   
152:   function executeDropReserve(
153:     mapping(address => DataTypes.ReserveData) storage reservesData, // <= FOUND 'DataTypes.'
154:     mapping(uint256 => address) storage reservesList,
155:     address asset
156:   ) external {

['170']

170:   
183:   function executeGetUserAccountData(
184:     mapping(address => DataTypes.ReserveData) storage reservesData, // <= FOUND 'DataTypes.'
185:     mapping(uint256 => address) storage reservesList,
186:     mapping(uint8 => DataTypes.EModeCategory) storage eModeCategories, // <= FOUND 'DataTypes.'
187:     DataTypes.CalculateUserAccountDataParams memory params // <= FOUND 'DataTypes.'
188:   )
189:     external
190:     view
191:     returns (
192:       uint256 totalCollateralBase,
193:       uint256 totalDebtBase,
194:       uint256 availableBorrowsBase,
195:       uint256 currentLiquidationThreshold,
196:       uint256 ltv,
197:       uint256 healthFactor
198:     )
199:   {

['75']

75:   
80:   function setLtv(DataTypes.ReserveConfigurationMap memory self, uint256 ltv) internal pure { // <= FOUND 'DataTypes.'

['86']

86:   
91:   function getLtv(DataTypes.ReserveConfigurationMap memory self) internal pure returns (uint256) { // <= FOUND 'DataTypes.'

['95']

95:   
100:   function setLiquidationThreshold(
101:     DataTypes.ReserveConfigurationMap memory self, // <= FOUND 'DataTypes.'
102:     uint256 threshold
103:   ) internal pure {

['111']

111:   
116:   function getLiquidationThreshold(
117:     DataTypes.ReserveConfigurationMap memory self // <= FOUND 'DataTypes.'
118:   ) internal pure returns (uint256) {

['122']

122:   
127:   function setLiquidationBonus(
128:     DataTypes.ReserveConfigurationMap memory self, // <= FOUND 'DataTypes.'
129:     uint256 bonus
130:   ) internal pure {

['138']

138:   
143:   function getLiquidationBonus(
144:     DataTypes.ReserveConfigurationMap memory self // <= FOUND 'DataTypes.'
145:   ) internal pure returns (uint256) {

['149']

149:   
154:   function setDecimals(
155:     DataTypes.ReserveConfigurationMap memory self, // <= FOUND 'DataTypes.'
156:     uint256 decimals
157:   ) internal pure {

['163']

163:   
168:   function getDecimals(
169:     DataTypes.ReserveConfigurationMap memory self // <= FOUND 'DataTypes.'
170:   ) internal pure returns (uint256) {

['174']

174:   
179:   function setActive(DataTypes.ReserveConfigurationMap memory self, bool active) internal pure { // <= FOUND 'DataTypes.'

['185']

185:   
190:   function getActive(DataTypes.ReserveConfigurationMap memory self) internal pure returns (bool) { // <= FOUND 'DataTypes.'

['194']

194:   
199:   function setFrozen(DataTypes.ReserveConfigurationMap memory self, bool frozen) internal pure { // <= FOUND 'DataTypes.'

['205']

205:   
210:   function getFrozen(DataTypes.ReserveConfigurationMap memory self) internal pure returns (bool) { // <= FOUND 'DataTypes.'

['214']

214:   
219:   function setPaused(DataTypes.ReserveConfigurationMap memory self, bool paused) internal pure { // <= FOUND 'DataTypes.'

['225']

225:   
230:   function getPaused(DataTypes.ReserveConfigurationMap memory self) internal pure returns (bool) { // <= FOUND 'DataTypes.'

['238']

238:   
247:   function setBorrowableInIsolation(
248:     DataTypes.ReserveConfigurationMap memory self, // <= FOUND 'DataTypes.'
249:     bool borrowable
250:   ) internal pure {

['256']

256:   
265:   function getBorrowableInIsolation(
266:     DataTypes.ReserveConfigurationMap memory self // <= FOUND 'DataTypes.'
267:   ) internal pure returns (bool) {

['268']

268:   
274:   function setSiloedBorrowing(
275:     DataTypes.ReserveConfigurationMap memory self, // <= FOUND 'DataTypes.'
276:     bool siloed
277:   ) internal pure {

['283']

283:   
289:   function getSiloedBorrowing(
290:     DataTypes.ReserveConfigurationMap memory self // <= FOUND 'DataTypes.'
291:   ) internal pure returns (bool) {

['294']

294:   
299:   function setBorrowingEnabled(
300:     DataTypes.ReserveConfigurationMap memory self, // <= FOUND 'DataTypes.'
301:     bool enabled
302:   ) internal pure {

['308']

308:   
313:   function getBorrowingEnabled(
314:     DataTypes.ReserveConfigurationMap memory self // <= FOUND 'DataTypes.'
315:   ) internal pure returns (bool) {

['319']

319:   
324:   function setStableRateBorrowingEnabled(
325:     DataTypes.ReserveConfigurationMap memory self, // <= FOUND 'DataTypes.'
326:     bool enabled
327:   ) internal pure {

['333']

333:   
338:   function getStableRateBorrowingEnabled(
339:     DataTypes.ReserveConfigurationMap memory self // <= FOUND 'DataTypes.'
340:   ) internal pure returns (bool) {

['344']

344:   
349:   function setReserveFactor(
350:     DataTypes.ReserveConfigurationMap memory self, // <= FOUND 'DataTypes.'
351:     uint256 reserveFactor
352:   ) internal pure {

['360']

360:   
365:   function getReserveFactor(
366:     DataTypes.ReserveConfigurationMap memory self // <= FOUND 'DataTypes.'
367:   ) internal pure returns (uint256) {

['371']

371:   
376:   function setBorrowCap(
377:     DataTypes.ReserveConfigurationMap memory self, // <= FOUND 'DataTypes.'
378:     uint256 borrowCap
379:   ) internal pure {

['385']

385:   
390:   function getBorrowCap(
391:     DataTypes.ReserveConfigurationMap memory self // <= FOUND 'DataTypes.'
392:   ) internal pure returns (uint256) {

['396']

396:   
401:   function setSupplyCap(
402:     DataTypes.ReserveConfigurationMap memory self, // <= FOUND 'DataTypes.'
403:     uint256 supplyCap
404:   ) internal pure {

['410']

410:   
415:   function getSupplyCap(
416:     DataTypes.ReserveConfigurationMap memory self // <= FOUND 'DataTypes.'
417:   ) internal pure returns (uint256) {

['421']

421:   
426:   function setDebtCeiling(
427:     DataTypes.ReserveConfigurationMap memory self, // <= FOUND 'DataTypes.'
428:     uint256 ceiling
429:   ) internal pure {

['435']

435:   
440:   function getDebtCeiling(
441:     DataTypes.ReserveConfigurationMap memory self // <= FOUND 'DataTypes.'
442:   ) internal pure returns (uint256) {

['446']

446:   
451:   function setLiquidationProtocolFee(
452:     DataTypes.ReserveConfigurationMap memory self, // <= FOUND 'DataTypes.'
453:     uint256 liquidationProtocolFee
454:   ) internal pure {

['465']

465:   
470:   function getLiquidationProtocolFee(
471:     DataTypes.ReserveConfigurationMap memory self // <= FOUND 'DataTypes.'
472:   ) internal pure returns (uint256) {

['477']

477:   
482:   function setUnbackedMintCap(
483:     DataTypes.ReserveConfigurationMap memory self, // <= FOUND 'DataTypes.'
484:     uint256 unbackedMintCap
485:   ) internal pure {

['493']

493:   
498:   function getUnbackedMintCap(
499:     DataTypes.ReserveConfigurationMap memory self // <= FOUND 'DataTypes.'
500:   ) internal pure returns (uint256) {

['504']

504:   
509:   function setEModeCategory(
510:     DataTypes.ReserveConfigurationMap memory self, // <= FOUND 'DataTypes.'
511:     uint256 category
512:   ) internal pure {

['518']

518:   
523:   function getEModeCategory(
524:     DataTypes.ReserveConfigurationMap memory self // <= FOUND 'DataTypes.'
525:   ) internal pure returns (uint256) {

['529']

529:   
534:   function setFlashLoanEnabled(
535:     DataTypes.ReserveConfigurationMap memory self, // <= FOUND 'DataTypes.'
536:     bool flashLoanEnabled
537:   ) internal pure {

['543']

543:   
548:   function getFlashLoanEnabled(
549:     DataTypes.ReserveConfigurationMap memory self // <= FOUND 'DataTypes.'
550:   ) internal pure returns (bool) {

['554']

554:   
559:   function setVirtualAccActive(
560:     DataTypes.ReserveConfigurationMap memory self, // <= FOUND 'DataTypes.'
561:     bool active
562:   ) internal pure {

['568']

568:   
573:   function getIsVirtualAccActive(
574:     DataTypes.ReserveConfigurationMap memory self // <= FOUND 'DataTypes.'
575:   ) internal pure returns (bool) {

['583']

583:   
592:   function getFlags(
593:     DataTypes.ReserveConfigurationMap memory self // <= FOUND 'DataTypes.'
594:   ) internal pure returns (bool, bool, bool, bool, bool) {

['607']

607:   
617:   function getParams(
618:     DataTypes.ReserveConfigurationMap memory self // <= FOUND 'DataTypes.'
619:   ) internal pure returns (uint256, uint256, uint256, uint256, uint256, uint256) {

['628']

628:   
634:   function getCaps(
635:     DataTypes.ReserveConfigurationMap memory self // <= FOUND 'DataTypes.'
636:   ) internal pure returns (uint256, uint256) {

['47']

47:   
54:   function getNormalizedIncome(
55:     DataTypes.ReserveData storage reserve // <= FOUND 'DataTypes.'
56:   ) internal view returns (uint256) {

['71']

71:   
78:   function getNormalizedDebt(
79:     DataTypes.ReserveData storage reserve // <= FOUND 'DataTypes.'
80:   ) internal view returns (uint256) {

['93']

93:   
98:   function updateState(
99:     DataTypes.ReserveData storage reserve, // <= FOUND 'DataTypes.'
100:     DataTypes.ReserveCache memory reserveCache // <= FOUND 'DataTypes.'
101:   ) internal {

['118']

118:   
126:   function cumulateToLiquidityIndex(
127:     DataTypes.ReserveData storage reserve, // <= FOUND 'DataTypes.'
128:     uint256 totalLiquidity,
129:     uint256 amount
130:   ) internal returns (uint256) {

['140']

140:   
148:   function init(
149:     DataTypes.ReserveData storage reserve, // <= FOUND 'DataTypes.'
150:     address aTokenAddress,
151:     address stableDebtTokenAddress,
152:     address variableDebtTokenAddress,
153:     address interestRateStrategyAddress
154:   ) internal {

['172']

172:   
180:   function updateInterestRatesAndVirtualBalance(
181:     DataTypes.ReserveData storage reserve, // <= FOUND 'DataTypes.'
182:     DataTypes.ReserveCache memory reserveCache, // <= FOUND 'DataTypes.'
183:     address reserveAddress,
184:     uint256 liquidityAdded,
185:     uint256 liquidityTaken
186:   ) internal {

['185']

185:     (
186:       vars.nextLiquidityRate,
187:       vars.nextStableRate,
188:       vars.nextVariableRate
189:     ) = IReserveInterestRateStrategy(reserve.interestRateStrategyAddress).calculateInterestRates(
190:       DataTypes.CalculateInterestRatesParams({ // <= FOUND 'DataTypes.'
191:         unbacked: reserve.unbacked,
192:         liquidityAdded: liquidityAdded,
193:         liquidityTaken: liquidityTaken,
194:         totalStableDebt: reserveCache.nextTotalStableDebt,
195:         totalVariableDebt: vars.totalVariableDebt,
196:         averageStableBorrowRate: reserveCache.nextAvgStableBorrowRate,
197:         reserveFactor: reserveCache.reserveFactor,
198:         reserve: reserveAddress,
199:         usingVirtualBalance: reserve.configuration.getIsVirtualAccActive(),
200:         virtualUnderlyingBalance: reserve.virtualUnderlyingBalance
201:       })

['243']

243:   
249:   function _accrueToTreasury(
250:     DataTypes.ReserveData storage reserve, // <= FOUND 'DataTypes.'
251:     DataTypes.ReserveCache memory reserveCache // <= FOUND 'DataTypes.'
252:   ) internal {

['296']

296:   
301:   function _updateIndexes(
302:     DataTypes.ReserveData storage reserve, // <= FOUND 'DataTypes.'
303:     DataTypes.ReserveCache memory reserveCache // <= FOUND 'DataTypes.'
304:   ) internal {

['336']

336:   
342:   function cache(
343:     DataTypes.ReserveData storage reserve // <= FOUND 'DataTypes.'
344:   ) internal view returns (DataTypes.ReserveCache memory) { // <= FOUND 'DataTypes.'

['339']

339:     DataTypes.ReserveCache memory reserveCache; // <= FOUND 'DataTypes.'

['52']

52:   
62:   function executeSupply(
63:     mapping(address => DataTypes.ReserveData) storage reservesData, // <= FOUND 'DataTypes.'
64:     mapping(uint256 => address) storage reservesList,
65:     DataTypes.UserConfigurationMap storage userConfig, // <= FOUND 'DataTypes.'
66:     DataTypes.ExecuteSupplyParams memory params // <= FOUND 'DataTypes.'
67:   ) external {

['106']

106:   
118:   function executeWithdraw(
119:     mapping(address => DataTypes.ReserveData) storage reservesData, // <= FOUND 'DataTypes.'
120:     mapping(uint256 => address) storage reservesList,
121:     mapping(uint8 => DataTypes.EModeCategory) storage eModeCategories, // <= FOUND 'DataTypes.'
122:     DataTypes.UserConfigurationMap storage userConfig, // <= FOUND 'DataTypes.'
123:     DataTypes.ExecuteWithdrawParams memory params // <= FOUND 'DataTypes.'
124:   ) external returns (uint256) {

['179']

179:   
191:   function executeFinalizeTransfer(
192:     mapping(address => DataTypes.ReserveData) storage reservesData, // <= FOUND 'DataTypes.'
193:     mapping(uint256 => address) storage reservesList,
194:     mapping(uint8 => DataTypes.EModeCategory) storage eModeCategories, // <= FOUND 'DataTypes.'
195:     mapping(address => DataTypes.UserConfigurationMap) storage usersConfig, // <= FOUND 'DataTypes.'
196:     DataTypes.FinalizeTransferParams memory params // <= FOUND 'DataTypes.'
197:   ) external {

['194']

194:       DataTypes.UserConfigurationMap storage fromConfig = usersConfig[params.from]; // <= FOUND 'DataTypes.'

['217']

217:         DataTypes.UserConfigurationMap storage toConfig = usersConfig[params.to]; // <= FOUND 'DataTypes.'

['250']

250:   
266:   function executeUseReserveAsCollateral(
267:     mapping(address => DataTypes.ReserveData) storage reservesData, // <= FOUND 'DataTypes.'
268:     mapping(uint256 => address) storage reservesList,
269:     mapping(uint8 => DataTypes.EModeCategory) storage eModeCategories, // <= FOUND 'DataTypes.'
270:     DataTypes.UserConfigurationMap storage userConfig, // <= FOUND 'DataTypes.'
271:     address asset,
272:     bool useAsCollateral,
273:     uint256 reservesCount,
274:     address priceOracle,
275:     uint8 userEModeCategory
276:   ) external {

['66']

66:   
71:   function validateSupply(
72:     DataTypes.ReserveCache memory reserveCache, // <= FOUND 'DataTypes.'
73:     DataTypes.ReserveData storage reserve, // <= FOUND 'DataTypes.'
74:     uint256 amount,
75:     address onBehalfOf
76:   ) internal view {

['98']

98:   
104:   function validateWithdraw(
105:     DataTypes.ReserveCache memory reserveCache, // <= FOUND 'DataTypes.'
106:     uint256 amount,
107:     uint256 userBalance
108:   ) internal pure {

['141']

141:   
148:   function validateBorrow(
149:     mapping(address => DataTypes.ReserveData) storage reservesData, // <= FOUND 'DataTypes.'
150:     mapping(uint256 => address) storage reservesList,
151:     mapping(uint8 => DataTypes.EModeCategory) storage eModeCategories, // <= FOUND 'DataTypes.'
152:     DataTypes.ValidateBorrowParams memory params // <= FOUND 'DataTypes.'
153:   ) internal view {

['176']

176:     
177:     require(
178:       params.interestRateMode == DataTypes.InterestRateMode.VARIABLE || // <= FOUND 'DataTypes.'
179:         params.interestRateMode == DataTypes.InterestRateMode.STABLE, // <= FOUND 'DataTypes.'
180:       Errors.INVALID_INTEREST_RATE_MODE_SELECTED // <= FOUND 'Errors.'
181:     );

['229']

229:     (
230:       vars.userCollateralInBaseCurrency,
231:       vars.userDebtInBaseCurrency,
232:       vars.currentLtv,
233:       ,
234:       vars.healthFactor,
235: 
236:     ) = GenericLogic.calculateUserAccountData(
237:       reservesData,
238:       reservesList,
239:       eModeCategories,
240:       DataTypes.CalculateUserAccountDataParams({ // <= FOUND 'DataTypes.'
241:         userConfig: params.userConfig,
242:         reservesCount: params.reservesCount,
243:         user: params.userAddress,
244:         oracle: params.oracle,
245:         userEModeCategory: params.userEModeCategory
246:       })

['283']

283:     
291:     if (params.interestRateMode == DataTypes.InterestRateMode.STABLE) { // <= FOUND 'DataTypes.'

['329']

329:   
338:   function validateRepay(
339:     DataTypes.ReserveCache memory reserveCache, // <= FOUND 'DataTypes.'
340:     uint256 amountSent,
341:     DataTypes.InterestRateMode interestRateMode, // <= FOUND 'DataTypes.'
342:     address onBehalfOf,
343:     uint256 stableDebt,
344:     uint256 variableDebt
345:   ) internal view {

['347']

347:     require(
348:       (stableDebt != 0 && interestRateMode == DataTypes.InterestRateMode.STABLE) || // <= FOUND 'DataTypes.'
349:         (variableDebt != 0 && interestRateMode == DataTypes.InterestRateMode.VARIABLE), // <= FOUND 'DataTypes.'
350:       Errors.NO_DEBT_OF_SELECTED_TYPE // <= FOUND 'Errors.'
351:     );

['363']

363:   
372:   function validateSwapRateMode(
373:     DataTypes.ReserveData storage reserve, // <= FOUND 'DataTypes.'
374:     DataTypes.ReserveCache memory reserveCache, // <= FOUND 'DataTypes.'
375:     DataTypes.UserConfigurationMap storage userConfig, // <= FOUND 'DataTypes.'
376:     uint256 stableDebt,
377:     uint256 variableDebt,
378:     DataTypes.InterestRateMode currentRateMode // <= FOUND 'DataTypes.'
379:   ) internal view {

['377']

377:     if (currentRateMode == DataTypes.InterestRateMode.STABLE) { // <= FOUND 'DataTypes.'

['379']

379:     } else if (currentRateMode == DataTypes.InterestRateMode.VARIABLE) { // <= FOUND 'DataTypes.'

['409']

409:   
417:   function validateRebalanceStableBorrowRate(
418:     DataTypes.ReserveData storage reserve, // <= FOUND 'DataTypes.'
419:     DataTypes.ReserveCache memory reserveCache, // <= FOUND 'DataTypes.'
420:     address reserveAddress
421:   ) internal view {

['421']

421:     (uint256 liquidityRateVariableDebtOnly, , ) = IReserveInterestRateStrategy(
422:       reserve.interestRateStrategyAddress
423:     ).calculateInterestRates(
424:         DataTypes.CalculateInterestRatesParams({ // <= FOUND 'DataTypes.'
425:           unbacked: reserve.unbacked,
426:           liquidityAdded: 0,
427:           liquidityTaken: 0,
428:           totalStableDebt: 0,
429:           totalVariableDebt: totalDebt,
430:           averageStableBorrowRate: 0,
431:           reserveFactor: reserveCache.reserveFactor,
432:           reserve: reserveAddress,
433:           usingVirtualBalance: reserve.configuration.getIsVirtualAccActive(),
434:           virtualUnderlyingBalance: reserve.virtualUnderlyingBalance
435:         })

['450']

450:   
455:   function validateSetUseReserveAsCollateral(
456:     DataTypes.ReserveCache memory reserveCache, // <= FOUND 'DataTypes.'
457:     uint256 userBalance
458:   ) internal pure {

['467']

467:   
473:   function validateFlashloan(
474:     mapping(address => DataTypes.ReserveData) storage reservesData, // <= FOUND 'DataTypes.'
475:     address[] memory assets,
476:     uint256[] memory amounts
477:   ) internal view {

['482']

482:   
486:   function validateFlashloanSimple(
487:     DataTypes.ReserveData storage reserve, // <= FOUND 'DataTypes.'
488:     uint256 amount
489:   ) internal view {

['486']

486:     DataTypes.ReserveConfigurationMap memory configuration = reserve.configuration; // <= FOUND 'DataTypes.'

['512']

512:   
519:   function validateLiquidationCall(
520:     DataTypes.UserConfigurationMap storage userConfig, // <= FOUND 'DataTypes.'
521:     DataTypes.ReserveData storage collateralReserve, // <= FOUND 'DataTypes.'
522:     DataTypes.ReserveData storage debtReserve, // <= FOUND 'DataTypes.'
523:     DataTypes.ValidateLiquidationCallParams memory params // <= FOUND 'DataTypes.'
524:   ) internal view {

['570']

570:   
581:   function validateHealthFactor(
582:     mapping(address => DataTypes.ReserveData) storage reservesData, // <= FOUND 'DataTypes.'
583:     mapping(uint256 => address) storage reservesList,
584:     mapping(uint8 => DataTypes.EModeCategory) storage eModeCategories, // <= FOUND 'DataTypes.'
585:     DataTypes.UserConfigurationMap memory userConfig, // <= FOUND 'DataTypes.'
586:     address user,
587:     uint8 userEModeCategory,
588:     uint256 reservesCount,
589:     address oracle
590:   ) internal view returns (uint256, bool) {

['580']

580:     (, , , , uint256 healthFactor, bool hasZeroLtvCollateral) = GenericLogic
581:       .calculateUserAccountData(
582:         reservesData,
583:         reservesList,
584:         eModeCategories,
585:         DataTypes.CalculateUserAccountDataParams({ // <= FOUND 'DataTypes.'
586:           userConfig: userConfig,
587:           reservesCount: reservesCount,
588:           user: user,
589:           oracle: oracle,
590:           userEModeCategory: userEModeCategory
591:         })

['614']

614:   
626:   function validateHFAndLtv(
627:     mapping(address => DataTypes.ReserveData) storage reservesData, // <= FOUND 'DataTypes.'
628:     mapping(uint256 => address) storage reservesList,
629:     mapping(uint8 => DataTypes.EModeCategory) storage eModeCategories, // <= FOUND 'DataTypes.'
630:     DataTypes.UserConfigurationMap memory userConfig, // <= FOUND 'DataTypes.'
631:     address asset,
632:     address from,
633:     uint256 reservesCount,
634:     address oracle,
635:     uint8 userEModeCategory
636:   ) internal view {

['625']

625:     DataTypes.ReserveData memory reserve = reservesData[asset]; // <= FOUND 'DataTypes.'

['648']

648:   
652:   function validateTransfer(DataTypes.ReserveData storage reserve) internal view { // <= FOUND 'DataTypes.'

['658']

658:   
664:   function validateDropReserve(
665:     mapping(uint256 => address) storage reservesList,
666:     DataTypes.ReserveData storage reserve, // <= FOUND 'DataTypes.'
667:     address asset
668:   ) internal view {

['685']

685:   
694:   function validateSetUserEMode(
695:     mapping(address => DataTypes.ReserveData) storage reservesData, // <= FOUND 'DataTypes.'
696:     mapping(uint256 => address) storage reservesList,
697:     mapping(uint8 => DataTypes.EModeCategory) storage eModeCategories, // <= FOUND 'DataTypes.'
698:     DataTypes.UserConfigurationMap memory userConfig, // <= FOUND 'DataTypes.'
699:     uint256 reservesCount,
700:     uint8 categoryId
701:   ) internal view {

['710']

710:             DataTypes.ReserveConfigurationMap memory configuration = reservesData[reservesList[i]] // <= FOUND 'DataTypes.'
711:               .configuration;

['731']

731:   
740:   function validateUseAsCollateral(
741:     mapping(address => DataTypes.ReserveData) storage reservesData, // <= FOUND 'DataTypes.'
742:     mapping(uint256 => address) storage reservesList,
743:     DataTypes.UserConfigurationMap storage userConfig, // <= FOUND 'DataTypes.'
744:     DataTypes.ReserveConfigurationMap memory reserveConfig // <= FOUND 'DataTypes.'
745:   ) internal view returns (bool) {

['758']

758:   
768:   function validateAutomaticUseAsCollateral(
769:     mapping(address => DataTypes.ReserveData) storage reservesData, // <= FOUND 'DataTypes.'
770:     mapping(uint256 => address) storage reservesList,
771:     DataTypes.UserConfigurationMap storage userConfig, // <= FOUND 'DataTypes.'
772:     DataTypes.ReserveConfigurationMap memory reserveConfig, // <= FOUND 'DataTypes.'
773:     address aTokenAddress
774:   ) internal view returns (bool) {

['73']

73:     require(
74:       unbacked <= unbackedMintCap * (10 ** reserveDecimals),
75:       Errors.UNBACKED_MINT_CAP_EXCEEDED // <= FOUND 'Errors.'
76:     );

['44']

44:     require(provider != address(0), Errors.INVALID_ADDRESSES_PROVIDER); // <= FOUND 'Errors.'

['49']

49:     require(
50:       msg.sender == ADDRESSES_PROVIDER.getPoolConfigurator(),
51:       Errors.CALLER_NOT_POOL_CONFIGURATOR // <= FOUND 'Errors.'
52:     );

['209']

209:     require(reserve != address(0), Errors.ZERO_ADDRESS_NOT_VALID); // <= FOUND 'Errors.'

['211']

211:     require(
212:       rateData.optimalUsageRatio <= MAX_OPTIMAL_POINT &&
213:         rateData.optimalUsageRatio >= MIN_OPTIMAL_POINT,
214:       Errors.INVALID_OPTIMAL_USAGE_RATIO // <= FOUND 'Errors.'
215:     );

['217']

217:     require(
218:       rateData.variableRateSlope1 <= rateData.variableRateSlope2,
219:       Errors.SLOPE_2_MUST_BE_GTE_SLOPE_1 // <= FOUND 'Errors.'
220:     );

['223']

223:     
224:     require(
225:       uint256(rateData.baseVariableBorrowRate) +
226:         uint256(rateData.variableRateSlope1) +
227:         uint256(rateData.variableRateSlope2) <=
228:         MAX_BORROW_RATE,
229:       Errors.INVALID_MAXRATE // <= FOUND 'Errors.'
230:     );

['112']

112:     require(
113:       vars.receiver.executeOperation(
114:         params.assets,
115:         params.amounts,
116:         vars.totalPremiums,
117:         msg.sender,
118:         params.params
119:       ),
120:       Errors.INVALID_FLASHLOAN_EXECUTOR_RETURN // <= FOUND 'Errors.'
121:     );

['210']

210:     require(
211:       receiver.executeOperation(
212:         params.asset,
213:         params.amount,
214:         totalPremium,
215:         msg.sender,
216:         params.params
217:       ),
218:       Errors.INVALID_FLASHLOAN_EXECUTOR_RETURN // <= FOUND 'Errors.'
219:     );

['69']

69:     require(
70:       ADDRESSES_PROVIDER.getPoolConfigurator() == msg.sender,
71:       Errors.CALLER_NOT_POOL_CONFIGURATOR // <= FOUND 'Errors.'
72:     );

['76']

76:     require(
77:       IACLManager(ADDRESSES_PROVIDER.getACLManager()).isPoolAdmin(msg.sender),
78:       Errors.CALLER_NOT_POOL_ADMIN // <= FOUND 'Errors.'
79:     );

['83']

83:     require(
84:       IACLManager(ADDRESSES_PROVIDER.getACLManager()).isBridge(msg.sender),
85:       Errors.CALLER_NOT_BRIDGE // <= FOUND 'Errors.'
86:     );

['620']

620:     require(msg.sender == _reserves[asset].aTokenAddress, Errors.CALLER_NOT_ATOKEN); // <= FOUND 'Errors.'

['663']

663:     require(asset != address(0), Errors.ZERO_ADDRESS_NOT_VALID); // <= FOUND 'Errors.'

['678']

678:     require(_reserves[asset].id != 0 || _reservesList[0] == asset, Errors.ASSET_NOT_LISTED); // <= FOUND 'Errors.'

['731']

731:     
732:     require(id != 0, Errors.EMODE_CATEGORY_RESERVED); // <= FOUND 'Errors.'

['85']

85:       require(IERC20Detailed(input[i].underlyingAsset).decimals() > 5, Errors.INVALID_DECIMALS); // <= FOUND 'Errors.'

['127']

127:       require(!currentConfig.getStableRateBorrowingEnabled(), Errors.STABLE_BORROWING_ENABLED); // <= FOUND 'Errors.'

['144']

144:     
147:     require(ltv <= liquidationThreshold, Errors.INVALID_RESERVE_PARAMS); // <= FOUND 'Errors.'

['151']

151:       
152:       
153:       require(liquidationBonus > PercentageMath.PERCENTAGE_FACTOR, Errors.INVALID_RESERVE_PARAMS); // <= FOUND 'Errors.'

['155']

155:       
156:       
157:       require(
158:         liquidationThreshold.percentMul(liquidationBonus) <= PercentageMath.PERCENTAGE_FACTOR,
159:         Errors.INVALID_RESERVE_PARAMS // <= FOUND 'Errors.'
160:       );

['160']

160:       require(liquidationBonus == 0, Errors.INVALID_RESERVE_PARAMS); // <= FOUND 'Errors.'

['191']

191:       require(currentConfig.getBorrowingEnabled(), Errors.BORROWING_NOT_ENABLED); // <= FOUND 'Errors.'

['265']

265:       require(gracePeriod <= MAX_GRACE_PERIOD, Errors.INVALID_GRACE_PERIOD); // <= FOUND 'Errors.'

['288']

288:     require(newReserveFactor <= PercentageMath.PERCENTAGE_FACTOR, Errors.INVALID_RESERVE_FACTOR); // <= FOUND 'Errors.'

['370']

370:     require(newFee <= PercentageMath.PERCENTAGE_FACTOR, Errors.INVALID_LIQUIDATION_PROTOCOL_FEE); // <= FOUND 'Errors.'

['387']

387:     require(ltv != 0, Errors.INVALID_EMODE_CATEGORY_PARAMS); // <= FOUND 'Errors.'

['388']

388:     require(liquidationThreshold != 0, Errors.INVALID_EMODE_CATEGORY_PARAMS); // <= FOUND 'Errors.'

['393']

393:     
396:     require(ltv <= liquidationThreshold, Errors.INVALID_EMODE_CATEGORY_PARAMS); // <= FOUND 'Errors.'

['394']

394:     require(
395:       liquidationBonus > PercentageMath.PERCENTAGE_FACTOR,
396:       Errors.INVALID_EMODE_CATEGORY_PARAMS // <= FOUND 'Errors.'
397:     );

['401']

401:     
403:     require(
404:       uint256(liquidationThreshold).percentMul(liquidationBonus) <=
405:         PercentageMath.PERCENTAGE_FACTOR,
406:       Errors.INVALID_EMODE_CATEGORY_PARAMS // <= FOUND 'Errors.'
407:     );

['411']

411:         require(ltv > currentConfig.getLtv(), Errors.INVALID_EMODE_CATEGORY_PARAMS); // <= FOUND 'Errors.'

['412']

412:         require(
413:           liquidationThreshold > currentConfig.getLiquidationThreshold(),
414:           Errors.INVALID_EMODE_CATEGORY_PARAMS // <= FOUND 'Errors.'
415:         );

['441']

441:       require(
442:         categoryData.liquidationThreshold > currentConfig.getLiquidationThreshold(),
443:         Errors.INVALID_EMODE_CATEGORY_ASSIGNMENT // <= FOUND 'Errors.'
444:       );

['501']

501:     require(
502:       newBridgeProtocolFee <= PercentageMath.PERCENTAGE_FACTOR,
503:       Errors.BRIDGE_PROTOCOL_FEE_INVALID // <= FOUND 'Errors.'
504:     );

['514']

514:     require(
515:       newFlashloanPremiumTotal <= PercentageMath.PERCENTAGE_FACTOR,
516:       Errors.FLASHLOAN_PREMIUM_INVALID // <= FOUND 'Errors.'
517:     );

['527']

527:     require(
528:       newFlashloanPremiumToProtocol <= PercentageMath.PERCENTAGE_FACTOR,
529:       Errors.FLASHLOAN_PREMIUM_INVALID // <= FOUND 'Errors.'
530:     );

['579']

579:     require(
580:       totalSupplied == 0 && reserveData.accruedToTreasury == 0,
581:       Errors.RESERVE_LIQUIDITY_NOT_ZERO // <= FOUND 'Errors.'
582:     );

['589']

589:     require(totalDebt == 0, Errors.RESERVE_DEBT_NOT_ZERO); // <= FOUND 'Errors.'

['594']

594:     require(aclManager.isPoolAdmin(msg.sender), Errors.CALLER_NOT_POOL_ADMIN); // <= FOUND 'Errors.'

['599']

599:     require(
600:       aclManager.isPoolAdmin(msg.sender) || aclManager.isEmergencyAdmin(msg.sender),
601:       Errors.CALLER_NOT_POOL_OR_EMERGENCY_ADMIN // <= FOUND 'Errors.'
602:     );

['607']

607:     require(
608:       aclManager.isAssetListingAdmin(msg.sender) || aclManager.isPoolAdmin(msg.sender),
609:       Errors.CALLER_NOT_ASSET_LISTING_OR_POOL_ADMIN // <= FOUND 'Errors.'
610:     );

['615']

615:     require(
616:       aclManager.isRiskAdmin(msg.sender) || aclManager.isPoolAdmin(msg.sender),
617:       Errors.CALLER_NOT_RISK_OR_POOL_ADMIN // <= FOUND 'Errors.'
618:     );

['623']

623:     require(
624:       aclManager.isRiskAdmin(msg.sender) ||
625:         aclManager.isPoolAdmin(msg.sender) ||
626:         aclManager.isEmergencyAdmin(msg.sender),
627:       Errors.CALLER_NOT_RISK_OR_POOL_OR_EMERGENCY_ADMIN // <= FOUND 'Errors.'
628:     );

['21']

21:     require(provider == ADDRESSES_PROVIDER, Errors.INVALID_ADDRESSES_PROVIDER); // <= FOUND 'Errors.'

['43']

43:     require(Address.isContract(params.asset), Errors.NOT_CONTRACT); // <= FOUND 'Errors.'

['53']

53:     require(!reserveAlreadyAdded, Errors.RESERVE_ALREADY_ADDED); // <= FOUND 'Errors.'

['63']

63:     require(params.reservesCount < params.maxNumberReserves, Errors.NO_MORE_RESERVES_ALLOWED); // <= FOUND 'Errors.'

['121']

121:     require(reservesData[asset].configuration.getDebtCeiling() == 0, Errors.DEBT_CEILING_NOT_ZERO); // <= FOUND 'Errors.'

['76']

76:     require(ltv <= MAX_VALID_LTV, Errors.INVALID_LTV); // <= FOUND 'Errors.'

['99']

99:     require(threshold <= MAX_VALID_LIQUIDATION_THRESHOLD, Errors.INVALID_LIQ_THRESHOLD); // <= FOUND 'Errors.'

['126']

126:     require(bonus <= MAX_VALID_LIQUIDATION_BONUS, Errors.INVALID_LIQ_BONUS); // <= FOUND 'Errors.'

['153']

153:     require(decimals <= MAX_VALID_DECIMALS, Errors.INVALID_DECIMALS); // <= FOUND 'Errors.'

['348']

348:     require(reserveFactor <= MAX_VALID_RESERVE_FACTOR, Errors.INVALID_RESERVE_FACTOR); // <= FOUND 'Errors.'

['375']

375:     require(borrowCap <= MAX_VALID_BORROW_CAP, Errors.INVALID_BORROW_CAP); // <= FOUND 'Errors.'

['400']

400:     require(supplyCap <= MAX_VALID_SUPPLY_CAP, Errors.INVALID_SUPPLY_CAP); // <= FOUND 'Errors.'

['425']

425:     require(ceiling <= MAX_VALID_DEBT_CEILING, Errors.INVALID_DEBT_CEILING); // <= FOUND 'Errors.'

['450']

450:     require(
451:       liquidationProtocolFee <= MAX_VALID_LIQUIDATION_PROTOCOL_FEE,
452:       Errors.INVALID_LIQUIDATION_PROTOCOL_FEE // <= FOUND 'Errors.'
453:     );

['481']

481:     require(unbackedMintCap <= MAX_VALID_UNBACKED_MINT_CAP, Errors.INVALID_UNBACKED_MINT_CAP); // <= FOUND 'Errors.'

['508']

508:     require(category <= MAX_VALID_EMODE_CATEGORY, Errors.INVALID_EMODE_CATEGORY); // <= FOUND 'Errors.'

['147']

147:     require(reserve.aTokenAddress == address(0), Errors.RESERVE_ALREADY_INITIALIZED); // <= FOUND 'Errors.'

['116']

116:     require(params.to != reserveCache.aTokenAddress, Errors.WITHDRAW_TO_ATOKEN); // <= FOUND 'Errors.'

['271']

271:       require(
272:         ValidationLogic.validateUseAsCollateral( // <= FOUND 'ValidationLogic.'
273:           reservesData,
274:           reservesList,
275:           userConfig,
276:           reserveCache.reserveConfiguration
277:         ),
278:         Errors.USER_IN_ISOLATION_MODE_OR_LTV_ZERO // <= FOUND 'Errors.'
279:       );

['72']

72:     require(amount != 0, Errors.INVALID_AMOUNT); // <= FOUND 'Errors.'

['77']

77:     require(isActive, Errors.RESERVE_INACTIVE); // <= FOUND 'Errors.'

['78']

78:     require(!isPaused, Errors.RESERVE_PAUSED); // <= FOUND 'Errors.'

['79']

79:     require(!isFrozen, Errors.RESERVE_FROZEN); // <= FOUND 'Errors.'

['80']

80:     require(onBehalfOf != reserveCache.aTokenAddress, Errors.SUPPLY_TO_ATOKEN); // <= FOUND 'Errors.'

['83']

83:     require(
84:       supplyCap == 0 ||
85:         ((IAToken(reserveCache.aTokenAddress).scaledTotalSupply() +
86:           uint256(reserve.accruedToTreasury)).rayMul(reserveCache.nextLiquidityIndex) + amount) <=
87:         supplyCap * (10 ** reserveCache.reserveConfiguration.getDecimals()),
88:       Errors.SUPPLY_CAP_EXCEEDED // <= FOUND 'Errors.'
89:     );

['104']

104:     require(amount <= userBalance, Errors.NOT_ENOUGH_AVAILABLE_USER_BALANCE); // <= FOUND 'Errors.'

['147']

147:     require(params.amount != 0, Errors.INVALID_AMOUNT); // <= FOUND 'Errors.'

['159']

159:     require(vars.isActive, Errors.RESERVE_INACTIVE); // <= FOUND 'Errors.'

['160']

160:     require(!vars.isPaused, Errors.RESERVE_PAUSED); // <= FOUND 'Errors.'

['161']

161:     require(!vars.isFrozen, Errors.RESERVE_FROZEN); // <= FOUND 'Errors.'

['162']

162:     require(vars.borrowingEnabled, Errors.BORROWING_NOT_ENABLED); // <= FOUND 'Errors.'

['163']

163:     require(
164:       !params.reserveCache.reserveConfiguration.getIsVirtualAccActive() ||
165:         IERC20(params.reserveCache.aTokenAddress).totalSupply() >= params.amount,
166:       Errors.INVALID_AMOUNT // <= FOUND 'Errors.'
167:     );

['169']

169:     require(
170:       params.priceOracleSentinel == address(0) ||
171:         IPriceOracleSentinel(params.priceOracleSentinel).isBorrowAllowed(),
172:       Errors.PRICE_ORACLE_SENTINEL_CHECK_FAILED // <= FOUND 'Errors.'
173:     );

['199']

199:         require(vars.totalDebt <= vars.borrowCap * vars.assetUnit, Errors.BORROW_CAP_EXCEEDED); // <= FOUND 'Errors.'

['206']

206:       
207:       
208:       require(
209:         params.reserveCache.reserveConfiguration.getBorrowableInIsolation(),
210:         Errors.ASSET_NOT_BORROWABLE_IN_ISOLATION // <= FOUND 'Errors.'
211:       );

['211']

211:       require(
212:         reservesData[params.isolationModeCollateralAddress].isolationModeTotalDebt +
213:           (params.amount /
214:             10 ** (vars.reserveDecimals - ReserveConfiguration.DEBT_CEILING_DECIMALS)) // <= FOUND 'ReserveConfiguration.'
215:             .toUint128() <=
216:           params.isolationModeDebtCeiling,
217:         Errors.DEBT_CEILING_EXCEEDED // <= FOUND 'Errors.'
218:       );

['222']

222:       require(
223:         params.reserveCache.reserveConfiguration.getEModeCategory() == params.userEModeCategory,
224:         Errors.INCONSISTENT_EMODE_CATEGORY // <= FOUND 'Errors.'
225:       );

['249']

249:     require(vars.userCollateralInBaseCurrency != 0, Errors.COLLATERAL_BALANCE_IS_ZERO); // <= FOUND 'Errors.'

['250']

250:     require(vars.currentLtv != 0, Errors.LTV_VALIDATION_FAILED); // <= FOUND 'Errors.'

['252']

252:     require(
253:       vars.healthFactor > HEALTH_FACTOR_LIQUIDATION_THRESHOLD,
254:       Errors.HEALTH_FACTOR_LOWER_THAN_LIQUIDATION_THRESHOLD // <= FOUND 'Errors.'
255:     );

['270']

270:     require(
271:       vars.collateralNeededInBaseCurrency <= vars.userCollateralInBaseCurrency,
272:       Errors.COLLATERAL_CANNOT_COVER_NEW_BORROW // <= FOUND 'Errors.'
273:     );

['286']

286:       
287: 
288:       require(vars.stableRateBorrowingEnabled, Errors.STABLE_BORROWING_NOT_ENABLED); // <= FOUND 'Errors.'

['288']

288:       require(
289:         !params.userConfig.isUsingAsCollateral(reservesData[params.asset].id) ||
290:           params.reserveCache.reserveConfiguration.getLtv() == 0 ||
291:           params.amount > IERC20(params.reserveCache.aTokenAddress).balanceOf(params.userAddress),
292:         Errors.COLLATERAL_SAME_AS_BORROWING_CURRENCY // <= FOUND 'Errors.'
293:       );

['301']

301:       require(params.amount <= maxLoanSizeStable, Errors.AMOUNT_BIGGER_THAN_MAX_LOAN_SIZE_STABLE); // <= FOUND 'Errors.'

['310']

310:         require(vars.siloedBorrowingAddress == params.asset, Errors.SILOED_BORROWING_VIOLATION); // <= FOUND 'Errors.'

['312']

312:         require(
313:           !params.reserveCache.reserveConfiguration.getSiloedBorrowing(),
314:           Errors.SILOED_BORROWING_VIOLATION // <= FOUND 'Errors.'
315:         );

['337']

337:     require(amountSent != 0, Errors.INVALID_AMOUNT); // <= FOUND 'Errors.'

['338']

338:     require(
339:       amountSent != type(uint256).max || msg.sender == onBehalfOf,
340:       Errors.NO_EXPLICIT_AMOUNT_TO_REPAY_ON_BEHALF // <= FOUND 'Errors.'
341:     );

['378']

378:       require(stableDebt != 0, Errors.NO_OUTSTANDING_STABLE_DEBT); // <= FOUND 'Errors.'

['380']

380:       require(variableDebt != 0, Errors.NO_OUTSTANDING_VARIABLE_DEBT); // <= FOUND 'Errors.'

['388']

388:       
389: 
395:       require(stableRateEnabled, Errors.STABLE_BORROWING_NOT_ENABLED); // <= FOUND 'Errors.'

['390']

390:       require(
391:         !userConfig.isUsingAsCollateral(reserve.id) ||
392:           reserveCache.reserveConfiguration.getLtv() == 0 ||
393:           stableDebt + variableDebt > IERC20(reserveCache.aTokenAddress).balanceOf(msg.sender),
394:         Errors.COLLATERAL_SAME_AS_BORROWING_CURRENCY // <= FOUND 'Errors.'
395:       );

['397']

397:       revert(Errors.INVALID_INTEREST_RATE_MODE_SELECTED); // <= FOUND 'Errors.'

['438']

438:     require(
439:       reserveCache.currLiquidityRate <=
440:         liquidityRateVariableDebtOnly.percentMul(REBALANCE_UP_LIQUIDITY_RATE_THRESHOLD),
441:       Errors.INTEREST_RATE_REBALANCE_CONDITIONS_NOT_MET // <= FOUND 'Errors.'
442:     );

['454']

454:     require(userBalance != 0, Errors.UNDERLYING_BALANCE_ZERO); // <= FOUND 'Errors.'

['472']

472:     require(assets.length == amounts.length, Errors.INCONSISTENT_FLASHLOAN_PARAMS); // <= FOUND 'Errors.'

['487']

487:     require(!configuration.getPaused(), Errors.RESERVE_PAUSED); // <= FOUND 'Errors.'

['488']

488:     require(configuration.getActive(), Errors.RESERVE_INACTIVE); // <= FOUND 'Errors.'

['489']

489:     require(configuration.getFlashLoanEnabled(), Errors.FLASHLOAN_DISABLED); // <= FOUND 'Errors.'

['490']

490:     require(
491:       !configuration.getIsVirtualAccActive() ||
492:         IERC20(reserve.aTokenAddress).totalSupply() >= amount,
493:       Errors.INVALID_AMOUNT // <= FOUND 'Errors.'
494:     );

['529']

529:     require(vars.collateralReserveActive && vars.principalReserveActive, Errors.RESERVE_INACTIVE); // <= FOUND 'Errors.'

['530']

530:     require(!vars.collateralReservePaused && !vars.principalReservePaused, Errors.RESERVE_PAUSED); // <= FOUND 'Errors.'

['532']

532:     require(
533:       params.priceOracleSentinel == address(0) ||
534:         params.healthFactor < MINIMUM_HEALTH_FACTOR_LIQUIDATION_THRESHOLD ||
535:         IPriceOracleSentinel(params.priceOracleSentinel).isLiquidationAllowed(),
536:       Errors.PRICE_ORACLE_SENTINEL_CHECK_FAILED // <= FOUND 'Errors.'
537:     );

['539']

539:     require(
540:       collateralReserve.liquidationGracePeriodUntil < uint40(block.timestamp) &&
541:         debtReserve.liquidationGracePeriodUntil < uint40(block.timestamp),
542:       Errors.LIQUIDATION_GRACE_SENTINEL_CHECK_FAILED // <= FOUND 'Errors.'
543:     );

['545']

545:     require(
546:       params.healthFactor < HEALTH_FACTOR_LIQUIDATION_THRESHOLD,
547:       Errors.HEALTH_FACTOR_NOT_BELOW_THRESHOLD // <= FOUND 'Errors.'
548:     );

['555']

555:     
556:     require(vars.isCollateralEnabled, Errors.COLLATERAL_CANNOT_BE_LIQUIDATED); // <= FOUND 'Errors.'

['556']

556:     require(params.totalDebt != 0, Errors.SPECIFIED_CURRENCY_NOT_BORROWED_BY_USER); // <= FOUND 'Errors.'

['594']

594:     require(
595:       healthFactor >= HEALTH_FACTOR_LIQUIDATION_THRESHOLD,
596:       Errors.HEALTH_FACTOR_LOWER_THAN_LIQUIDATION_THRESHOLD // <= FOUND 'Errors.'
597:     );

['638']

638:     require(
639:       !hasZeroLtvCollateral || reserve.configuration.getLtv() == 0,
640:       Errors.LTV_VALIDATION_FAILED // <= FOUND 'Errors.'
641:     );

['649']

649:     require(!reserve.configuration.getPaused(), Errors.RESERVE_PAUSED); // <= FOUND 'Errors.'

['664']

664:     require(reserve.id != 0 || reservesList[0] == asset, Errors.ASSET_NOT_LISTED); // <= FOUND 'Errors.'

['665']

665:     require(IERC20(reserve.stableDebtTokenAddress).totalSupply() == 0, Errors.STABLE_DEBT_NOT_ZERO); // <= FOUND 'Errors.'

['666']

666:     require(
667:       IERC20(reserve.variableDebtTokenAddress).totalSupply() == 0,
668:       Errors.VARIABLE_DEBT_SUPPLY_NOT_ZERO // <= FOUND 'Errors.'
669:     );

['670']

670:     require(
671:       IERC20(reserve.aTokenAddress).totalSupply() == 0 && reserve.accruedToTreasury == 0,
672:       Errors.UNDERLYING_CLAIMABLE_RIGHTS_NOT_ZERO // <= FOUND 'Errors.'
673:     );

['694']

694:     
695:     require(
696:       categoryId == 0 || eModeCategories[categoryId].liquidationThreshold != 0,
697:       Errors.INCONSISTENT_EMODE_CATEGORY // <= FOUND 'Errors.'
698:     );

['712']

712:             require(
713:               configuration.getEModeCategory() == categoryId,
714:               Errors.INCONSISTENT_EMODE_CATEGORY // <= FOUND 'Errors.'
715:             );

['422']

422:     FlashLoanLogic.executeFlashLoan( // <= FOUND 'FlashLoanLogic.'
423:       _reserves,
424:       _reservesList,
425:       _eModeCategories,
426:       _usersConfig[onBehalfOf],
427:       flashParams
428:     );

['448']

448:     FlashLoanLogic.executeFlashLoanSimple(_reserves[asset], flashParams); // <= FOUND 'FlashLoanLogic.'

['453']

453:     PoolLogic.executeMintToTreasury(_reserves, assets); // <= FOUND 'PoolLogic.'

['669']

669:     PoolLogic.executeDropReserve(_reserves, _reservesList, asset); // <= FOUND 'PoolLogic.'

['767']

767:     PoolLogic.executeResetIsolationModeTotalDebt(_reserves, asset); // <= FOUND 'PoolLogic.'

['781']

781:     PoolLogic.executeSetLiquidationGracePeriod(_reserves, asset, until); // <= FOUND 'PoolLogic.'

['790']

790:     PoolLogic.executeRescueTokens(token, to, amount); // <= FOUND 'PoolLogic.'

['135']

135:       uint256 nextIsolationModeTotalDebt = reservesData[isolationModeCollateralAddress]
136:         .isolationModeTotalDebt += (params.amount /
137:         10 **
138:           (reserveCache.reserveConfiguration.getDecimals() -
139:             ReserveConfiguration.DEBT_CEILING_DECIMALS)).toUint128(); // <= FOUND 'ReserveConfiguration.'

['608']

608:     return ReserveConfiguration.MAX_RESERVES_COUNT; // <= FOUND 'ReserveConfiguration.'

['696']

696:     ReserveLogic.updateInterestRatesAndVirtualBalance(reserve, reserveCache, asset, 0, 0); // <= FOUND 'ReserveLogic.'

['352']

352:     SupplyLogic.executeUseReserveAsCollateral( // <= FOUND 'SupplyLogic.'
353:       _reserves,
354:       _reservesList,
355:       _eModeCategories,
356:       _usersConfig[msg.sender],
357:       asset,
358:       useAsCollateral,
359:       _reservesCount,
360:       ADDRESSES_PROVIDER.getPriceOracle(),
361:       _usersEModeCategory[msg.sender]
362:     );

['196']

196:     ValidationLogic.validateRepay( // <= FOUND 'ValidationLogic.'
197:       reserveCache,
198:       params.amount,
199:       params.interestRateMode,
200:       params.onBehalfOf,
201:       stableDebt,
202:       variableDebt
203:     );

['290']

290:     ValidationLogic.validateRebalanceStableBorrowRate(reserve, reserveCache, asset); // <= FOUND 'ValidationLogic.'

['326']

326:     ValidationLogic.validateSwapRateMode( // <= FOUND 'ValidationLogic.'
327:       reserve,
328:       reserveCache,
329:       userConfig,
330:       stableDebt,
331:       variableDebt,
332:       interestRateMode
333:     );

['66']

66:     ValidationLogic.validateSupply(reserveCache, reserve, amount, onBehalfOf); // <= FOUND 'ValidationLogic.'

['88']

88:       if (
89:         ValidationLogic.validateAutomaticUseAsCollateral( // <= FOUND 'ValidationLogic.'
90:           reservesData,
91:           reservesList,
92:           userConfig,
93:           reserveCache.reserveConfiguration,
94:           reserveCache.aTokenAddress
95:         )
96:       ) {

['82']

82:     
86:     ValidationLogic.validateFlashloan(reservesData, params.assets, params.amounts); // <= FOUND 'ValidationLogic.'

['199']

199:     
203:     ValidationLogic.validateFlashloanSimple(reserve, params.amount); // <= FOUND 'ValidationLogic.'

['303']

303:       if (
304:         ValidationLogic.validateAutomaticUseAsCollateral( // <= FOUND 'ValidationLogic.'
305:           reservesData,
306:           reservesList,
307:           liquidatorConfig,
308:           collateralReserve.configuration,
309:           collateralReserve.aTokenAddress
310:         )
311:       ) {

['152']

152:     ValidationLogic.validateDropReserve(reservesList, reserve, asset); // <= FOUND 'ValidationLogic.'

['63']

63:     ValidationLogic.validateSupply(reserveCache, reserve, params.amount, params.onBehalfOf); // <= FOUND 'ValidationLogic.'

['130']

130:     ValidationLogic.validateWithdraw(reserveCache, amountToWithdraw, userBalance); // <= FOUND 'ValidationLogic.'

['149']

149:       ValidationLogic.validateHFAndLtv( // <= FOUND 'ValidationLogic.'
150:         reservesData,
151:         reservesList,
152:         eModeCategories,
153:         userConfig,
154:         params.asset,
155:         msg.sender,
156:         params.reservesCount,
157:         params.oracle,
158:         params.userEModeCategory
159:       );

['188']

188:     ValidationLogic.validateTransfer(reserve); // <= FOUND 'ValidationLogic.'

['198']

198:           ValidationLogic.validateHFAndLtv( // <= FOUND 'ValidationLogic.'
199:             reservesData,
200:             reservesList,
201:             eModeCategories,
202:             usersConfig[params.from],
203:             params.asset,
204:             params.from,
205:             params.reservesCount,
206:             params.oracle,
207:             params.fromEModeCategory
208:           );

['218']

218:         if (
219:           ValidationLogic.validateAutomaticUseAsCollateral( // <= FOUND 'ValidationLogic.'
220:             reservesData,
221:             reservesList,
222:             toConfig,
223:             reserve.configuration,
224:             reserve.aTokenAddress
225:           )
226:         ) {

['266']

266:     ValidationLogic.validateSetUseReserveAsCollateral(reserveCache, userBalance); // <= FOUND 'ValidationLogic.'

['285']

285:       ValidationLogic.validateHFAndLtv( // <= FOUND 'ValidationLogic.'
286:         reservesData,
287:         reservesList,
288:         eModeCategories,
289:         userConfig,
290:         asset,
291:         msg.sender,
292:         reservesCount,
293:         priceOracle,
294:         userEModeCategory
295:       );

[NonCritical-23] Try catch statement without human readable error

Resolution

In Solidity, the try-catch statement is used for handling exceptions in external function calls and contract creation. However, when a try-catch block doesn't include a catch for specific human-readable errors (using catch Error(string memory reason)), it can miss catching exceptions that provide explanatory error messages. This lack of detailed error handling could hinder debugging and obscure the reasons behind transaction failures. To address this, it's recommended to include a catch block specifically for Error to capture and handle these descriptive error messages effectively. This practice enhances the contract's robustness by providing clearer insights into why certain operations fail, thereby improving maintainability and troubleshooting.

Num of instances: 1

Findings

Click to show findings

['165']

165:     try
166:       IERC20WithPermit(asset).permit(
167:         msg.sender,
168:         address(this),
169:         amount,
170:         deadline,
171:         permitV,
172:         permitR,
173:         permitS
174:       )
175:     {} catch {} // <= FOUND

[NonCritical-24] Simplify complex require statements

Resolution

Simplifying complex require statements with multiple logical OR (||) operators in Solidity can be achieved by using revert statements. This involves converting the conditional logic of require into separate if statements, each followed by a revert for specific failing conditions. This approach enhances readability and maintains clarity, especially when dealing with multiple conditions. It allows for more descriptive error messages for each specific case, improving the debugging process and making the code more maintainable.

Num of instances: 4

Findings

Click to show findings

['623']

623: require(
624:       aclManager.isRiskAdmin(msg.sender) || // <= FOUND
625:         aclManager.isPoolAdmin(msg.sender) || // <= FOUND
626:         aclManager.isEmergencyAdmin(msg.sender),
627:       Errors.CALLER_NOT_RISK_OR_POOL_OR_EMERGENCY_ADMIN
628:     );

['288']

288: require(
289:         !params.userConfig.isUsingAsCollateral(reservesData[params.asset].id) || // <= FOUND
290:           params.reserveCache.reserveConfiguration.getLtv() == 0 || // <= FOUND
291:           params.amount > IERC20(params.reserveCache.aTokenAddress).balanceOf(params.userAddress),
292:         Errors.COLLATERAL_SAME_AS_BORROWING_CURRENCY
293:       );

['390']

390: require(
391:         !userConfig.isUsingAsCollateral(reserve.id) || // <= FOUND
392:           reserveCache.reserveConfiguration.getLtv() == 0 || // <= FOUND
393:           stableDebt + variableDebt > IERC20(reserveCache.aTokenAddress).balanceOf(msg.sender),
394:         Errors.COLLATERAL_SAME_AS_BORROWING_CURRENCY
395:       );

['532']

532: require(
533:       params.priceOracleSentinel == address(0) || // <= FOUND
534:         params.healthFactor < MINIMUM_HEALTH_FACTOR_LIQUIDATION_THRESHOLD || // <= FOUND
535:         IPriceOracleSentinel(params.priceOracleSentinel).isLiquidationAllowed(),
536:       Errors.PRICE_ORACLE_SENTINEL_CHECK_FAILED
537:     );

[NonCritical-25] Constructors should emit an event

Resolution

Emitting an event in a constructor of a smart contract provides transparency and traceability in blockchain applications. This event logs the contract’s creation, aiding in monitoring and verifying contract deployment. Although constructors are executed only once, the emitted event ensures the contract's initialization is recorded on the blockchain.

Num of instances: 2

Findings

Click to show findings

['43']

43:   constructor(address provider) { // <= FOUND
44:     require(provider != address(0), Errors.INVALID_ADDRESSES_PROVIDER);
45:     ADDRESSES_PROVIDER = IPoolAddressesProvider(provider);
46:   }

['93']

93:   constructor(IPoolAddressesProvider provider) { // <= FOUND
94:     ADDRESSES_PROVIDER = provider;
95:   }

[NonCritical-26] Avoid arithmetic directly within array indices

Resolution

Avoiding arithmetic directly within array indices, like test[i + 2], is recommended to prevent errors such as index out of bounds or incorrect data access. This practice enhances code readability and maintainability. Instead, calculate the index beforehand, store it in a variable, and then use that variable to access the array element. This approach reduces mistakes, especially in complex loops or when handling dynamic data, ensuring that each access is clear and verifiable. It's about keeping code clean and understandable, minimizing potential bugs.

Num of instances: 1

Findings

Click to show findings

['563']

563:         reservesList[i - droppedReservesCount] = _reservesList[i]; // <= FOUND

[Gas-1] The result of a function call should be cached rather than re-calling the function

Resolution

External calls in Solidity are costly in terms of gas usage. This can significantly impact contract efficiency and cost. Functions that make repetitive calls to fetch the same data from other contracts can cause unnecessary gas expenditure. To optimize this, it's advisable to store the returned value of these function calls in a state variable, essentially caching the data. This data can be updated at regular intervals or under specific conditions instead of fetching it from the external contract on every invocation. Be sure to analyze the frequency of data change in the external contract to balance data freshness with gas efficiency when implementing caching.

Num of instances: 1

Findings

Click to show findings

['220']

220:   function setReserveFreeze(
221:     address asset,
222:     bool freeze
223:   ) external override onlyRiskOrPoolOrEmergencyAdmins {
224:     DataTypes.ReserveConfigurationMap memory currentConfig = _pool.getConfiguration(asset);
225:     currentConfig.setFrozen(freeze);
226: 
227:     if (freeze) {
228:       _pendingLtv[asset] = currentConfig.getLtv(); // <= FOUND
229:       _isPendingLtvSet[asset] = true;
230:       currentConfig.setLtv(0);
231: 
232:       emit PendingLtvChanged(asset, currentConfig.getLtv()); // <= FOUND
233:     } else if (_isPendingLtvSet[asset]) {
234:       uint256 ltv = _pendingLtv[asset];
235:       currentConfig.setLtv(ltv);
236: 
237:       delete _pendingLtv[asset];
238:       delete _isPendingLtvSet[asset];
239: 
240:       emit PendingLtvRemoved(asset);
241:     }
242: 
243:     _pool.setConfiguration(asset, currentConfig);
244:     emit ReserveFrozen(asset, freeze);
245:   }

[Gas-2] Usage of smaller uint/int types causes overhead

Resolution

When using a smaller int/uint type it first needs to be converted to it's 258 bit counterpart to be operated, this increases the gass cost and thus should be avoided. However it does make sense to use smaller int/uint values within structs provided you pack the struct properly.

Num of instances: 43

Findings

Click to show findings

['68']

68:   function executeBorrow(
69:     mapping(address => DataTypes.ReserveData) storage reservesData,
70:     mapping(uint256 => address) storage reservesList,
71:     mapping(uint8 => DataTypes.EModeCategory) storage eModeCategories, // <= FOUND
72:     DataTypes.UserConfigurationMap storage userConfig,
73:     DataTypes.ExecuteBorrowParams memory params
74:   ) external {
75:     DataTypes.ReserveData storage reserve = reservesData[params.asset];
76:     DataTypes.ReserveCache memory reserveCache = reserve.cache();
77: 
78:     reserve.updateState(reserveCache);
79: 
80:     (
81:       bool isolationModeActive,
82:       address isolationModeCollateralAddress,
83:       uint256 isolationModeDebtCeiling
84:     ) = userConfig.getIsolationModeState(reservesData, reservesList);
85: 
86:     ValidationLogic.validateBorrow(
87:       reservesData,
88:       reservesList,
89:       eModeCategories,
90:       DataTypes.ValidateBorrowParams({
91:         reserveCache: reserveCache,
92:         userConfig: userConfig,
93:         asset: params.asset,
94:         userAddress: params.onBehalfOf,
95:         amount: params.amount,
96:         interestRateMode: params.interestRateMode,
97:         maxStableLoanPercent: params.maxStableRateBorrowSizePercent,
98:         reservesCount: params.reservesCount,
99:         oracle: params.oracle,
100:         userEModeCategory: params.userEModeCategory,
101:         priceOracleSentinel: params.priceOracleSentinel,
102:         isolationModeActive: isolationModeActive,
103:         isolationModeCollateralAddress: isolationModeCollateralAddress,
104:         isolationModeDebtCeiling: isolationModeDebtCeiling
105:       })
106:     );
107: 
108:     uint256 currentStableRate = 0;
109:     bool isFirstBorrowing = false;
110: 
111:     if (params.interestRateMode == DataTypes.InterestRateMode.STABLE) {
112:       currentStableRate = reserve.currentStableBorrowRate;
113: 
114:       (
115:         isFirstBorrowing,
116:         reserveCache.nextTotalStableDebt,
117:         reserveCache.nextAvgStableBorrowRate
118:       ) = IStableDebtToken(reserveCache.stableDebtTokenAddress).mint(
119:         params.user,
120:         params.onBehalfOf,
121:         params.amount,
122:         currentStableRate
123:       );
124:     } else {
125:       (isFirstBorrowing, reserveCache.nextScaledVariableDebt) = IVariableDebtToken(
126:         reserveCache.variableDebtTokenAddress
127:       ).mint(params.user, params.onBehalfOf, params.amount, reserveCache.nextVariableBorrowIndex);
128:     }
129: 
130:     if (isFirstBorrowing) {
131:       userConfig.setBorrowing(reserve.id, true);
132:     }
133: 
134:     if (isolationModeActive) {
135:       uint256 nextIsolationModeTotalDebt = reservesData[isolationModeCollateralAddress]
136:         .isolationModeTotalDebt += (params.amount /
137:         10 **
138:           (reserveCache.reserveConfiguration.getDecimals() -
139:             ReserveConfiguration.DEBT_CEILING_DECIMALS)).toUint128();
140:       emit IsolationModeTotalDebtUpdated(
141:         isolationModeCollateralAddress,
142:         nextIsolationModeTotalDebt
143:       );
144:     }
145: 
146:     reserve.updateInterestRatesAndVirtualBalance(
147:       reserveCache,
148:       params.asset,
149:       0,
150:       params.releaseUnderlying ? params.amount : 0
151:     );
152: 
153:     if (params.releaseUnderlying) {
154:       IAToken(reserveCache.aTokenAddress).transferUnderlyingTo(params.user, params.amount);
155:     }
156: 
157:     emit Borrow(
158:       params.asset,
159:       params.user,
160:       params.onBehalfOf,
161:       params.amount,
162:       params.interestRateMode,
163:       params.interestRateMode == DataTypes.InterestRateMode.STABLE
164:         ? currentStableRate
165:         : reserve.currentVariableBorrowRate,
166:       params.referralCode
167:     );
168:   }

['71']

71:   function executeFlashLoan(
72:     mapping(address => DataTypes.ReserveData) storage reservesData,
73:     mapping(uint256 => address) storage reservesList,
74:     mapping(uint8 => DataTypes.EModeCategory) storage eModeCategories, // <= FOUND
75:     DataTypes.UserConfigurationMap storage userConfig,
76:     DataTypes.FlashloanParams memory params
77:   ) external {
78:     
82:     ValidationLogic.validateFlashloan(reservesData, params.assets, params.amounts);
83: 
84:     FlashLoanLocalVars memory vars;
85: 
86:     vars.totalPremiums = new uint256[](params.assets.length);
87: 
88:     vars.receiver = IFlashLoanReceiver(params.receiverAddress);
89:     (vars.flashloanPremiumTotal, vars.flashloanPremiumToProtocol) = params.isAuthorizedFlashBorrower
90:       ? (0, 0)
91:       : (params.flashLoanPremiumTotal, params.flashLoanPremiumToProtocol);
92: 
93:     for (vars.i = 0; vars.i < params.assets.length; vars.i++) {
94:       vars.currentAmount = params.amounts[vars.i];
95:       vars.totalPremiums[vars.i] = DataTypes.InterestRateMode(params.interestRateModes[vars.i]) ==
96:         DataTypes.InterestRateMode.NONE
97:         ? vars.currentAmount.percentMul(vars.flashloanPremiumTotal)
98:         : 0;
99: 
100:       if (reservesData[params.assets[vars.i]].configuration.getIsVirtualAccActive()) {
101:         reservesData[params.assets[vars.i]].virtualUnderlyingBalance -= vars
102:           .currentAmount
103:           .toUint128();
104:       }
105: 
106:       IAToken(reservesData[params.assets[vars.i]].aTokenAddress).transferUnderlyingTo(
107:         params.receiverAddress,
108:         vars.currentAmount
109:       );
110:     }
111: 
112:     require(
113:       vars.receiver.executeOperation(
114:         params.assets,
115:         params.amounts,
116:         vars.totalPremiums,
117:         msg.sender,
118:         params.params
119:       ),
120:       Errors.INVALID_FLASHLOAN_EXECUTOR_RETURN
121:     );
122: 
123:     for (vars.i = 0; vars.i < params.assets.length; vars.i++) {
124:       vars.currentAsset = params.assets[vars.i];
125:       vars.currentAmount = params.amounts[vars.i];
126: 
127:       if (
128:         DataTypes.InterestRateMode(params.interestRateModes[vars.i]) ==
129:         DataTypes.InterestRateMode.NONE
130:       ) {
131:         _handleFlashLoanRepayment(
132:           reservesData[vars.currentAsset],
133:           DataTypes.FlashLoanRepaymentParams({
134:             asset: vars.currentAsset,
135:             receiverAddress: params.receiverAddress,
136:             amount: vars.currentAmount,
137:             totalPremium: vars.totalPremiums[vars.i],
138:             flashLoanPremiumToProtocol: vars.flashloanPremiumToProtocol,
139:             referralCode: params.referralCode
140:           })
141:         );
142:       } else {
143:         
144:         
145:         BorrowLogic.executeBorrow(
146:           reservesData,
147:           reservesList,
148:           eModeCategories,
149:           userConfig,
150:           DataTypes.ExecuteBorrowParams({
151:             asset: vars.currentAsset,
152:             user: msg.sender,
153:             onBehalfOf: params.onBehalfOf,
154:             amount: vars.currentAmount,
155:             interestRateMode: DataTypes.InterestRateMode(params.interestRateModes[vars.i]),
156:             referralCode: params.referralCode,
157:             releaseUnderlying: false,
158:             maxStableRateBorrowSizePercent: IPool(params.pool)
159:               .MAX_STABLE_RATE_BORROW_SIZE_PERCENT(),
160:             reservesCount: IPool(params.pool).getReservesCount(),
161:             oracle: IPoolAddressesProvider(params.addressesProvider).getPriceOracle(),
162:             userEModeCategory: IPool(params.pool).getUserEMode(params.onBehalfOf).toUint8(),
163:             priceOracleSentinel: IPoolAddressesProvider(params.addressesProvider)
164:               .getPriceOracleSentinel()
165:           })
166:         );
167:         
168:         emit FlashLoan(
169:           params.receiverAddress,
170:           msg.sender,
171:           vars.currentAsset,
172:           vars.currentAmount,
173:           DataTypes.InterestRateMode(params.interestRateModes[vars.i]),
174:           0,
175:           params.referralCode
176:         );
177:       }
178:     }
179:   }

['27']

27:   function supplyWithPermit(bytes32 args, bytes32 r, bytes32 s) external override {
28:     (address asset, uint256 amount, uint16 referralCode, uint256 deadline, uint8 v) = CalldataLogic // <= FOUND
29:       .decodeSupplyWithPermitParams(_reservesList, args);
30: 
31:     supplyWithPermit(asset, amount, msg.sender, referralCode, deadline, v, r, s);
32:   }

['60']

60:   function repayWithPermit(bytes32 args, bytes32 r, bytes32 s) external override returns (uint256) {
61:     (
62:       address asset,
63:       uint256 amount,
64:       uint256 interestRateMode,
65:       uint256 deadline,
66:       uint8 v // <= FOUND
67:     ) = CalldataLogic.decodeRepayWithPermitParams(_reservesList, args);
68: 
69:     return repayWithPermit(asset, amount, interestRateMode, msg.sender, deadline, v, r, s);
70:   }

['96']

96:   function executeLiquidationCall(
97:     mapping(address => DataTypes.ReserveData) storage reservesData,
98:     mapping(uint256 => address) storage reservesList,
99:     mapping(address => DataTypes.UserConfigurationMap) storage usersConfig,
100:     mapping(uint8 => DataTypes.EModeCategory) storage eModeCategories, // <= FOUND
101:     DataTypes.ExecuteLiquidationCallParams memory params
102:   ) external {
103:     LiquidationCallLocalVars memory vars;
104: 
105:     DataTypes.ReserveData storage collateralReserve = reservesData[params.collateralAsset];
106:     DataTypes.ReserveData storage debtReserve = reservesData[params.debtAsset];
107:     DataTypes.UserConfigurationMap storage userConfig = usersConfig[params.user];
108:     vars.debtReserveCache = debtReserve.cache();
109:     debtReserve.updateState(vars.debtReserveCache);
110: 
111:     (, , , , vars.healthFactor, ) = GenericLogic.calculateUserAccountData(
112:       reservesData,
113:       reservesList,
114:       eModeCategories,
115:       DataTypes.CalculateUserAccountDataParams({
116:         userConfig: userConfig,
117:         reservesCount: params.reservesCount,
118:         user: params.user,
119:         oracle: params.priceOracle,
120:         userEModeCategory: params.userEModeCategory
121:       })
122:     );
123: 
124:     (vars.userVariableDebt, vars.userTotalDebt, vars.actualDebtToLiquidate) = _calculateDebt(
125:       vars.debtReserveCache,
126:       params,
127:       vars.healthFactor
128:     );
129: 
130:     ValidationLogic.validateLiquidationCall(
131:       userConfig,
132:       collateralReserve,
133:       debtReserve,
134:       DataTypes.ValidateLiquidationCallParams({
135:         debtReserveCache: vars.debtReserveCache,
136:         totalDebt: vars.userTotalDebt,
137:         healthFactor: vars.healthFactor,
138:         priceOracleSentinel: params.priceOracleSentinel
139:       })
140:     );
141: 
142:     (
143:       vars.collateralAToken,
144:       vars.collateralPriceSource,
145:       vars.debtPriceSource,
146:       vars.liquidationBonus
147:     ) = _getConfigurationData(eModeCategories, collateralReserve, params);
148: 
149:     vars.userCollateralBalance = vars.collateralAToken.balanceOf(params.user);
150: 
151:     (
152:       vars.actualCollateralToLiquidate,
153:       vars.actualDebtToLiquidate,
154:       vars.liquidationProtocolFeeAmount
155:     ) = _calculateAvailableCollateralToLiquidate(
156:       collateralReserve,
157:       vars.debtReserveCache,
158:       vars.collateralPriceSource,
159:       vars.debtPriceSource,
160:       vars.actualDebtToLiquidate,
161:       vars.userCollateralBalance,
162:       vars.liquidationBonus,
163:       IPriceOracleGetter(params.priceOracle)
164:     );
165: 
166:     if (vars.userTotalDebt == vars.actualDebtToLiquidate) {
167:       userConfig.setBorrowing(debtReserve.id, false);
168:     }
169: 
172:     if (
173:       vars.actualCollateralToLiquidate + vars.liquidationProtocolFeeAmount ==
174:       vars.userCollateralBalance
175:     ) {
176:       userConfig.setUsingAsCollateral(collateralReserve.id, false);
177:       emit ReserveUsedAsCollateralDisabled(params.collateralAsset, params.user);
178:     }
179: 
180:     _burnDebtTokens(params, vars);
181: 
182:     debtReserve.updateInterestRatesAndVirtualBalance(
183:       vars.debtReserveCache,
184:       params.debtAsset,
185:       vars.actualDebtToLiquidate,
186:       0
187:     );
188: 
189:     IsolationModeLogic.updateIsolatedDebtIfIsolated(
190:       reservesData,
191:       reservesList,
192:       userConfig,
193:       vars.debtReserveCache,
194:       vars.actualDebtToLiquidate
195:     );
196: 
197:     if (params.receiveAToken) {
198:       _liquidateATokens(reservesData, reservesList, usersConfig, collateralReserve, params, vars);
199:     } else {
200:       _burnCollateralATokens(collateralReserve, params, vars);
201:     }
202: 
204:     if (vars.liquidationProtocolFeeAmount != 0) {
205:       uint256 liquidityIndex = collateralReserve.getNormalizedIncome();
206:       uint256 scaledDownLiquidationProtocolFee = vars.liquidationProtocolFeeAmount.rayDiv(
207:         liquidityIndex
208:       );
209:       uint256 scaledDownUserBalance = vars.collateralAToken.scaledBalanceOf(params.user);
210:       
211:       if (scaledDownLiquidationProtocolFee > scaledDownUserBalance) {
212:         vars.liquidationProtocolFeeAmount = scaledDownUserBalance.rayMul(liquidityIndex);
213:       }
214:       vars.collateralAToken.transferOnLiquidation(
215:         params.user,
216:         vars.collateralAToken.RESERVE_TREASURY_ADDRESS(),
217:         vars.liquidationProtocolFeeAmount
218:       );
219:     }
220: 
222:     IERC20(params.debtAsset).safeTransferFrom(
223:       msg.sender,
224:       vars.debtReserveCache.aTokenAddress,
225:       vars.actualDebtToLiquidate
226:     );
227: 
228:     IAToken(vars.debtReserveCache.aTokenAddress).handleRepayment(
229:       msg.sender,
230:       params.user,
231:       vars.actualDebtToLiquidate
232:     );
233: 
234:     emit LiquidationCall(
235:       params.collateralAsset,
236:       params.debtAsset,
237:       params.user,
238:       vars.actualDebtToLiquidate,
239:       vars.actualCollateralToLiquidate,
240:       msg.sender,
241:       params.receiveAToken
242:     );
243:   }

['399']

399:   function _getConfigurationData(
400:     mapping(uint8 => DataTypes.EModeCategory) storage eModeCategories, // <= FOUND
401:     DataTypes.ReserveData storage collateralReserve,
402:     DataTypes.ExecuteLiquidationCallParams memory params
403:   ) internal view returns (IAToken, address, address, uint256) {
404:     IAToken collateralAToken = IAToken(collateralReserve.aTokenAddress);
405:     uint256 liquidationBonus = collateralReserve.configuration.getLiquidationBonus();
406: 
407:     address collateralPriceSource = params.collateralAsset;
408:     address debtPriceSource = params.debtAsset;
409: 
410:     if (params.userEModeCategory != 0) {
411:       address eModePriceSource = eModeCategories[params.userEModeCategory].priceSource;
412: 
413:       if (
414:         EModeLogic.isInEModeCategory(
415:           params.userEModeCategory,
416:           collateralReserve.configuration.getEModeCategory()
417:         )
418:       ) {
419:         liquidationBonus = eModeCategories[params.userEModeCategory].liquidationBonus;
420: 
421:         if (eModePriceSource != address(0)) {
422:           collateralPriceSource = eModePriceSource;
423:         }
424:       }
425: 
426:       
427:       if (eModePriceSource != address(0)) {
428:         debtPriceSource = eModePriceSource;
429:       }
430:     }
431: 
432:     return (collateralAToken, collateralPriceSource, debtPriceSource, liquidationBonus);
433:   }

['155']

155:   function supplyWithPermit(
156:     address asset,
157:     uint256 amount,
158:     address onBehalfOf,
159:     uint16 referralCode, // <= FOUND
160:     uint256 deadline,
161:     uint8 permitV, // <= FOUND
162:     bytes32 permitR,
163:     bytes32 permitS
164:   ) public virtual override {
165:     try
166:       IERC20WithPermit(asset).permit(
167:         msg.sender,
168:         address(this),
169:         amount,
170:         deadline,
171:         permitV,
172:         permitR,
173:         permitS
174:       )
175:     {} catch {}
176:     SupplyLogic.executeSupply(
177:       _reserves,
178:       _reservesList,
179:       _usersConfig[onBehalfOf],
180:       DataTypes.ExecuteSupplyParams({
181:         asset: asset,
182:         amount: amount,
183:         onBehalfOf: onBehalfOf,
184:         referralCode: referralCode
185:       })
186:     );
187:   }

['265']

265:   function repayWithPermit(
266:     address asset,
267:     uint256 amount,
268:     uint256 interestRateMode,
269:     address onBehalfOf,
270:     uint256 deadline,
271:     uint8 permitV, // <= FOUND
272:     bytes32 permitR,
273:     bytes32 permitS
274:   ) public virtual override returns (uint256) {
275:     try
276:       IERC20WithPermit(asset).permit(
277:         msg.sender,
278:         address(this),
279:         amount,
280:         deadline,
281:         permitV,
282:         permitR,
283:         permitS
284:       )
285:     {} catch {}
286: 
287:     {
288:       DataTypes.ExecuteRepayParams memory params = DataTypes.ExecuteRepayParams({
289:         asset: asset,
290:         amount: amount,
291:         interestRateMode: DataTypes.InterestRateMode(interestRateMode),
292:         onBehalfOf: onBehalfOf,
293:         useATokens: false
294:       });
295:       return BorrowLogic.executeRepay(_reserves, _reservesList, _usersConfig[onBehalfOf], params);
296:     }
297:   }

['726']

726:   function configureEModeCategory(
727:     uint8 id, // <= FOUND
728:     DataTypes.EModeCategory memory category
729:   ) external virtual override onlyPoolConfigurator {
730:     
731:     require(id != 0, Errors.EMODE_CATEGORY_RESERVED);
732:     _eModeCategories[id] = category;
733:   }

['736']

736:   function getEModeCategoryData(
737:     uint8 id // <= FOUND
738:   ) external view virtual override returns (DataTypes.EModeCategory memory) {
739:     return _eModeCategories[id];
740:   }

['743']

743:   function setUserEMode(uint8 categoryId) external virtual override { // <= FOUND
744:     EModeLogic.executeSetUserEMode(
745:       _reserves,
746:       _reservesList,
747:       _eModeCategories,
748:       _usersEModeCategory,
749:       _usersConfig[msg.sender],
750:       DataTypes.ExecuteSetUserEModeParams({
751:         reservesCount: _reservesCount,
752:         oracle: ADDRESSES_PROVIDER.getPriceOracle(),
753:         categoryId: categoryId
754:       })
755:     );
756:   }

['379']

379:   function setEModeCategory(
380:     uint8 categoryId, // <= FOUND
381:     uint16 ltv, // <= FOUND
382:     uint16 liquidationThreshold, // <= FOUND
383:     uint16 liquidationBonus, // <= FOUND
384:     address oracle,
385:     string calldata label
386:   ) external override onlyRiskOrPoolAdmins {
387:     require(ltv != 0, Errors.INVALID_EMODE_CATEGORY_PARAMS);
388:     require(liquidationThreshold != 0, Errors.INVALID_EMODE_CATEGORY_PARAMS);
389: 
393:     require(ltv <= liquidationThreshold, Errors.INVALID_EMODE_CATEGORY_PARAMS);
394:     require(
395:       liquidationBonus > PercentageMath.PERCENTAGE_FACTOR,
396:       Errors.INVALID_EMODE_CATEGORY_PARAMS
397:     );
398: 
401:     require(
402:       uint256(liquidationThreshold).percentMul(liquidationBonus) <=
403:         PercentageMath.PERCENTAGE_FACTOR,
404:       Errors.INVALID_EMODE_CATEGORY_PARAMS
405:     );
406: 
407:     address[] memory reserves = _pool.getReservesList();
408:     for (uint256 i = 0; i < reserves.length; i++) {
409:       DataTypes.ReserveConfigurationMap memory currentConfig = _pool.getConfiguration(reserves[i]);
410:       if (categoryId == currentConfig.getEModeCategory()) {
411:         require(ltv > currentConfig.getLtv(), Errors.INVALID_EMODE_CATEGORY_PARAMS);
412:         require(
413:           liquidationThreshold > currentConfig.getLiquidationThreshold(),
414:           Errors.INVALID_EMODE_CATEGORY_PARAMS
415:         );
416:       }
417:     }
418: 
419:     _pool.configureEModeCategory(
420:       categoryId,
421:       DataTypes.EModeCategory({
422:         ltv: ltv,
423:         liquidationThreshold: liquidationThreshold,
424:         liquidationBonus: liquidationBonus,
425:         priceSource: oracle,
426:         label: label
427:       })
428:     );
429:     emit EModeCategoryAdded(categoryId, ltv, liquidationThreshold, liquidationBonus, oracle, label);
430:   }

['433']

433:   function setAssetEModeCategory(
434:     address asset,
435:     uint8 newCategoryId // <= FOUND
436:   ) external override onlyRiskOrPoolAdmins {
437:     DataTypes.ReserveConfigurationMap memory currentConfig = _pool.getConfiguration(asset);
438: 
439:     if (newCategoryId != 0) {
440:       DataTypes.EModeCategory memory categoryData = _pool.getEModeCategoryData(newCategoryId);
441:       require(
442:         categoryData.liquidationThreshold > currentConfig.getLiquidationThreshold(),
443:         Errors.INVALID_EMODE_CATEGORY_ASSIGNMENT
444:       );
445:     }
446:     uint256 oldCategoryId = currentConfig.getEModeCategory();
447:     currentConfig.setEModeCategory(newCategoryId);
448:     _pool.setConfiguration(asset, currentConfig);
449:     emit EModeAssetCategoryChanged(asset, uint8(oldCategoryId), newCategoryId);
450:   }

['170']

170:   function executeGetUserAccountData(
171:     mapping(address => DataTypes.ReserveData) storage reservesData,
172:     mapping(uint256 => address) storage reservesList,
173:     mapping(uint8 => DataTypes.EModeCategory) storage eModeCategories, // <= FOUND
174:     DataTypes.CalculateUserAccountDataParams memory params
175:   )
176:     external
177:     view
178:     returns (
179:       uint256 totalCollateralBase,
180:       uint256 totalDebtBase,
181:       uint256 availableBorrowsBase,
182:       uint256 currentLiquidationThreshold,
183:       uint256 ltv,
184:       uint256 healthFactor
185:     )
186:   {
187:     (
188:       totalCollateralBase,
189:       totalDebtBase,
190:       ltv,
191:       currentLiquidationThreshold,
192:       healthFactor,
193: 
194:     ) = GenericLogic.calculateUserAccountData(reservesData, reservesList, eModeCategories, params);
195: 
196:     availableBorrowsBase = GenericLogic.calculateAvailableBorrows(
197:       totalCollateralBase,
198:       totalDebtBase,
199:       ltv
200:     );
201:   }

['106']

106:   function executeWithdraw(
107:     mapping(address => DataTypes.ReserveData) storage reservesData,
108:     mapping(uint256 => address) storage reservesList,
109:     mapping(uint8 => DataTypes.EModeCategory) storage eModeCategories, // <= FOUND
110:     DataTypes.UserConfigurationMap storage userConfig,
111:     DataTypes.ExecuteWithdrawParams memory params
112:   ) external returns (uint256) {
113:     DataTypes.ReserveData storage reserve = reservesData[params.asset];
114:     DataTypes.ReserveCache memory reserveCache = reserve.cache();
115: 
116:     require(params.to != reserveCache.aTokenAddress, Errors.WITHDRAW_TO_ATOKEN);
117: 
118:     reserve.updateState(reserveCache);
119: 
120:     uint256 userBalance = IAToken(reserveCache.aTokenAddress).scaledBalanceOf(msg.sender).rayMul(
121:       reserveCache.nextLiquidityIndex
122:     );
123: 
124:     uint256 amountToWithdraw = params.amount;
125: 
126:     if (params.amount == type(uint256).max) {
127:       amountToWithdraw = userBalance;
128:     }
129: 
130:     ValidationLogic.validateWithdraw(reserveCache, amountToWithdraw, userBalance);
131: 
132:     reserve.updateInterestRatesAndVirtualBalance(reserveCache, params.asset, 0, amountToWithdraw);
133: 
134:     bool isCollateral = userConfig.isUsingAsCollateral(reserve.id);
135: 
136:     if (isCollateral && amountToWithdraw == userBalance) {
137:       userConfig.setUsingAsCollateral(reserve.id, false);
138:       emit ReserveUsedAsCollateralDisabled(params.asset, msg.sender);
139:     }
140: 
141:     IAToken(reserveCache.aTokenAddress).burn(
142:       msg.sender,
143:       params.to,
144:       amountToWithdraw,
145:       reserveCache.nextLiquidityIndex
146:     );
147: 
148:     if (isCollateral && userConfig.isBorrowingAny()) {
149:       ValidationLogic.validateHFAndLtv(
150:         reservesData,
151:         reservesList,
152:         eModeCategories,
153:         userConfig,
154:         params.asset,
155:         msg.sender,
156:         params.reservesCount,
157:         params.oracle,
158:         params.userEModeCategory
159:       );
160:     }
161: 
162:     emit Withdraw(params.asset, msg.sender, params.to, amountToWithdraw);
163: 
164:     return amountToWithdraw;
165:   }

['179']

179:   function executeFinalizeTransfer(
180:     mapping(address => DataTypes.ReserveData) storage reservesData,
181:     mapping(uint256 => address) storage reservesList,
182:     mapping(uint8 => DataTypes.EModeCategory) storage eModeCategories, // <= FOUND
183:     mapping(address => DataTypes.UserConfigurationMap) storage usersConfig,
184:     DataTypes.FinalizeTransferParams memory params
185:   ) external {
186:     DataTypes.ReserveData storage reserve = reservesData[params.asset];
187: 
188:     ValidationLogic.validateTransfer(reserve);
189: 
190:     uint256 reserveId = reserve.id;
191:     uint256 scaledAmount = params.amount.rayDiv(reserve.getNormalizedIncome());
192: 
193:     if (params.from != params.to && scaledAmount != 0) {
194:       DataTypes.UserConfigurationMap storage fromConfig = usersConfig[params.from];
195: 
196:       if (fromConfig.isUsingAsCollateral(reserveId)) {
197:         if (fromConfig.isBorrowingAny()) {
198:           ValidationLogic.validateHFAndLtv(
199:             reservesData,
200:             reservesList,
201:             eModeCategories,
202:             usersConfig[params.from],
203:             params.asset,
204:             params.from,
205:             params.reservesCount,
206:             params.oracle,
207:             params.fromEModeCategory
208:           );
209:         }
210:         if (params.balanceFromBefore == params.amount) {
211:           fromConfig.setUsingAsCollateral(reserveId, false);
212:           emit ReserveUsedAsCollateralDisabled(params.asset, params.from);
213:         }
214:       }
215: 
216:       if (params.balanceToBefore == 0) {
217:         DataTypes.UserConfigurationMap storage toConfig = usersConfig[params.to];
218:         if (
219:           ValidationLogic.validateAutomaticUseAsCollateral(
220:             reservesData,
221:             reservesList,
222:             toConfig,
223:             reserve.configuration,
224:             reserve.aTokenAddress
225:           )
226:         ) {
227:           toConfig.setUsingAsCollateral(reserveId, true);
228:           emit ReserveUsedAsCollateralEnabled(params.asset, params.to);
229:         }
230:       }
231:     }
232:   }

['250']

250:   function executeUseReserveAsCollateral(
251:     mapping(address => DataTypes.ReserveData) storage reservesData,
252:     mapping(uint256 => address) storage reservesList,
253:     mapping(uint8 => DataTypes.EModeCategory) storage eModeCategories, // <= FOUND
254:     DataTypes.UserConfigurationMap storage userConfig,
255:     address asset,
256:     bool useAsCollateral,
257:     uint256 reservesCount,
258:     address priceOracle,
259:     uint8 userEModeCategory // <= FOUND
260:   ) external {
261:     DataTypes.ReserveData storage reserve = reservesData[asset];
262:     DataTypes.ReserveCache memory reserveCache = reserve.cache();
263: 
264:     uint256 userBalance = IERC20(reserveCache.aTokenAddress).balanceOf(msg.sender);
265: 
266:     ValidationLogic.validateSetUseReserveAsCollateral(reserveCache, userBalance);
267: 
268:     if (useAsCollateral == userConfig.isUsingAsCollateral(reserve.id)) return;
269: 
270:     if (useAsCollateral) {
271:       require(
272:         ValidationLogic.validateUseAsCollateral(
273:           reservesData,
274:           reservesList,
275:           userConfig,
276:           reserveCache.reserveConfiguration
277:         ),
278:         Errors.USER_IN_ISOLATION_MODE_OR_LTV_ZERO
279:       );
280: 
281:       userConfig.setUsingAsCollateral(reserve.id, true);
282:       emit ReserveUsedAsCollateralEnabled(asset, msg.sender);
283:     } else {
284:       userConfig.setUsingAsCollateral(reserve.id, false);
285:       ValidationLogic.validateHFAndLtv(
286:         reservesData,
287:         reservesList,
288:         eModeCategories,
289:         userConfig,
290:         asset,
291:         msg.sender,
292:         reservesCount,
293:         priceOracle,
294:         userEModeCategory
295:       );
296: 
297:       emit ReserveUsedAsCollateralDisabled(asset, msg.sender);
298:     }
299:   }

['141']

141:   function validateBorrow(
142:     mapping(address => DataTypes.ReserveData) storage reservesData,
143:     mapping(uint256 => address) storage reservesList,
144:     mapping(uint8 => DataTypes.EModeCategory) storage eModeCategories, // <= FOUND
145:     DataTypes.ValidateBorrowParams memory params
146:   ) internal view {
147:     require(params.amount != 0, Errors.INVALID_AMOUNT);
148: 
149:     ValidateBorrowLocalVars memory vars;
150: 
151:     (
152:       vars.isActive,
153:       vars.isFrozen,
154:       vars.borrowingEnabled,
155:       vars.stableRateBorrowingEnabled,
156:       vars.isPaused
157:     ) = params.reserveCache.reserveConfiguration.getFlags();
158: 
159:     require(vars.isActive, Errors.RESERVE_INACTIVE);
160:     require(!vars.isPaused, Errors.RESERVE_PAUSED);
161:     require(!vars.isFrozen, Errors.RESERVE_FROZEN);
162:     require(vars.borrowingEnabled, Errors.BORROWING_NOT_ENABLED);
163:     require(
164:       !params.reserveCache.reserveConfiguration.getIsVirtualAccActive() ||
165:         IERC20(params.reserveCache.aTokenAddress).totalSupply() >= params.amount,
166:       Errors.INVALID_AMOUNT
167:     );
168: 
169:     require(
170:       params.priceOracleSentinel == address(0) ||
171:         IPriceOracleSentinel(params.priceOracleSentinel).isBorrowAllowed(),
172:       Errors.PRICE_ORACLE_SENTINEL_CHECK_FAILED
173:     );
174: 
176:     require(
177:       params.interestRateMode == DataTypes.InterestRateMode.VARIABLE ||
178:         params.interestRateMode == DataTypes.InterestRateMode.STABLE,
179:       Errors.INVALID_INTEREST_RATE_MODE_SELECTED
180:     );
181: 
182:     vars.reserveDecimals = params.reserveCache.reserveConfiguration.getDecimals();
183:     vars.borrowCap = params.reserveCache.reserveConfiguration.getBorrowCap();
184:     unchecked {
185:       vars.assetUnit = 10 ** vars.reserveDecimals;
186:     }
187: 
188:     if (vars.borrowCap != 0) {
189:       vars.totalSupplyVariableDebt = params.reserveCache.currScaledVariableDebt.rayMul(
190:         params.reserveCache.nextVariableBorrowIndex
191:       );
192: 
193:       vars.totalDebt =
194:         params.reserveCache.currTotalStableDebt +
195:         vars.totalSupplyVariableDebt +
196:         params.amount;
197: 
198:       unchecked {
199:         require(vars.totalDebt <= vars.borrowCap * vars.assetUnit, Errors.BORROW_CAP_EXCEEDED);
200:       }
201:     }
202: 
203:     if (params.isolationModeActive) {
204:       
205:       
206:       require(
207:         params.reserveCache.reserveConfiguration.getBorrowableInIsolation(),
208:         Errors.ASSET_NOT_BORROWABLE_IN_ISOLATION
209:       );
210: 
211:       require(
212:         reservesData[params.isolationModeCollateralAddress].isolationModeTotalDebt +
213:           (params.amount /
214:             10 ** (vars.reserveDecimals - ReserveConfiguration.DEBT_CEILING_DECIMALS))
215:             .toUint128() <=
216:           params.isolationModeDebtCeiling,
217:         Errors.DEBT_CEILING_EXCEEDED
218:       );
219:     }
220: 
221:     if (params.userEModeCategory != 0) {
222:       require(
223:         params.reserveCache.reserveConfiguration.getEModeCategory() == params.userEModeCategory,
224:         Errors.INCONSISTENT_EMODE_CATEGORY
225:       );
226:       vars.eModePriceSource = eModeCategories[params.userEModeCategory].priceSource;
227:     }
228: 
229:     (
230:       vars.userCollateralInBaseCurrency,
231:       vars.userDebtInBaseCurrency,
232:       vars.currentLtv,
233:       ,
234:       vars.healthFactor,
235: 
236:     ) = GenericLogic.calculateUserAccountData(
237:       reservesData,
238:       reservesList,
239:       eModeCategories,
240:       DataTypes.CalculateUserAccountDataParams({
241:         userConfig: params.userConfig,
242:         reservesCount: params.reservesCount,
243:         user: params.userAddress,
244:         oracle: params.oracle,
245:         userEModeCategory: params.userEModeCategory
246:       })
247:     );
248: 
249:     require(vars.userCollateralInBaseCurrency != 0, Errors.COLLATERAL_BALANCE_IS_ZERO);
250:     require(vars.currentLtv != 0, Errors.LTV_VALIDATION_FAILED);
251: 
252:     require(
253:       vars.healthFactor > HEALTH_FACTOR_LIQUIDATION_THRESHOLD,
254:       Errors.HEALTH_FACTOR_LOWER_THAN_LIQUIDATION_THRESHOLD
255:     );
256: 
257:     vars.amountInBaseCurrency =
258:       IPriceOracleGetter(params.oracle).getAssetPrice(
259:         vars.eModePriceSource != address(0) ? vars.eModePriceSource : params.asset
260:       ) *
261:       params.amount;
262:     unchecked {
263:       vars.amountInBaseCurrency /= vars.assetUnit;
264:     }
265: 
267:     vars.collateralNeededInBaseCurrency = (vars.userDebtInBaseCurrency + vars.amountInBaseCurrency)
268:       .percentDiv(vars.currentLtv); 
269: 
270:     require(
271:       vars.collateralNeededInBaseCurrency <= vars.userCollateralInBaseCurrency,
272:       Errors.COLLATERAL_CANNOT_COVER_NEW_BORROW
273:     );
274: 
283:     if (params.interestRateMode == DataTypes.InterestRateMode.STABLE) {
284:       
285: 
286:       require(vars.stableRateBorrowingEnabled, Errors.STABLE_BORROWING_NOT_ENABLED);
287: 
288:       require(
289:         !params.userConfig.isUsingAsCollateral(reservesData[params.asset].id) ||
290:           params.reserveCache.reserveConfiguration.getLtv() == 0 ||
291:           params.amount > IERC20(params.reserveCache.aTokenAddress).balanceOf(params.userAddress),
292:         Errors.COLLATERAL_SAME_AS_BORROWING_CURRENCY
293:       );
294: 
295:       vars.availableLiquidity = reservesData[params.asset].virtualUnderlyingBalance;
296: 
297:       
298:       
299:       uint256 maxLoanSizeStable = vars.availableLiquidity.percentMul(params.maxStableLoanPercent);
300: 
301:       require(params.amount <= maxLoanSizeStable, Errors.AMOUNT_BIGGER_THAN_MAX_LOAN_SIZE_STABLE);
302:     }
303: 
304:     if (params.userConfig.isBorrowingAny()) {
305:       (vars.siloedBorrowingEnabled, vars.siloedBorrowingAddress) = params
306:         .userConfig
307:         .getSiloedBorrowingState(reservesData, reservesList);
308: 
309:       if (vars.siloedBorrowingEnabled) {
310:         require(vars.siloedBorrowingAddress == params.asset, Errors.SILOED_BORROWING_VIOLATION);
311:       } else {
312:         require(
313:           !params.reserveCache.reserveConfiguration.getSiloedBorrowing(),
314:           Errors.SILOED_BORROWING_VIOLATION
315:         );
316:       }
317:     }
318:   }

['570']

570:   function validateHealthFactor(
571:     mapping(address => DataTypes.ReserveData) storage reservesData,
572:     mapping(uint256 => address) storage reservesList,
573:     mapping(uint8 => DataTypes.EModeCategory) storage eModeCategories, // <= FOUND
574:     DataTypes.UserConfigurationMap memory userConfig,
575:     address user,
576:     uint8 userEModeCategory, // <= FOUND
577:     uint256 reservesCount,
578:     address oracle
579:   ) internal view returns (uint256, bool) {
580:     (, , , , uint256 healthFactor, bool hasZeroLtvCollateral) = GenericLogic
581:       .calculateUserAccountData(
582:         reservesData,
583:         reservesList,
584:         eModeCategories,
585:         DataTypes.CalculateUserAccountDataParams({
586:           userConfig: userConfig,
587:           reservesCount: reservesCount,
588:           user: user,
589:           oracle: oracle,
590:           userEModeCategory: userEModeCategory
591:         })
592:       );
593: 
594:     require(
595:       healthFactor >= HEALTH_FACTOR_LIQUIDATION_THRESHOLD,
596:       Errors.HEALTH_FACTOR_LOWER_THAN_LIQUIDATION_THRESHOLD
597:     );
598: 
599:     return (healthFactor, hasZeroLtvCollateral);
600:   }

['614']

614:   function validateHFAndLtv(
615:     mapping(address => DataTypes.ReserveData) storage reservesData,
616:     mapping(uint256 => address) storage reservesList,
617:     mapping(uint8 => DataTypes.EModeCategory) storage eModeCategories, // <= FOUND
618:     DataTypes.UserConfigurationMap memory userConfig,
619:     address asset,
620:     address from,
621:     uint256 reservesCount,
622:     address oracle,
623:     uint8 userEModeCategory // <= FOUND
624:   ) internal view {
625:     DataTypes.ReserveData memory reserve = reservesData[asset];
626: 
627:     (, bool hasZeroLtvCollateral) = validateHealthFactor(
628:       reservesData,
629:       reservesList,
630:       eModeCategories,
631:       userConfig,
632:       from,
633:       userEModeCategory,
634:       reservesCount,
635:       oracle
636:     );
637: 
638:     require(
639:       !hasZeroLtvCollateral || reserve.configuration.getLtv() == 0,
640:       Errors.LTV_VALIDATION_FAILED
641:     );
642:   }

['685']

685:   function validateSetUserEMode(
686:     mapping(address => DataTypes.ReserveData) storage reservesData,
687:     mapping(uint256 => address) storage reservesList,
688:     mapping(uint8 => DataTypes.EModeCategory) storage eModeCategories, // <= FOUND
689:     DataTypes.UserConfigurationMap memory userConfig,
690:     uint256 reservesCount,
691:     uint8 categoryId // <= FOUND
692:   ) internal view {
693:     
694:     require(
695:       categoryId == 0 || eModeCategories[categoryId].liquidationThreshold != 0,
696:       Errors.INCONSISTENT_EMODE_CATEGORY
697:     );
698: 
700:     if (userConfig.isEmpty()) {
701:       return;
702:     }
703: 
706:     if (categoryId != 0) {
707:       unchecked {
708:         for (uint256 i = 0; i < reservesCount; i++) {
709:           if (userConfig.isBorrowing(i)) {
710:             DataTypes.ReserveConfigurationMap memory configuration = reservesData[reservesList[i]]
711:               .configuration;
712:             require(
713:               configuration.getEModeCategory() == categoryId,
714:               Errors.INCONSISTENT_EMODE_CATEGORY
715:             );
716:           }
717:         }
718:       }
719:     }
720:   }

['52']

52:   function executeMintUnbacked(
53:     mapping(address => DataTypes.ReserveData) storage reservesData,
54:     mapping(uint256 => address) storage reservesList,
55:     DataTypes.UserConfigurationMap storage userConfig,
56:     address asset,
57:     uint256 amount,
58:     address onBehalfOf,
59:     uint16 referralCode // <= FOUND
60:   ) external {
61:     DataTypes.ReserveData storage reserve = reservesData[asset];
62:     DataTypes.ReserveCache memory reserveCache = reserve.cache();
63: 
64:     reserve.updateState(reserveCache);
65: 
66:     ValidationLogic.validateSupply(reserveCache, reserve, amount, onBehalfOf);
67: 
68:     uint256 unbackedMintCap = reserveCache.reserveConfiguration.getUnbackedMintCap();
69:     uint256 reserveDecimals = reserveCache.reserveConfiguration.getDecimals();
70: 
71:     uint256 unbacked = reserve.unbacked += amount.toUint128();
72: 
73:     require(
74:       unbacked <= unbackedMintCap * (10 ** reserveDecimals),
75:       Errors.UNBACKED_MINT_CAP_EXCEEDED
76:     );
77: 
78:     reserve.updateInterestRatesAndVirtualBalance(reserveCache, asset, 0, 0);
79: 
80:     bool isFirstSupply = IAToken(reserveCache.aTokenAddress).mint(
81:       msg.sender,
82:       onBehalfOf,
83:       amount,
84:       reserveCache.nextLiquidityIndex
85:     );
86: 
87:     if (isFirstSupply) {
88:       if (
89:         ValidationLogic.validateAutomaticUseAsCollateral(
90:           reservesData,
91:           reservesList,
92:           userConfig,
93:           reserveCache.reserveConfiguration,
94:           reserveCache.aTokenAddress
95:         )
96:       ) {
97:         userConfig.setUsingAsCollateral(reserve.id, true);
98:         emit ReserveUsedAsCollateralEnabled(asset, onBehalfOf);
99:       }
100:     }
101: 
102:     emit MintUnbacked(asset, msg.sender, onBehalfOf, amount, referralCode);
103:   }

['17']

17:   function supply(bytes32 args) external override {
18:     (address asset, uint256 amount, uint16 referralCode) = CalldataLogic.decodeSupplyParams( // <= FOUND
19:       _reservesList,
20:       args
21:     );
22: 
23:     supply(asset, amount, msg.sender, referralCode);
24:   }

['42']

42:   function borrow(bytes32 args) external override {
43:     (address asset, uint256 amount, uint256 interestRateMode, uint16 referralCode) = CalldataLogic // <= FOUND
44:       .decodeBorrowParams(_reservesList, args);
45: 
46:     borrow(asset, amount, interestRateMode, referralCode, msg.sender);
47:   }

['107']

107:   function mintUnbacked(
108:     address asset,
109:     uint256 amount,
110:     address onBehalfOf,
111:     uint16 referralCode // <= FOUND
112:   ) external virtual override onlyBridge {
113:     BridgeLogic.executeMintUnbacked(
114:       _reserves,
115:       _reservesList,
116:       _usersConfig[onBehalfOf],
117:       asset,
118:       amount,
119:       onBehalfOf,
120:       referralCode
121:     );
122:   }

['135']

135:   function supply(
136:     address asset,
137:     uint256 amount,
138:     address onBehalfOf,
139:     uint16 referralCode // <= FOUND
140:   ) public virtual override {
141:     SupplyLogic.executeSupply(
142:       _reserves,
143:       _reservesList,
144:       _usersConfig[onBehalfOf],
145:       DataTypes.ExecuteSupplyParams({
146:         asset: asset,
147:         amount: amount,
148:         onBehalfOf: onBehalfOf,
149:         referralCode: referralCode
150:       })
151:     );
152:   }

['213']

213:   function borrow(
214:     address asset,
215:     uint256 amount,
216:     uint256 interestRateMode,
217:     uint16 referralCode, // <= FOUND
218:     address onBehalfOf
219:   ) public virtual override {
220:     BorrowLogic.executeBorrow(
221:       _reserves,
222:       _reservesList,
223:       _eModeCategories,
224:       _usersConfig[onBehalfOf],
225:       DataTypes.ExecuteBorrowParams({
226:         asset: asset,
227:         user: msg.sender,
228:         onBehalfOf: onBehalfOf,
229:         amount: amount,
230:         interestRateMode: DataTypes.InterestRateMode(interestRateMode),
231:         referralCode: referralCode,
232:         releaseUnderlying: true,
233:         maxStableRateBorrowSizePercent: _maxStableRateBorrowSizePercent,
234:         reservesCount: _reservesCount,
235:         oracle: ADDRESSES_PROVIDER.getPriceOracle(),
236:         userEModeCategory: _usersEModeCategory[onBehalfOf],
237:         priceOracleSentinel: ADDRESSES_PROVIDER.getPriceOracleSentinel()
238:       })
239:     );
240:   }

['393']

393:   function flashLoan(
394:     address receiverAddress,
395:     address[] calldata assets,
396:     uint256[] calldata amounts,
397:     uint256[] calldata interestRateModes,
398:     address onBehalfOf,
399:     bytes calldata params,
400:     uint16 referralCode // <= FOUND
401:   ) public virtual override {
402:     DataTypes.FlashloanParams memory flashParams = DataTypes.FlashloanParams({
403:       receiverAddress: receiverAddress,
404:       assets: assets,
405:       amounts: amounts,
406:       interestRateModes: interestRateModes,
407:       onBehalfOf: onBehalfOf,
408:       params: params,
409:       referralCode: referralCode,
410:       flashLoanPremiumToProtocol: _flashLoanPremiumToProtocol,
411:       flashLoanPremiumTotal: _flashLoanPremiumTotal,
412:       maxStableRateBorrowSizePercent: _maxStableRateBorrowSizePercent,
413:       reservesCount: _reservesCount,
414:       addressesProvider: address(ADDRESSES_PROVIDER),
415:       pool: address(this),
416:       userEModeCategory: _usersEModeCategory[onBehalfOf],
417:       isAuthorizedFlashBorrower: IACLManager(ADDRESSES_PROVIDER.getACLManager()).isFlashBorrower(
418:         msg.sender
419:       )
420:     });
421: 
422:     FlashLoanLogic.executeFlashLoan(
423:       _reserves,
424:       _reservesList,
425:       _eModeCategories,
426:       _usersConfig[onBehalfOf],
427:       flashParams
428:     );
429:   }

['432']

432:   function flashLoanSimple(
433:     address receiverAddress,
434:     address asset,
435:     uint256 amount,
436:     bytes calldata params,
437:     uint16 referralCode // <= FOUND
438:   ) public virtual override {
439:     DataTypes.FlashloanSimpleParams memory flashParams = DataTypes.FlashloanSimpleParams({
440:       receiverAddress: receiverAddress,
441:       asset: asset,
442:       amount: amount,
443:       params: params,
444:       referralCode: referralCode,
445:       flashLoanPremiumToProtocol: _flashLoanPremiumToProtocol,
446:       flashLoanPremiumTotal: _flashLoanPremiumTotal
447:     });
448:     FlashLoanLogic.executeFlashLoanSimple(_reserves[asset], flashParams);
449:   }

['582']

582:   function getReserveAddressById(uint16 id) external view returns (address) { // <= FOUND
583:     return _reservesList[id];
584:   }

['795']

795:   function deposit(
796:     address asset,
797:     uint256 amount,
798:     address onBehalfOf,
799:     uint16 referralCode // <= FOUND
800:   ) external virtual override {
801:     SupplyLogic.executeSupply(
802:       _reserves,
803:       _reservesList,
804:       _usersConfig[onBehalfOf],
805:       DataTypes.ExecuteSupplyParams({
806:         asset: asset,
807:         amount: amount,
808:         onBehalfOf: onBehalfOf,
809:         referralCode: referralCode
810:       })
811:     );
812:   }

['38']

38:   function executeInitReserve(
39:     mapping(address => DataTypes.ReserveData) storage reservesData,
40:     mapping(uint256 => address) storage reservesList,
41:     DataTypes.InitReserveParams memory params
42:   ) external returns (bool) {
43:     require(Address.isContract(params.asset), Errors.NOT_CONTRACT);
44:     reservesData[params.asset].init(
45:       params.aTokenAddress,
46:       params.stableDebtAddress,
47:       params.variableDebtAddress,
48:       params.interestRateStrategyAddress
49:     );
50: 
51:     bool reserveAlreadyAdded = reservesData[params.asset].id != 0 ||
52:       reservesList[0] == params.asset;
53:     require(!reserveAlreadyAdded, Errors.RESERVE_ALREADY_ADDED);
54: 
55:     for (uint16 i = 0; i < params.reservesCount; i++) { // <= FOUND
56:       if (reservesList[i] == address(0)) {
57:         reservesData[params.asset].id = i;
58:         reservesList[i] = params.asset;
59:         return false;
60:       }
61:     }
62: 
63:     require(params.reservesCount < params.maxNumberReserves, Errors.NO_MORE_RESERVES_ALLOWED);
64:     reservesData[params.asset].id = params.reservesCount;
65:     reservesList[params.reservesCount] = params.asset;
66:     return true;
67:   }

['68']

68: uint16 public constant MAX_RESERVES_COUNT = 128; // <= FOUND

['776']

776:   function setLiquidationGracePeriod(
777:     address asset,
778:     uint40 until // <= FOUND
779:   ) external virtual override onlyPoolConfigurator {
780:     require(_reserves[asset].id != 0 || _reservesList[0] == asset, Errors.ASSET_NOT_LISTED);
781:     PoolLogic.executeSetLiquidationGracePeriod(_reserves, asset, until);
782:   }

['259']

259:   function setReservePause(
260:     address asset,
261:     bool paused,
262:     uint40 gracePeriod // <= FOUND
263:   ) public override onlyEmergencyOrPoolAdmin {
264:     if (!paused && gracePeriod != 0) {
265:       require(gracePeriod <= MAX_GRACE_PERIOD, Errors.INVALID_GRACE_PERIOD);
266: 
267:       uint40 until = uint40(block.timestamp) + gracePeriod; // <= FOUND
268:       _pool.setLiquidationGracePeriod(asset, until);
269:       emit LiquidationGracePeriodChanged(asset, until);
270:     }
271: 
272:     DataTypes.ReserveConfigurationMap memory currentConfig = _pool.getConfiguration(asset);
273:     currentConfig.setPaused(paused);
274:     _pool.setConfiguration(asset, currentConfig);
275:     emit ReservePaused(asset, paused);
276:   }

['484']

484:   function setPoolPause(bool paused, uint40 gracePeriod) public override onlyEmergencyOrPoolAdmin { // <= FOUND
485:     address[] memory reserves = _pool.getReservesList();
486: 
487:     for (uint256 i = 0; i < reserves.length; i++) {
488:       if (reserves[i] != address(0)) {
489:         setReservePause(reserves[i], paused, gracePeriod);
490:       }
491:     }
492:   }

['132']

132:   function executeSetLiquidationGracePeriod(
133:     mapping(address => DataTypes.ReserveData) storage reservesData,
134:     address asset,
135:     uint40 until // <= FOUND
136:   ) external {
137:     reservesData[asset].liquidationGracePeriodUntil = until;
138:   }

['47']

47:   function getNormalizedIncome(
48:     DataTypes.ReserveData storage reserve
49:   ) internal view returns (uint256) {
50:     uint40 timestamp = reserve.lastUpdateTimestamp; // <= FOUND
51: 
53:     if (timestamp == block.timestamp) {
54:       
55:       return reserve.liquidityIndex;
56:     } else {
57:       return
58:         MathUtils.calculateLinearInterest(reserve.currentLiquidityRate, timestamp).rayMul(
59:           reserve.liquidityIndex
60:         );
61:     }
62:   }

['71']

71:   function getNormalizedDebt(
72:     DataTypes.ReserveData storage reserve
73:   ) internal view returns (uint256) {
74:     uint40 timestamp = reserve.lastUpdateTimestamp; // <= FOUND
75: 
77:     if (timestamp == block.timestamp) {
78:       
79:       return reserve.variableBorrowIndex;
80:     } else {
81:       return
82:         MathUtils.calculateCompoundedInterest(reserve.currentVariableBorrowRate, timestamp).rayMul(
83:           reserve.variableBorrowIndex
84:         );
85:     }
86:   }

['35']

35: uint40 public constant MAX_GRACE_PERIOD = 4 hours; // <= FOUND

['717']

717:   function updateFlashloanPremiums(
718:     uint128 flashLoanPremiumTotal, // <= FOUND
719:     uint128 flashLoanPremiumToProtocol // <= FOUND
720:   ) external virtual override onlyPoolConfigurator {
721:     _flashLoanPremiumTotal = flashLoanPremiumTotal;
722:     _flashLoanPremiumToProtocol = flashLoanPremiumToProtocol;
723:   }

['511']

511:   function updateFlashloanPremiumTotal(
512:     uint128 newFlashloanPremiumTotal // <= FOUND
513:   ) external override onlyPoolAdmin {
514:     require(
515:       newFlashloanPremiumTotal <= PercentageMath.PERCENTAGE_FACTOR,
516:       Errors.FLASHLOAN_PREMIUM_INVALID
517:     );
518:     uint128 oldFlashloanPremiumTotal = _pool.FLASHLOAN_PREMIUM_TOTAL(); // <= FOUND
519:     _pool.updateFlashloanPremiums(newFlashloanPremiumTotal, _pool.FLASHLOAN_PREMIUM_TO_PROTOCOL());
520:     emit FlashloanPremiumTotalUpdated(oldFlashloanPremiumTotal, newFlashloanPremiumTotal);
521:   }

['524']

524:   function updateFlashloanPremiumToProtocol(
525:     uint128 newFlashloanPremiumToProtocol // <= FOUND
526:   ) external override onlyPoolAdmin {
527:     require(
528:       newFlashloanPremiumToProtocol <= PercentageMath.PERCENTAGE_FACTOR,
529:       Errors.FLASHLOAN_PREMIUM_INVALID
530:     );
531:     uint128 oldFlashloanPremiumToProtocol = _pool.FLASHLOAN_PREMIUM_TO_PROTOCOL(); // <= FOUND
532:     _pool.updateFlashloanPremiums(_pool.FLASHLOAN_PREMIUM_TOTAL(), newFlashloanPremiumToProtocol);
533:     emit FlashloanPremiumToProtocolUpdated(
534:       oldFlashloanPremiumToProtocol,
535:       newFlashloanPremiumToProtocol
536:     );
537:   }

[Gas-3] Use != 0 instead of > 0

Resolution

Replace spotted instances with != 0 for uints as this uses less gas

Num of instances: 2

Findings

Click to show findings

['210']

210:       if (liquidityAdded > 0) { // <= FOUND

['213']

213:       if (liquidityTaken > 0) { // <= FOUND

[Gas-4] Default int values are manually reset

Resolution

Using .delete is better than resetting a Solidity variable to its default value manually because it frees up storage space on the Ethereum blockchain, resulting in gas cost savings.

Num of instances: 4

Findings

Click to show findings

['130']

130:     vars.currentLiquidityRate = 0; // <= FOUND

['93']

93:     for (vars.i = 0; vars.i < params.assets.length; vars.i++) { // <= FOUND

['101']

101:         reserve.accruedToTreasury = 0; // <= FOUND

['122']

122:     reservesData[asset].isolationModeTotalDebt = 0; // <= FOUND

[Gas-5] Function calls within for loops

Resolution

Making function calls or external calls within loops in Solidity can lead to inefficient gas usage, potential bottlenecks, and increased vulnerability to attacks. Each function call or external call consumes gas, and when executed within a loop, the gas cost multiplies, potentially causing the transaction to run out of gas or exceed block gas limits. This can result in transaction failure or unpredictable behavior.

Num of instances: 14

Findings

Click to show findings

['123']

123:     for (vars.i = 0; vars.i < params.assets.length; vars.i++) {
124:       vars.currentAsset = params.assets[vars.i];
125:       vars.currentAmount = params.amounts[vars.i];
126: 
127:       if (
128:         DataTypes.InterestRateMode(params.interestRateModes[vars.i]) ==
129:         DataTypes.InterestRateMode.NONE
130:       ) {
131:         _handleFlashLoanRepayment( // <= FOUND
132:           reservesData[vars.currentAsset],
133:           DataTypes.FlashLoanRepaymentParams({
134:             asset: vars.currentAsset,
135:             receiverAddress: params.receiverAddress,
136:             amount: vars.currentAmount,
137:             totalPremium: vars.totalPremiums[vars.i],
138:             flashLoanPremiumToProtocol: vars.flashloanPremiumToProtocol,
139:             referralCode: params.referralCode
140:           })
141:         );
142:       } else {
143:         
144:         
145:         BorrowLogic.executeBorrow( // <= FOUND
146:           reservesData,
147:           reservesList,
148:           eModeCategories,
149:           userConfig,
150:           DataTypes.ExecuteBorrowParams({
151:             asset: vars.currentAsset,
152:             user: msg.sender,
153:             onBehalfOf: params.onBehalfOf,
154:             amount: vars.currentAmount,
155:             interestRateMode: DataTypes.InterestRateMode(params.interestRateModes[vars.i]),
156:             referralCode: params.referralCode,
157:             releaseUnderlying: false,
158:             maxStableRateBorrowSizePercent: IPool(params.pool)
159:               .MAX_STABLE_RATE_BORROW_SIZE_PERCENT(), // <= FOUND
160:             reservesCount: IPool(params.pool).getReservesCount(), // <= FOUND
161:             oracle: IPoolAddressesProvider(params.addressesProvider).getPriceOracle(),
162:             userEModeCategory: IPool(params.pool).getUserEMode(params.onBehalfOf).toUint8(), // <= FOUND
163:             priceOracleSentinel: IPoolAddressesProvider(params.addressesProvider)
164:               .getPriceOracleSentinel()
165:           })
166:         );
167:         
168:         emit FlashLoan(
169:           params.receiverAddress,
170:           msg.sender,
171:           vars.currentAsset,
172:           vars.currentAmount,
173:           DataTypes.InterestRateMode(params.interestRateModes[vars.i]),
174:           0,
175:           params.referralCode
176:         );
177:       }
178:     }

['84']

84:    for (uint256 i = 0; i < input.length; i++) {
85:       require(IERC20Detailed(input[i].underlyingAsset).decimals() > 5, Errors.INVALID_DECIMALS);
86: 
87:       ConfiguratorLogic.executeInitReserve(cachedPool, input[i]); // <= FOUND
88:       emit ReserveInterestRateDataChanged(
89:         input[i].underlyingAsset,
90:         input[i].interestRateStrategyAddress,
91:         input[i].interestRateData
92:       );
93:     }

['84']

84:     for (uint256 i = 0; i < input.length; i++) {
85:       require(IERC20Detailed(input[i].underlyingAsset).decimals() > 5, Errors.INVALID_DECIMALS);
86: 
87:       ConfiguratorLogic.executeInitReserve(cachedPool, input[i]); // <= FOUND
88:       emit ReserveInterestRateDataChanged(
89:         input[i].underlyingAsset,
90:         input[i].interestRateStrategyAddress,
91:         input[i].interestRateData
92:       );
93:     }

['88']

88:    for (uint256 i = 0; i < assets.length; i++) {
89:       address assetAddress = assets[i];
90: 
91:       DataTypes.ReserveData storage reserve = reservesData[assetAddress];
92: 
93:       
94:       if (!reserve.configuration.getActive()) { // <= FOUND
95:         continue;
96:       }
97: 
98:       uint256 accruedToTreasury = reserve.accruedToTreasury;
99: 
100:       if (accruedToTreasury != 0) {
101:         reserve.accruedToTreasury = 0;
102:         uint256 normalizedIncome = reserve.getNormalizedIncome(); // <= FOUND
103:         uint256 amountToMint = accruedToTreasury.rayMul(normalizedIncome);
104:         IAToken(reserve.aTokenAddress).mintToTreasury(amountToMint, normalizedIncome); // <= FOUND
105: 
106:         emit MintedToTreasury(assetAddress, amountToMint);
107:       }
108:     }

['88']

88:     for (uint256 i = 0; i < assets.length; i++) {
89:       address assetAddress = assets[i];
90: 
91:       DataTypes.ReserveData storage reserve = reservesData[assetAddress];
92: 
93:       
94:       if (!reserve.configuration.getActive()) { // <= FOUND
95:         continue;
96:       }
97: 
98:       uint256 accruedToTreasury = reserve.accruedToTreasury;
99: 
100:       if (accruedToTreasury != 0) {
101:         reserve.accruedToTreasury = 0;
102:         uint256 normalizedIncome = reserve.getNormalizedIncome(); // <= FOUND
103:         uint256 amountToMint = accruedToTreasury.rayMul(normalizedIncome);
104:         IAToken(reserve.aTokenAddress).mintToTreasury(amountToMint, normalizedIncome); // <= FOUND
105: 
106:         emit MintedToTreasury(assetAddress, amountToMint);
107:       }
108:     }

['408']

408:    for (uint256 i = 0; i < reserves.length; i++) {
409:       DataTypes.ReserveConfigurationMap memory currentConfig = _pool.getConfiguration(reserves[i]); // <= FOUND
410:       if (categoryId == currentConfig.getEModeCategory()) { // <= FOUND
411:         require(ltv > currentConfig.getLtv(), Errors.INVALID_EMODE_CATEGORY_PARAMS); // <= FOUND
412:         require(
413:           liquidationThreshold > currentConfig.getLiquidationThreshold(), // <= FOUND
414:           Errors.INVALID_EMODE_CATEGORY_PARAMS
415:         );
416:       }
417:     }

['408']

408:     for (uint256 i = 0; i < reserves.length; i++) {
409:       DataTypes.ReserveConfigurationMap memory currentConfig = _pool.getConfiguration(reserves[i]); // <= FOUND
410:       if (categoryId == currentConfig.getEModeCategory()) { // <= FOUND
411:         require(ltv > currentConfig.getLtv(), Errors.INVALID_EMODE_CATEGORY_PARAMS); // <= FOUND
412:         require(
413:           liquidationThreshold > currentConfig.getLiquidationThreshold(), // <= FOUND
414:           Errors.INVALID_EMODE_CATEGORY_PARAMS
415:         );
416:       }
417:     }

['487']

487:    for (uint256 i = 0; i < reserves.length; i++) {
488:       if (reserves[i] != address(0)) {
489:         setReservePause(reserves[i], paused, gracePeriod); // <= FOUND
490:       }
491:     }

['487']

487:     for (uint256 i = 0; i < reserves.length; i++) {
488:       if (reserves[i] != address(0)) {
489:         setReservePause(reserves[i], paused, gracePeriod); // <= FOUND
490:       }
491:     }

['708']

708:         for (uint256 i = 0; i < reservesCount; i++) {
709:           if (userConfig.isBorrowing(i)) {
710:             DataTypes.ReserveConfigurationMap memory configuration = reservesData[reservesList[i]]
711:               .configuration;
712:             require(
713:               configuration.getEModeCategory() == categoryId, // <= FOUND
714:               Errors.INCONSISTENT_EMODE_CATEGORY
715:             );
716:           }
717:         }

['93']

93:    for (vars.i = 0; vars.i < params.assets.length; vars.i++) {
94:       vars.currentAmount = params.amounts[vars.i];
95:       vars.totalPremiums[vars.i] = DataTypes.InterestRateMode(params.interestRateModes[vars.i]) ==
96:         DataTypes.InterestRateMode.NONE
97:         ? vars.currentAmount.percentMul(vars.flashloanPremiumTotal)
98:         : 0;
99: 
100:       if (reservesData[params.assets[vars.i]].configuration.getIsVirtualAccActive()) { // <= FOUND
101:         reservesData[params.assets[vars.i]].virtualUnderlyingBalance -= vars
102:           .currentAmount
103:           .toUint128();
104:       }
105: 
106:       IAToken(reservesData[params.assets[vars.i]].aTokenAddress).transferUnderlyingTo(
107:         params.receiverAddress,
108:         vars.currentAmount
109:       );
110:     }

['93']

93:     for (vars.i = 0; vars.i < params.assets.length; vars.i++) {
94:       vars.currentAmount = params.amounts[vars.i];
95:       vars.totalPremiums[vars.i] = DataTypes.InterestRateMode(params.interestRateModes[vars.i]) ==
96:         DataTypes.InterestRateMode.NONE
97:         ? vars.currentAmount.percentMul(vars.flashloanPremiumTotal)
98:         : 0;
99: 
100:       if (reservesData[params.assets[vars.i]].configuration.getIsVirtualAccActive()) { // <= FOUND
101:         reservesData[params.assets[vars.i]].virtualUnderlyingBalance -= vars
102:           .currentAmount
103:           .toUint128();
104:       }
105: 
106:       IAToken(reservesData[params.assets[vars.i]].aTokenAddress).transferUnderlyingTo(
107:         params.receiverAddress,
108:         vars.currentAmount
109:       );
110:     }

['473']

473:    for (uint256 i = 0; i < assets.length; i++) {
474:       validateFlashloanSimple(reservesData[assets[i]], amounts[i]); // <= FOUND
475:     }

['473']

473:     for (uint256 i = 0; i < assets.length; i++) {
474:       validateFlashloanSimple(reservesData[assets[i]], amounts[i]); // <= FOUND
475:     }

[Gas-6] Use assembly to check for the zero address

Resolution

Using assembly for address comparisons in Solidity can save gas because it allows for more direct access to the Ethereum Virtual Machine (EVM), reducing the overhead of higher-level operations. Solidity's high-level abstraction simplifies coding but can introduce additional gas costs. Using assembly for simple operations like address comparisons can be more gas-efficient.

Num of instances: 11

Findings

Click to show findings

['208']

208:   function _setInterestRateParams(address reserve, InterestRateData memory rateData) internal {
209:     require(reserve != address(0), Errors.ZERO_ADDRESS_NOT_VALID); // <= FOUND
210: 
211:     require(
212:       rateData.optimalUsageRatio <= MAX_OPTIMAL_POINT &&
213:         rateData.optimalUsageRatio >= MIN_OPTIMAL_POINT,
214:       Errors.INVALID_OPTIMAL_USAGE_RATIO
215:     );
216: 
217:     require(
218:       rateData.variableRateSlope1 <= rateData.variableRateSlope2,
219:       Errors.SLOPE_2_MUST_BE_GTE_SLOPE_1
220:     );
221: 
223:     require(
224:       uint256(rateData.baseVariableBorrowRate) +
225:         uint256(rateData.variableRateSlope1) +
226:         uint256(rateData.variableRateSlope2) <=
227:         MAX_BORROW_RATE,
228:       Errors.INVALID_MAXRATE
229:     );
230: 
231:     _interestRateData[reserve] = rateData;
232:     emit RateDataUpdate(
233:       reserve,
234:       rateData.optimalUsageRatio,
235:       rateData.baseVariableBorrowRate,
236:       rateData.variableRateSlope1,
237:       rateData.variableRateSlope2
238:     );
239:   }

['399']

399:   function _getConfigurationData(
400:     mapping(uint8 => DataTypes.EModeCategory) storage eModeCategories,
401:     DataTypes.ReserveData storage collateralReserve,
402:     DataTypes.ExecuteLiquidationCallParams memory params
403:   ) internal view returns (IAToken, address, address, uint256) {
404:     IAToken collateralAToken = IAToken(collateralReserve.aTokenAddress);
405:     uint256 liquidationBonus = collateralReserve.configuration.getLiquidationBonus();
406: 
407:     address collateralPriceSource = params.collateralAsset;
408:     address debtPriceSource = params.debtAsset;
409: 
410:     if (params.userEModeCategory != 0) {
411:       address eModePriceSource = eModeCategories[params.userEModeCategory].priceSource;
412: 
413:       if (
414:         EModeLogic.isInEModeCategory(
415:           params.userEModeCategory,
416:           collateralReserve.configuration.getEModeCategory()
417:         )
418:       ) {
419:         liquidationBonus = eModeCategories[params.userEModeCategory].liquidationBonus;
420: 
421:         if (eModePriceSource != address(0)) { // <= FOUND
422:           collateralPriceSource = eModePriceSource;
423:         }
424:       }
425: 
426:       
427:       if (eModePriceSource != address(0)) { // <= FOUND
428:         debtPriceSource = eModePriceSource;
429:       }
430:     }
431: 
432:     return (collateralAToken, collateralPriceSource, debtPriceSource, liquidationBonus);
433:   }

['673']

673:   function setReserveInterestRateStrategyAddress(
674:     address asset,
675:     address rateStrategyAddress
676:   ) external virtual override onlyPoolConfigurator {
677:     require(asset != address(0), Errors.ZERO_ADDRESS_NOT_VALID); // <= FOUND
678:     require(_reserves[asset].id != 0 || _reservesList[0] == asset, Errors.ASSET_NOT_LISTED);
679: 
680:     _reserves[asset].interestRateStrategyAddress = rateStrategyAddress;
681:   }

['700']

700:   function setConfiguration(
701:     address asset,
702:     DataTypes.ReserveConfigurationMap calldata configuration
703:   ) external virtual override onlyPoolConfigurator {
704:     require(asset != address(0), Errors.ZERO_ADDRESS_NOT_VALID); // <= FOUND
705:     require(_reserves[asset].id != 0 || _reservesList[0] == asset, Errors.ASSET_NOT_LISTED);
706:     _reserves[asset].configuration = configuration;
707:   }

['484']

484:   function setPoolPause(bool paused, uint40 gracePeriod) public override onlyEmergencyOrPoolAdmin {
485:     address[] memory reserves = _pool.getReservesList();
486: 
487:     for (uint256 i = 0; i < reserves.length; i++) {
488:       if (reserves[i] != address(0)) { // <= FOUND
489:         setReservePause(reserves[i], paused, gracePeriod);
490:       }
491:     }
492:   }

['38']

38:   function executeInitReserve(
39:     mapping(address => DataTypes.ReserveData) storage reservesData,
40:     mapping(uint256 => address) storage reservesList,
41:     DataTypes.InitReserveParams memory params
42:   ) external returns (bool) {
43:     require(Address.isContract(params.asset), Errors.NOT_CONTRACT);
44:     reservesData[params.asset].init(
45:       params.aTokenAddress,
46:       params.stableDebtAddress,
47:       params.variableDebtAddress,
48:       params.interestRateStrategyAddress
49:     );
50: 
51:     bool reserveAlreadyAdded = reservesData[params.asset].id != 0 ||
52:       reservesList[0] == params.asset;
53:     require(!reserveAlreadyAdded, Errors.RESERVE_ALREADY_ADDED);
54: 
55:     for (uint16 i = 0; i < params.reservesCount; i++) {
56:       if (reservesList[i] == address(0)) { // <= FOUND
57:         reservesData[params.asset].id = i;
58:         reservesList[i] = params.asset;
59:         return false;
60:       }
61:     }
62: 
63:     require(params.reservesCount < params.maxNumberReserves, Errors.NO_MORE_RESERVES_ALLOWED);
64:     reservesData[params.asset].id = params.reservesCount;
65:     reservesList[params.reservesCount] = params.asset;
66:     return true;
67:   }

['146']

146:   function executeDropReserve(
147:     mapping(address => DataTypes.ReserveData) storage reservesData,
148:     mapping(uint256 => address) storage reservesList,
149:     address asset
150:   ) external {
151:     DataTypes.ReserveData storage reserve = reservesData[asset];
152:     ValidationLogic.validateDropReserve(reservesList, reserve, asset);
153:     reservesList[reservesData[asset].id] = address(0); // <= FOUND
154:     delete reservesData[asset];
155:   }

['140']

140:   function init(
141:     DataTypes.ReserveData storage reserve,
142:     address aTokenAddress,
143:     address stableDebtTokenAddress,
144:     address variableDebtTokenAddress,
145:     address interestRateStrategyAddress
146:   ) internal {
147:     require(reserve.aTokenAddress == address(0), Errors.RESERVE_ALREADY_INITIALIZED); // <= FOUND
148: 
149:     reserve.liquidityIndex = uint128(WadRayMath.RAY);
150:     reserve.variableBorrowIndex = uint128(WadRayMath.RAY);
151:     reserve.aTokenAddress = aTokenAddress;
152:     reserve.stableDebtTokenAddress = stableDebtTokenAddress;
153:     reserve.variableDebtTokenAddress = variableDebtTokenAddress;
154:     reserve.interestRateStrategyAddress = interestRateStrategyAddress;
155:   }

['141']

141:   function validateBorrow(
142:     mapping(address => DataTypes.ReserveData) storage reservesData,
143:     mapping(uint256 => address) storage reservesList,
144:     mapping(uint8 => DataTypes.EModeCategory) storage eModeCategories,
145:     DataTypes.ValidateBorrowParams memory params
146:   ) internal view {
147:     require(params.amount != 0, Errors.INVALID_AMOUNT);
148: 
149:     ValidateBorrowLocalVars memory vars;
150: 
151:     (
152:       vars.isActive,
153:       vars.isFrozen,
154:       vars.borrowingEnabled,
155:       vars.stableRateBorrowingEnabled,
156:       vars.isPaused
157:     ) = params.reserveCache.reserveConfiguration.getFlags();
158: 
159:     require(vars.isActive, Errors.RESERVE_INACTIVE);
160:     require(!vars.isPaused, Errors.RESERVE_PAUSED);
161:     require(!vars.isFrozen, Errors.RESERVE_FROZEN);
162:     require(vars.borrowingEnabled, Errors.BORROWING_NOT_ENABLED);
163:     require(
164:       !params.reserveCache.reserveConfiguration.getIsVirtualAccActive() ||
165:         IERC20(params.reserveCache.aTokenAddress).totalSupply() >= params.amount,
166:       Errors.INVALID_AMOUNT
167:     );
168: 
169:     require(
170:       params.priceOracleSentinel == address(0) || // <= FOUND
171:         IPriceOracleSentinel(params.priceOracleSentinel).isBorrowAllowed(),
172:       Errors.PRICE_ORACLE_SENTINEL_CHECK_FAILED
173:     );
174: 
176:     require(
177:       params.interestRateMode == DataTypes.InterestRateMode.VARIABLE ||
178:         params.interestRateMode == DataTypes.InterestRateMode.STABLE,
179:       Errors.INVALID_INTEREST_RATE_MODE_SELECTED
180:     );
181: 
182:     vars.reserveDecimals = params.reserveCache.reserveConfiguration.getDecimals();
183:     vars.borrowCap = params.reserveCache.reserveConfiguration.getBorrowCap();
184:     unchecked {
185:       vars.assetUnit = 10 ** vars.reserveDecimals;
186:     }
187: 
188:     if (vars.borrowCap != 0) {
189:       vars.totalSupplyVariableDebt = params.reserveCache.currScaledVariableDebt.rayMul(
190:         params.reserveCache.nextVariableBorrowIndex
191:       );
192: 
193:       vars.totalDebt =
194:         params.reserveCache.currTotalStableDebt +
195:         vars.totalSupplyVariableDebt +
196:         params.amount;
197: 
198:       unchecked {
199:         require(vars.totalDebt <= vars.borrowCap * vars.assetUnit, Errors.BORROW_CAP_EXCEEDED);
200:       }
201:     }
202: 
203:     if (params.isolationModeActive) {
204:       
205:       
206:       require(
207:         params.reserveCache.reserveConfiguration.getBorrowableInIsolation(),
208:         Errors.ASSET_NOT_BORROWABLE_IN_ISOLATION
209:       );
210: 
211:       require(
212:         reservesData[params.isolationModeCollateralAddress].isolationModeTotalDebt +
213:           (params.amount /
214:             10 ** (vars.reserveDecimals - ReserveConfiguration.DEBT_CEILING_DECIMALS))
215:             .toUint128() <=
216:           params.isolationModeDebtCeiling,
217:         Errors.DEBT_CEILING_EXCEEDED
218:       );
219:     }
220: 
221:     if (params.userEModeCategory != 0) {
222:       require(
223:         params.reserveCache.reserveConfiguration.getEModeCategory() == params.userEModeCategory,
224:         Errors.INCONSISTENT_EMODE_CATEGORY
225:       );
226:       vars.eModePriceSource = eModeCategories[params.userEModeCategory].priceSource;
227:     }
228: 
229:     (
230:       vars.userCollateralInBaseCurrency,
231:       vars.userDebtInBaseCurrency,
232:       vars.currentLtv,
233:       ,
234:       vars.healthFactor,
235: 
236:     ) = GenericLogic.calculateUserAccountData(
237:       reservesData,
238:       reservesList,
239:       eModeCategories,
240:       DataTypes.CalculateUserAccountDataParams({
241:         userConfig: params.userConfig,
242:         reservesCount: params.reservesCount,
243:         user: params.userAddress,
244:         oracle: params.oracle,
245:         userEModeCategory: params.userEModeCategory
246:       })
247:     );
248: 
249:     require(vars.userCollateralInBaseCurrency != 0, Errors.COLLATERAL_BALANCE_IS_ZERO);
250:     require(vars.currentLtv != 0, Errors.LTV_VALIDATION_FAILED);
251: 
252:     require(
253:       vars.healthFactor > HEALTH_FACTOR_LIQUIDATION_THRESHOLD,
254:       Errors.HEALTH_FACTOR_LOWER_THAN_LIQUIDATION_THRESHOLD
255:     );
256: 
257:     vars.amountInBaseCurrency =
258:       IPriceOracleGetter(params.oracle).getAssetPrice(
259:         vars.eModePriceSource != address(0) ? vars.eModePriceSource : params.asset // <= FOUND
260:       ) *
261:       params.amount;
262:     unchecked {
263:       vars.amountInBaseCurrency /= vars.assetUnit;
264:     }
265: 
267:     vars.collateralNeededInBaseCurrency = (vars.userDebtInBaseCurrency + vars.amountInBaseCurrency)
268:       .percentDiv(vars.currentLtv); 
269: 
270:     require(
271:       vars.collateralNeededInBaseCurrency <= vars.userCollateralInBaseCurrency,
272:       Errors.COLLATERAL_CANNOT_COVER_NEW_BORROW
273:     );
274: 
283:     if (params.interestRateMode == DataTypes.InterestRateMode.STABLE) {
284:       
285: 
286:       require(vars.stableRateBorrowingEnabled, Errors.STABLE_BORROWING_NOT_ENABLED);
287: 
288:       require(
289:         !params.userConfig.isUsingAsCollateral(reservesData[params.asset].id) ||
290:           params.reserveCache.reserveConfiguration.getLtv() == 0 ||
291:           params.amount > IERC20(params.reserveCache.aTokenAddress).balanceOf(params.userAddress),
292:         Errors.COLLATERAL_SAME_AS_BORROWING_CURRENCY
293:       );
294: 
295:       vars.availableLiquidity = reservesData[params.asset].virtualUnderlyingBalance;
296: 
297:       
298:       
299:       uint256 maxLoanSizeStable = vars.availableLiquidity.percentMul(params.maxStableLoanPercent);
300: 
301:       require(params.amount <= maxLoanSizeStable, Errors.AMOUNT_BIGGER_THAN_MAX_LOAN_SIZE_STABLE);
302:     }
303: 
304:     if (params.userConfig.isBorrowingAny()) {
305:       (vars.siloedBorrowingEnabled, vars.siloedBorrowingAddress) = params
306:         .userConfig
307:         .getSiloedBorrowingState(reservesData, reservesList);
308: 
309:       if (vars.siloedBorrowingEnabled) {
310:         require(vars.siloedBorrowingAddress == params.asset, Errors.SILOED_BORROWING_VIOLATION);
311:       } else {
312:         require(
313:           !params.reserveCache.reserveConfiguration.getSiloedBorrowing(),
314:           Errors.SILOED_BORROWING_VIOLATION
315:         );
316:       }
317:     }
318:   }

['512']

512:   function validateLiquidationCall(
513:     DataTypes.UserConfigurationMap storage userConfig,
514:     DataTypes.ReserveData storage collateralReserve,
515:     DataTypes.ReserveData storage debtReserve,
516:     DataTypes.ValidateLiquidationCallParams memory params
517:   ) internal view {
518:     ValidateLiquidationCallLocalVars memory vars;
519: 
520:     (vars.collateralReserveActive, , , , vars.collateralReservePaused) = collateralReserve
521:       .configuration
522:       .getFlags();
523: 
524:     (vars.principalReserveActive, , , , vars.principalReservePaused) = params
525:       .debtReserveCache
526:       .reserveConfiguration
527:       .getFlags();
528: 
529:     require(vars.collateralReserveActive && vars.principalReserveActive, Errors.RESERVE_INACTIVE);
530:     require(!vars.collateralReservePaused && !vars.principalReservePaused, Errors.RESERVE_PAUSED);
531: 
532:     require(
533:       params.priceOracleSentinel == address(0) || // <= FOUND
534:         params.healthFactor < MINIMUM_HEALTH_FACTOR_LIQUIDATION_THRESHOLD ||
535:         IPriceOracleSentinel(params.priceOracleSentinel).isLiquidationAllowed(),
536:       Errors.PRICE_ORACLE_SENTINEL_CHECK_FAILED
537:     );
538: 
539:     require(
540:       collateralReserve.liquidationGracePeriodUntil < uint40(block.timestamp) &&
541:         debtReserve.liquidationGracePeriodUntil < uint40(block.timestamp),
542:       Errors.LIQUIDATION_GRACE_SENTINEL_CHECK_FAILED
543:     );
544: 
545:     require(
546:       params.healthFactor < HEALTH_FACTOR_LIQUIDATION_THRESHOLD,
547:       Errors.HEALTH_FACTOR_NOT_BELOW_THRESHOLD
548:     );
549: 
550:     vars.isCollateralEnabled =
551:       collateralReserve.configuration.getLiquidationThreshold() != 0 &&
552:       userConfig.isUsingAsCollateral(collateralReserve.id);
553: 
555:     require(vars.isCollateralEnabled, Errors.COLLATERAL_CANNOT_BE_LIQUIDATED);
556:     require(params.totalDebt != 0, Errors.SPECIFIED_CURRENCY_NOT_BORROWED_BY_USER);
557:   }

['658']

658:   function validateDropReserve(
659:     mapping(uint256 => address) storage reservesList,
660:     DataTypes.ReserveData storage reserve,
661:     address asset
662:   ) internal view {
663:     require(asset != address(0), Errors.ZERO_ADDRESS_NOT_VALID); // <= FOUND
664:     require(reserve.id != 0 || reservesList[0] == asset, Errors.ASSET_NOT_LISTED);
665:     require(IERC20(reserve.stableDebtTokenAddress).totalSupply() == 0, Errors.STABLE_DEBT_NOT_ZERO);
666:     require(
667:       IERC20(reserve.variableDebtTokenAddress).totalSupply() == 0,
668:       Errors.VARIABLE_DEBT_SUPPLY_NOT_ZERO
669:     );
670:     require(
671:       IERC20(reserve.aTokenAddress).totalSupply() == 0 && reserve.accruedToTreasury == 0,
672:       Errors.UNDERLYING_CLAIMABLE_RIGHTS_NOT_ZERO
673:     );
674:   }

[Gas-7] Use assembly to emit events

Resolution

With the use of inline assembly in Solidity, we can take advantage of low-level features like scratch space and the free memory pointer, offering more gas-efficient ways of emitting events. The scratch space is a certain area of memory where we can temporarily store data, and the free memory pointer indicates the next available memory slot. Using these, we can efficiently assemble event data without incurring additional memory expansion costs. However, safety is paramount: to avoid overwriting or leakage, we must cache the free memory pointer before use and restore it afterward, ensuring that it points to the correct memory location post-operation.

Num of instances: 58

Findings

Click to show findings

['140']

140:       emit IsolationModeTotalDebtUpdated( // <= FOUND
141:         isolationModeCollateralAddress,
142:         nextIsolationModeTotalDebt
143:       );

['157']

157:     emit Borrow( // <= FOUND
158:       params.asset,
159:       params.user,
160:       params.onBehalfOf,
161:       params.amount,
162:       params.interestRateMode,
163:       params.interestRateMode == DataTypes.InterestRateMode.STABLE
164:         ? currentStableRate
165:         : reserve.currentVariableBorrowRate,
166:       params.referralCode
167:     );

['257']

257:         emit ReserveUsedAsCollateralDisabled(params.asset, msg.sender); // <= FOUND

['268']

268:     emit Repay(params.asset, params.onBehalfOf, msg.sender, paybackAmount, params.useATokens); // <= FOUND

['302']

302:     emit RebalanceStableBorrowRate(asset, user); // <= FOUND

['355']

355:     emit SwapBorrowRateMode(asset, user, interestRateMode); // <= FOUND

['98']

98:         emit ReserveUsedAsCollateralEnabled(asset, onBehalfOf); // <= FOUND

['102']

102:     emit MintUnbacked(asset, msg.sender, onBehalfOf, amount, referralCode); // <= FOUND

['146']

146:     emit BackUnbacked(asset, msg.sender, backingAmount, fee); // <= FOUND

['122']

122:     emit ReserveInitialized( // <= FOUND
123:       input.underlyingAsset,
124:       aTokenProxyAddress,
125:       stableDebtTokenProxyAddress,
126:       variableDebtTokenProxyAddress,
127:       input.interestRateStrategyAddress
128:     );

['159']

159:     emit ATokenUpgraded(input.asset, reserveData.aTokenAddress, input.implementation); // <= FOUND

['193']

193:     emit StableDebtTokenUpgraded( // <= FOUND
194:       input.asset,
195:       reserveData.stableDebtTokenAddress,
196:       input.implementation
197:     );

['231']

231:     emit VariableDebtTokenUpgraded( // <= FOUND
232:       input.asset,
233:       reserveData.variableDebtTokenAddress,
234:       input.implementation
235:     );

['232']

232:     emit RateDataUpdate( // <= FOUND
233:       reserve,
234:       rateData.optimalUsageRatio,
235:       rateData.baseVariableBorrowRate,
236:       rateData.variableRateSlope1,
237:       rateData.variableRateSlope2
238:     );

['168']

168:         
169:         emit FlashLoan( // <= FOUND
170:           params.receiverAddress,
171:           msg.sender,
172:           vars.currentAsset,
173:           vars.currentAmount,
174:           DataTypes.InterestRateMode(params.interestRateModes[vars.i]),
175:           0,
176:           params.referralCode
177:         );

['274']

274:     emit FlashLoan( // <= FOUND
275:       params.receiverAddress,
276:       msg.sender,
277:       params.asset,
278:       params.amount,
279:       DataTypes.InterestRateMode(0),
280:       params.totalPremium,
281:       params.referralCode
282:     );

['177']

177:       emit ReserveUsedAsCollateralDisabled(params.collateralAsset, params.user); // <= FOUND

['234']

234:     emit LiquidationCall( // <= FOUND
235:       params.collateralAsset,
236:       params.debtAsset,
237:       params.user,
238:       vars.actualDebtToLiquidate,
239:       vars.actualCollateralToLiquidate,
240:       msg.sender,
241:       params.receiveAToken
242:     );

['313']

313:         emit ReserveUsedAsCollateralEnabled(params.collateralAsset, msg.sender); // <= FOUND

['88']

88:       emit ReserveInterestRateDataChanged( // <= FOUND
89:         input[i].underlyingAsset,
90:         input[i].interestRateStrategyAddress,
91:         input[i].interestRateData
92:       );

['99']

99:     emit ReserveDropped(asset); // <= FOUND

['131']

131:     emit ReserveBorrowing(asset, enabled); // <= FOUND

['171']

171:       emit PendingLtvChanged(asset, ltv); // <= FOUND

['181']

181:     emit CollateralConfigurationChanged(asset, ltv, liquidationThreshold, liquidationBonus); // <= FOUND

['195']

195:     emit ReserveStableRateBorrowing(asset, enabled); // <= FOUND

['207']

207:     emit ReserveFlashLoaning(asset, enabled); // <= FOUND

['216']

216:     emit ReserveActive(asset, active); // <= FOUND

['232']

232:       emit PendingLtvChanged(asset, currentConfig.getLtv()); // <= FOUND

['240']

240:       emit PendingLtvRemoved(asset); // <= FOUND

['244']

244:     emit ReserveFrozen(asset, freeze); // <= FOUND

['255']

255:     emit BorrowableInIsolationChanged(asset, borrowable); // <= FOUND

['269']

269:       emit LiquidationGracePeriodChanged(asset, until); // <= FOUND

['275']

275:     emit ReservePaused(asset, paused); // <= FOUND

['296']

296:     emit ReserveFactorChanged(asset, oldReserveFactor, newReserveFactor); // <= FOUND

['319']

319:     emit DebtCeilingChanged(asset, oldDebtCeiling, newDebtCeiling); // <= FOUND

['338']

338:     emit SiloedBorrowingChanged(asset, oldSiloed, newSiloed); // <= FOUND

['350']

350:     emit BorrowCapChanged(asset, oldBorrowCap, newBorrowCap); // <= FOUND

['362']

362:     emit SupplyCapChanged(asset, oldSupplyCap, newSupplyCap); // <= FOUND

['375']

375:     emit LiquidationProtocolFeeChanged(asset, oldFee, newFee); // <= FOUND

['429']

429:     emit EModeCategoryAdded(categoryId, ltv, liquidationThreshold, liquidationBonus, oracle, label); // <= FOUND

['449']

449:     emit EModeAssetCategoryChanged(asset, uint8(oldCategoryId), newCategoryId); // <= FOUND

['461']

461:     emit UnbackedMintCapChanged(asset, oldUnbackedMintCap, newUnbackedMintCap); // <= FOUND

['507']

507:     emit BridgeProtocolFeeUpdated(oldBridgeProtocolFee, newBridgeProtocolFee); // <= FOUND

['520']

520:     emit FlashloanPremiumTotalUpdated(oldFlashloanPremiumTotal, newFlashloanPremiumTotal); // <= FOUND

['533']

533:     emit FlashloanPremiumToProtocolUpdated( // <= FOUND
534:       oldFlashloanPremiumToProtocol,
535:       newFlashloanPremiumToProtocol
536:     );

['560']

560:     emit ReserveInterestRateDataChanged(asset, newRateStrategyAddress, rateData); // <= FOUND

['564']

564:       emit ReserveInterestRateStrategyChanged( // <= FOUND
565:         asset,
566:         oldRateStrategyAddress,
567:         newRateStrategyAddress
568:       );

['106']

106:         emit MintedToTreasury(assetAddress, amountToMint); // <= FOUND

['123']

123:     emit IsolationModeTotalDebtUpdated(asset, 0); // <= FOUND

['218']

218:     emit ReserveDataUpdated( // <= FOUND
219:       reserveAddress,
220:       vars.nextLiquidityRate,
221:       vars.nextStableRate,
222:       vars.nextVariableRate,
223:       reserveCache.nextLiquidityIndex,
224:       reserveCache.nextVariableBorrowIndex
225:     );

['87']

87:         emit ReserveUsedAsCollateralEnabled(params.asset, params.onBehalfOf); // <= FOUND

['91']

91:     emit Supply(params.asset, msg.sender, params.onBehalfOf, params.amount, params.referralCode); // <= FOUND

['138']

138:       emit ReserveUsedAsCollateralDisabled(params.asset, msg.sender); // <= FOUND

['162']

162:     emit Withdraw(params.asset, msg.sender, params.to, amountToWithdraw); // <= FOUND

['212']

212:           emit ReserveUsedAsCollateralDisabled(params.asset, params.from); // <= FOUND

['228']

228:           emit ReserveUsedAsCollateralEnabled(params.asset, params.to); // <= FOUND

['282']

282:       emit ReserveUsedAsCollateralEnabled(asset, msg.sender); // <= FOUND

['297']

297:       emit ReserveUsedAsCollateralDisabled(asset, msg.sender); // <= FOUND

[Gas-8] Use assembly in place of abi.decode to extract calldata values more efficiently

Resolution

Using inline assembly to extract calldata values can be more gas-efficient than using abi.decode in Solidity. Inline assembly gives more direct access to EVM operations, enabling optimized usage of calldata. However, assembly should be used judiciously as it's more prone to errors. Opt for this approach when performance is critical and the complexity it introduces is manageable.

Num of instances: 1

Findings

Click to show findings

['61']

61:     _setInterestRateParams(reserve, abi.decode(rateData, (InterestRateData))); // <= FOUND

[Gas-9] Using private rather than public for constants and immutables, saves gas

Resolution

Using private visibility for constants and immutables in Solidity instead of public can save gas. This is because private elements are not included in the contract's ABI, reducing the deployment and interaction costs. To achieve better efficiency, it is recommended to use private visibility when external access is not needed.

Num of instances: 111

Findings

Click to show findings

['29']

29: uint256 public constant MAX_BORROW_RATE = 1000_00; // <= FOUND

['32']

32: uint256 public constant MIN_OPTIMAL_POINT = 1_00; // <= FOUND

['35']

35: uint256 public constant MAX_OPTIMAL_POINT = 99_00; // <= FOUND

['7']

7: uint256 public constant CONFIGURATOR_REVISION = 3; // <= FOUND

['9']

9: uint256 public constant POOL_REVISION = 4; // <= FOUND

['35']

35: uint40 public constant MAX_GRACE_PERIOD = 4 hours; // <= FOUND

['10']

10: string public constant CALLER_NOT_POOL_ADMIN = '1';  // <= FOUND

['11']

11: string public constant CALLER_NOT_EMERGENCY_ADMIN = '2';  // <= FOUND

['12']

12: string public constant CALLER_NOT_POOL_OR_EMERGENCY_ADMIN = '3';  // <= FOUND

['13']

13: string public constant CALLER_NOT_RISK_OR_POOL_ADMIN = '4';  // <= FOUND

['14']

14: string public constant CALLER_NOT_ASSET_LISTING_OR_POOL_ADMIN = '5';  // <= FOUND

['15']

15: string public constant CALLER_NOT_BRIDGE = '6';  // <= FOUND

['16']

16: string public constant ADDRESSES_PROVIDER_NOT_REGISTERED = '7';  // <= FOUND

['17']

17: string public constant INVALID_ADDRESSES_PROVIDER_ID = '8';  // <= FOUND

['18']

18: string public constant NOT_CONTRACT = '9';  // <= FOUND

['19']

19: string public constant CALLER_NOT_POOL_CONFIGURATOR = '10';  // <= FOUND

['20']

20: string public constant CALLER_NOT_ATOKEN = '11';  // <= FOUND

['21']

21: string public constant INVALID_ADDRESSES_PROVIDER = '12';  // <= FOUND

['22']

22: string public constant INVALID_FLASHLOAN_EXECUTOR_RETURN = '13';  // <= FOUND

['23']

23: string public constant RESERVE_ALREADY_ADDED = '14';  // <= FOUND

['24']

24: string public constant NO_MORE_RESERVES_ALLOWED = '15';  // <= FOUND

['25']

25: string public constant EMODE_CATEGORY_RESERVED = '16';  // <= FOUND

['26']

26: string public constant INVALID_EMODE_CATEGORY_ASSIGNMENT = '17';  // <= FOUND

['27']

27: string public constant RESERVE_LIQUIDITY_NOT_ZERO = '18';  // <= FOUND

['28']

28: string public constant FLASHLOAN_PREMIUM_INVALID = '19';  // <= FOUND

['29']

29: string public constant INVALID_RESERVE_PARAMS = '20';  // <= FOUND

['30']

30: string public constant INVALID_EMODE_CATEGORY_PARAMS = '21';  // <= FOUND

['31']

31: string public constant BRIDGE_PROTOCOL_FEE_INVALID = '22';  // <= FOUND

['32']

32: string public constant CALLER_MUST_BE_POOL = '23';  // <= FOUND

['33']

33: string public constant INVALID_MINT_AMOUNT = '24';  // <= FOUND

['34']

34: string public constant INVALID_BURN_AMOUNT = '25';  // <= FOUND

['35']

35: string public constant INVALID_AMOUNT = '26';  // <= FOUND

['36']

36: string public constant RESERVE_INACTIVE = '27';  // <= FOUND

['37']

37: string public constant RESERVE_FROZEN = '28';  // <= FOUND

['38']

38: string public constant RESERVE_PAUSED = '29';  // <= FOUND

['39']

39: string public constant BORROWING_NOT_ENABLED = '30';  // <= FOUND

['40']

40: string public constant STABLE_BORROWING_NOT_ENABLED = '31';  // <= FOUND

['41']

41: string public constant NOT_ENOUGH_AVAILABLE_USER_BALANCE = '32';  // <= FOUND

['42']

42: string public constant INVALID_INTEREST_RATE_MODE_SELECTED = '33';  // <= FOUND

['43']

43: string public constant COLLATERAL_BALANCE_IS_ZERO = '34';  // <= FOUND

['44']

44: string public constant HEALTH_FACTOR_LOWER_THAN_LIQUIDATION_THRESHOLD = '35';  // <= FOUND

['45']

45: string public constant COLLATERAL_CANNOT_COVER_NEW_BORROW = '36';  // <= FOUND

['46']

46: string public constant COLLATERAL_SAME_AS_BORROWING_CURRENCY = '37';  // <= FOUND

['47']

47: string public constant AMOUNT_BIGGER_THAN_MAX_LOAN_SIZE_STABLE = '38';  // <= FOUND

['48']

48: string public constant NO_DEBT_OF_SELECTED_TYPE = '39';  // <= FOUND

['49']

49: string public constant NO_EXPLICIT_AMOUNT_TO_REPAY_ON_BEHALF = '40';  // <= FOUND

['50']

50: string public constant NO_OUTSTANDING_STABLE_DEBT = '41';  // <= FOUND

['51']

51: string public constant NO_OUTSTANDING_VARIABLE_DEBT = '42';  // <= FOUND

['52']

52: string public constant UNDERLYING_BALANCE_ZERO = '43';  // <= FOUND

['53']

53: string public constant INTEREST_RATE_REBALANCE_CONDITIONS_NOT_MET = '44';  // <= FOUND

['54']

54: string public constant HEALTH_FACTOR_NOT_BELOW_THRESHOLD = '45';  // <= FOUND

['55']

55: string public constant COLLATERAL_CANNOT_BE_LIQUIDATED = '46';  // <= FOUND

['56']

56: string public constant SPECIFIED_CURRENCY_NOT_BORROWED_BY_USER = '47';  // <= FOUND

['57']

57: string public constant INCONSISTENT_FLASHLOAN_PARAMS = '49';  // <= FOUND

['58']

58: string public constant BORROW_CAP_EXCEEDED = '50';  // <= FOUND

['59']

59: string public constant SUPPLY_CAP_EXCEEDED = '51';  // <= FOUND

['60']

60: string public constant UNBACKED_MINT_CAP_EXCEEDED = '52';  // <= FOUND

['61']

61: string public constant DEBT_CEILING_EXCEEDED = '53';  // <= FOUND

['62']

62: string public constant UNDERLYING_CLAIMABLE_RIGHTS_NOT_ZERO = '54';  // <= FOUND

['63']

63: string public constant STABLE_DEBT_NOT_ZERO = '55';  // <= FOUND

['64']

64: string public constant VARIABLE_DEBT_SUPPLY_NOT_ZERO = '56';  // <= FOUND

['65']

65: string public constant LTV_VALIDATION_FAILED = '57';  // <= FOUND

['66']

66: string public constant INCONSISTENT_EMODE_CATEGORY = '58';  // <= FOUND

['67']

67: string public constant PRICE_ORACLE_SENTINEL_CHECK_FAILED = '59';  // <= FOUND

['68']

68: string public constant ASSET_NOT_BORROWABLE_IN_ISOLATION = '60';  // <= FOUND

['69']

69: string public constant RESERVE_ALREADY_INITIALIZED = '61';  // <= FOUND

['70']

70: string public constant USER_IN_ISOLATION_MODE_OR_LTV_ZERO = '62';  // <= FOUND

['71']

71: string public constant INVALID_LTV = '63';  // <= FOUND

['72']

72: string public constant INVALID_LIQ_THRESHOLD = '64';  // <= FOUND

['73']

73: string public constant INVALID_LIQ_BONUS = '65';  // <= FOUND

['74']

74: string public constant INVALID_DECIMALS = '66';  // <= FOUND

['75']

75: string public constant INVALID_RESERVE_FACTOR = '67';  // <= FOUND

['76']

76: string public constant INVALID_BORROW_CAP = '68';  // <= FOUND

['77']

77: string public constant INVALID_SUPPLY_CAP = '69';  // <= FOUND

['78']

78: string public constant INVALID_LIQUIDATION_PROTOCOL_FEE = '70';  // <= FOUND

['79']

79: string public constant INVALID_EMODE_CATEGORY = '71';  // <= FOUND

['80']

80: string public constant INVALID_UNBACKED_MINT_CAP = '72';  // <= FOUND

['81']

81: string public constant INVALID_DEBT_CEILING = '73';  // <= FOUND

['82']

82: string public constant INVALID_RESERVE_INDEX = '74';  // <= FOUND

['83']

83: string public constant ACL_ADMIN_CANNOT_BE_ZERO = '75';  // <= FOUND

['84']

84: string public constant INCONSISTENT_PARAMS_LENGTH = '76';  // <= FOUND

['85']

85: string public constant ZERO_ADDRESS_NOT_VALID = '77';  // <= FOUND

['86']

86: string public constant INVALID_EXPIRATION = '78';  // <= FOUND

['87']

87: string public constant INVALID_SIGNATURE = '79';  // <= FOUND

['88']

88: string public constant OPERATION_NOT_SUPPORTED = '80';  // <= FOUND

['89']

89: string public constant DEBT_CEILING_NOT_ZERO = '81';  // <= FOUND

['90']

90: string public constant ASSET_NOT_LISTED = '82';  // <= FOUND

['91']

91: string public constant INVALID_OPTIMAL_USAGE_RATIO = '83';  // <= FOUND

['92']

92: string public constant INVALID_OPTIMAL_STABLE_TO_TOTAL_DEBT_RATIO = '84';  // <= FOUND

['93']

93: string public constant UNDERLYING_CANNOT_BE_RESCUED = '85';  // <= FOUND

['94']

94: string public constant ADDRESSES_PROVIDER_ALREADY_ADDED = '86';  // <= FOUND

['95']

95: string public constant POOL_ADDRESSES_DO_NOT_MATCH = '87';  // <= FOUND

['96']

96: string public constant STABLE_BORROWING_ENABLED = '88';  // <= FOUND

['97']

97: string public constant SILOED_BORROWING_VIOLATION = '89';  // <= FOUND

['98']

98: string public constant RESERVE_DEBT_NOT_ZERO = '90';  // <= FOUND

['99']

99: string public constant FLASHLOAN_DISABLED = '91';  // <= FOUND

['100']

100: string public constant INVALID_MAXRATE = '92';  // <= FOUND

['101']

101: string public constant WITHDRAW_TO_ATOKEN = '93';  // <= FOUND

['102']

102: string public constant SUPPLY_TO_ATOKEN = '94';  // <= FOUND

['103']

103: string public constant SLOPE_2_MUST_BE_GTE_SLOPE_1 = '95';  // <= FOUND

['104']

104: string public constant CALLER_NOT_RISK_OR_POOL_OR_EMERGENCY_ADMIN = '96';  // <= FOUND

['105']

105: string public constant LIQUIDATION_GRACE_SENTINEL_CHECK_FAILED = '97';  // <= FOUND

['106']

106: string public constant INVALID_GRACE_PERIOD = '98';  // <= FOUND

['61']

61: uint256 public constant MAX_LIQUIDATION_CLOSE_FACTOR = 1e4; // <= FOUND

['68']

68: uint256 public constant CLOSE_FACTOR_HF_THRESHOLD = 0.95e18; // <= FOUND

['67']

67: uint256 public constant DEBT_CEILING_DECIMALS = 2; // <= FOUND

['68']

68: uint16 public constant MAX_RESERVES_COUNT = 128; // <= FOUND

['43']

43: uint256 public constant REBALANCE_UP_LIQUIDITY_RATE_THRESHOLD = 0.9e4; // <= FOUND

['47']

47: uint256 public constant MINIMUM_HEALTH_FACTOR_LIQUIDATION_THRESHOLD = 0.95e18; // <= FOUND

['53']

53: uint256 public constant HEALTH_FACTOR_LIQUIDATION_THRESHOLD = 1e18; // <= FOUND

['58']

58: bytes32 public constant ISOLATED_COLLATERAL_SUPPLIER_ROLE = // <= FOUND

[Gas-10] Lack of unchecked in loops

Resolution

In Solidity, the unchecked block allows arithmetic operations to not revert on overflow. Without using unchecked in loops, extra gas is consumed due to overflow checks. If it's certain that overflows won't occur within the loop, using unchecked can make the loop more gas-efficient by skipping unnecessary checks.

Num of instances: 18

Findings

Click to show findings

['93']

93:    for (vars.i = 0; vars.i < params.assets.length; vars.i++) {
94:       vars.currentAmount = params.amounts[vars.i];
95:       vars.totalPremiums[vars.i] = DataTypes.InterestRateMode(params.interestRateModes[vars.i]) ==
96:         DataTypes.InterestRateMode.NONE
97:         ? vars.currentAmount.percentMul(vars.flashloanPremiumTotal)
98:         : 0;
99: 
100:       if (reservesData[params.assets[vars.i]].configuration.getIsVirtualAccActive()) {
101:         reservesData[params.assets[vars.i]].virtualUnderlyingBalance -= vars
102:           .currentAmount
103:           .toUint128();
104:       }
105: 
106:       IAToken(reservesData[params.assets[vars.i]].aTokenAddress).transferUnderlyingTo(
107:         params.receiverAddress,
108:         vars.currentAmount
109:       );
110:     }

['561']

561:    for (uint256 i = 0; i < reservesListCount; i++) {
562:       if (_reservesList[i] != address(0)) {
563:         reservesList[i - droppedReservesCount] = _reservesList[i];
564:       } else {
565:         droppedReservesCount++;
566:       }
567:     }

['84']

84:    for (uint256 i = 0; i < input.length; i++) {
85:       require(IERC20Detailed(input[i].underlyingAsset).decimals() > 5, Errors.INVALID_DECIMALS);
86: 
87:       ConfiguratorLogic.executeInitReserve(cachedPool, input[i]);
88:       emit ReserveInterestRateDataChanged(
89:         input[i].underlyingAsset,
90:         input[i].interestRateStrategyAddress,
91:         input[i].interestRateData
92:       );
93:     }

['408']

408:    for (uint256 i = 0; i < reserves.length; i++) {
409:       DataTypes.ReserveConfigurationMap memory currentConfig = _pool.getConfiguration(reserves[i]);
410:       if (categoryId == currentConfig.getEModeCategory()) {
411:         require(ltv > currentConfig.getLtv(), Errors.INVALID_EMODE_CATEGORY_PARAMS);
412:         require(
413:           liquidationThreshold > currentConfig.getLiquidationThreshold(),
414:           Errors.INVALID_EMODE_CATEGORY_PARAMS
415:         );
416:       }
417:     }

['487']

487:    for (uint256 i = 0; i < reserves.length; i++) {
488:       if (reserves[i] != address(0)) {
489:         setReservePause(reserves[i], paused, gracePeriod);
490:       }
491:     }

['55']

55:    for (uint16 i = 0; i < params.reservesCount; i++) {
56:       if (reservesList[i] == address(0)) {
57:         reservesData[params.asset].id = i;
58:         reservesList[i] = params.asset;
59:         return false;
60:       }
61:     }

['88']

88:    for (uint256 i = 0; i < assets.length; i++) {
89:       address assetAddress = assets[i];
90: 
91:       DataTypes.ReserveData storage reserve = reservesData[assetAddress];
92: 
93:       
94:       if (!reserve.configuration.getActive()) {
95:         continue;
96:       }
97: 
98:       uint256 accruedToTreasury = reserve.accruedToTreasury;
99: 
100:       if (accruedToTreasury != 0) {
101:         reserve.accruedToTreasury = 0;
102:         uint256 normalizedIncome = reserve.getNormalizedIncome();
103:         uint256 amountToMint = accruedToTreasury.rayMul(normalizedIncome);
104:         IAToken(reserve.aTokenAddress).mintToTreasury(amountToMint, normalizedIncome);
105: 
106:         emit MintedToTreasury(assetAddress, amountToMint);
107:       }
108:     }

['473']

473:    for (uint256 i = 0; i < assets.length; i++) {
474:       validateFlashloanSimple(reservesData[assets[i]], amounts[i]);
475:     }

['93']

93:     for (vars.i = 0; vars.i < params.assets.length; vars.i++) {
94:       vars.currentAmount = params.amounts[vars.i];
95:       vars.totalPremiums[vars.i] = DataTypes.InterestRateMode(params.interestRateModes[vars.i]) ==
96:         DataTypes.InterestRateMode.NONE
97:         ? vars.currentAmount.percentMul(vars.flashloanPremiumTotal)
98:         : 0;
99: 
100:       if (reservesData[params.assets[vars.i]].configuration.getIsVirtualAccActive()) {
101:         reservesData[params.assets[vars.i]].virtualUnderlyingBalance -= vars
102:           .currentAmount
103:           .toUint128();
104:       }
105: 
106:       IAToken(reservesData[params.assets[vars.i]].aTokenAddress).transferUnderlyingTo(
107:         params.receiverAddress,
108:         vars.currentAmount
109:       );
110:     }

['123']

123:     for (vars.i = 0; vars.i < params.assets.length; vars.i++) {
124:       vars.currentAsset = params.assets[vars.i];
125:       vars.currentAmount = params.amounts[vars.i];
126: 
127:       if (
128:         DataTypes.InterestRateMode(params.interestRateModes[vars.i]) ==
129:         DataTypes.InterestRateMode.NONE
130:       ) {
131:         _handleFlashLoanRepayment(
132:           reservesData[vars.currentAsset],
133:           DataTypes.FlashLoanRepaymentParams({
134:             asset: vars.currentAsset,
135:             receiverAddress: params.receiverAddress,
136:             amount: vars.currentAmount,
137:             totalPremium: vars.totalPremiums[vars.i],
138:             flashLoanPremiumToProtocol: vars.flashloanPremiumToProtocol,
139:             referralCode: params.referralCode
140:           })
141:         );
142:       } else {
143:         
144:         
145:         BorrowLogic.executeBorrow(
146:           reservesData,
147:           reservesList,
148:           eModeCategories,
149:           userConfig,
150:           DataTypes.ExecuteBorrowParams({
151:             asset: vars.currentAsset,
152:             user: msg.sender,
153:             onBehalfOf: params.onBehalfOf,
154:             amount: vars.currentAmount,
155:             interestRateMode: DataTypes.InterestRateMode(params.interestRateModes[vars.i]),
156:             referralCode: params.referralCode,
157:             releaseUnderlying: false,
158:             maxStableRateBorrowSizePercent: IPool(params.pool)
159:               .MAX_STABLE_RATE_BORROW_SIZE_PERCENT(),
160:             reservesCount: IPool(params.pool).getReservesCount(),
161:             oracle: IPoolAddressesProvider(params.addressesProvider).getPriceOracle(),
162:             userEModeCategory: IPool(params.pool).getUserEMode(params.onBehalfOf).toUint8(),
163:             priceOracleSentinel: IPoolAddressesProvider(params.addressesProvider)
164:               .getPriceOracleSentinel()
165:           })
166:         );
167:         
168:         emit FlashLoan(
169:           params.receiverAddress,
170:           msg.sender,
171:           vars.currentAsset,
172:           vars.currentAmount,
173:           DataTypes.InterestRateMode(params.interestRateModes[vars.i]),
174:           0,
175:           params.referralCode
176:         );
177:       }
178:     }

['561']

561:     for (uint256 i = 0; i < reservesListCount; i++) {
562:       if (_reservesList[i] != address(0)) {
563:         reservesList[i - droppedReservesCount] = _reservesList[i];
564:       } else {
565:         droppedReservesCount++;
566:       }
567:     }

['84']

84:     for (uint256 i = 0; i < input.length; i++) {
85:       require(IERC20Detailed(input[i].underlyingAsset).decimals() > 5, Errors.INVALID_DECIMALS);
86: 
87:       ConfiguratorLogic.executeInitReserve(cachedPool, input[i]);
88:       emit ReserveInterestRateDataChanged(
89:         input[i].underlyingAsset,
90:         input[i].interestRateStrategyAddress,
91:         input[i].interestRateData
92:       );
93:     }

['408']

408:     for (uint256 i = 0; i < reserves.length; i++) {
409:       DataTypes.ReserveConfigurationMap memory currentConfig = _pool.getConfiguration(reserves[i]);
410:       if (categoryId == currentConfig.getEModeCategory()) {
411:         require(ltv > currentConfig.getLtv(), Errors.INVALID_EMODE_CATEGORY_PARAMS);
412:         require(
413:           liquidationThreshold > currentConfig.getLiquidationThreshold(),
414:           Errors.INVALID_EMODE_CATEGORY_PARAMS
415:         );
416:       }
417:     }

['487']

487:     for (uint256 i = 0; i < reserves.length; i++) {
488:       if (reserves[i] != address(0)) {
489:         setReservePause(reserves[i], paused, gracePeriod);
490:       }
491:     }

['55']

55:     for (uint16 i = 0; i < params.reservesCount; i++) {
56:       if (reservesList[i] == address(0)) {
57:         reservesData[params.asset].id = i;
58:         reservesList[i] = params.asset;
59:         return false;
60:       }
61:     }

['88']

88:     for (uint256 i = 0; i < assets.length; i++) {
89:       address assetAddress = assets[i];
90: 
91:       DataTypes.ReserveData storage reserve = reservesData[assetAddress];
92: 
93:       
94:       if (!reserve.configuration.getActive()) {
95:         continue;
96:       }
97: 
98:       uint256 accruedToTreasury = reserve.accruedToTreasury;
99: 
100:       if (accruedToTreasury != 0) {
101:         reserve.accruedToTreasury = 0;
102:         uint256 normalizedIncome = reserve.getNormalizedIncome();
103:         uint256 amountToMint = accruedToTreasury.rayMul(normalizedIncome);
104:         IAToken(reserve.aTokenAddress).mintToTreasury(amountToMint, normalizedIncome);
105: 
106:         emit MintedToTreasury(assetAddress, amountToMint);
107:       }
108:     }

['473']

473:     for (uint256 i = 0; i < assets.length; i++) {
474:       validateFlashloanSimple(reservesData[assets[i]], amounts[i]);
475:     }

['708']

708:         for (uint256 i = 0; i < reservesCount; i++) {
709:           if (userConfig.isBorrowing(i)) {
710:             DataTypes.ReserveConfigurationMap memory configuration = reservesData[reservesList[i]]
711:               .configuration;
712:             require(
713:               configuration.getEModeCategory() == categoryId,
714:               Errors.INCONSISTENT_EMODE_CATEGORY
715:             );
716:           }
717:         }

[Gas-11] Use assembly to validate msg.sender

Resolution

Utilizing assembly for validating msg.sender can potentially save gas as it allows for more direct and efficient access to Ethereum’s EVM opcodes, bypassing some of the overhead introduced by Solidity’s higher-level abstractions. However, this practice requires deep expertise in EVM, as incorrect implementation can introduce critical vulnerabilities. It is a trade-off between gas efficiency and code safety.

Num of instances: 4

Findings

Click to show findings

['49']

49:     require( // <= FOUND
50:       msg.sender == ADDRESSES_PROVIDER.getPoolConfigurator(), // <= FOUND
51:       Errors.CALLER_NOT_POOL_CONFIGURATOR
52:     );

['620']

620:     require(msg.sender == _reserves[asset].aTokenAddress, Errors.CALLER_NOT_ATOKEN); // <= FOUND

['338']

338:     require( // <= FOUND
339:       amountSent != type(uint256).max || msg.sender == onBehalfOf, // <= FOUND
340:       Errors.NO_EXPLICIT_AMOUNT_TO_REPAY_ON_BEHALF
341:     );

['69']

69:     require( // <= FOUND
70:       ADDRESSES_PROVIDER.getPoolConfigurator() == msg.sender, // <= FOUND
71:       Errors.CALLER_NOT_POOL_CONFIGURATOR
72:     );

[Gas-12] Simple checks for zero uint can be done using assembly to save gas

Resolution

Using assembly for simple zero checks on unsigned integers can save gas due to lower-level, optimized operations.

Resolution: Implement inline assembly with Solidity's assembly block to perform zero checks. Ensure thorough testing and verification, as assembly lacks the safety checks of high-level Solidity, potentially introducing vulnerabilities if not used carefully.

Num of instances: 11

Findings

Click to show findings

['160']

160:       require(liquidationBonus == 0, Errors.INVALID_RESERVE_PARAMS); // <= FOUND

['589']

589:     require(totalDebt == 0, Errors.RESERVE_DEBT_NOT_ZERO); // <= FOUND

['731']

731:     
732:     require(id != 0, Errors.EMODE_CATEGORY_RESERVED); // <= FOUND

['387']

387:     require(ltv != 0, Errors.INVALID_EMODE_CATEGORY_PARAMS); // <= FOUND

['388']

388:     require(liquidationThreshold != 0, Errors.INVALID_EMODE_CATEGORY_PARAMS); // <= FOUND

['588']

588:     return (
589:       (dataLocal & ~ACTIVE_MASK) != 0, // <= FOUND
590:       (dataLocal & ~FROZEN_MASK) != 0, // <= FOUND
591:       (dataLocal & ~BORROWING_MASK) != 0, // <= FOUND
592:       (dataLocal & ~STABLE_BORROWING_MASK) != 0, // <= FOUND
593:       (dataLocal & ~PAUSED_MASK) != 0 // <= FOUND
594:     );

['72']

72:     require(amount != 0, Errors.INVALID_AMOUNT); // <= FOUND

['337']

337:     require(amountSent != 0, Errors.INVALID_AMOUNT); // <= FOUND

['378']

378:       require(stableDebt != 0, Errors.NO_OUTSTANDING_STABLE_DEBT); // <= FOUND

['380']

380:       require(variableDebt != 0, Errors.NO_OUTSTANDING_VARIABLE_DEBT); // <= FOUND

['454']

454:     require(userBalance != 0, Errors.UNDERLYING_BALANCE_ZERO); // <= FOUND

[Gas-13] Using nested if to save gas

Resolution

Using nested if statements instead of logical AND (&&) operators can potentially save gas in Solidity contracts. When a series of conditions are connected with &&, all conditions must be evaluated even if the first one fails. In contrast, nested if statements allow for short-circuiting; if the first condition fails, the rest are skipped, saving gas. This approach is more gas-efficient, especially when dealing with complex or gas-intensive conditions. However, it's crucial to balance gas savings with code readability and maintainability, ensuring that the code remains clear and easy to understand.

Num of instances: 18

Findings

Click to show findings

['210']

210:     if (params.useATokens && params.amount == type(uint256).max) { // <= FOUND
211:       params.amount = IAToken(reserveCache.aTokenAddress).balanceOf(msg.sender);
212:     }

['264']

264:    if (!paused && gracePeriod != 0) { // <= FOUND
265:       require(gracePeriod <= MAX_GRACE_PERIOD, Errors.INVALID_GRACE_PERIOD);
266: 
267:       uint40 until = uint40(block.timestamp) + gracePeriod;
268:       _pool.setLiquidationGracePeriod(asset, until);
269:       emit LiquidationGracePeriodChanged(asset, until);
270:     }

['309']

309:     if (currentConfig.getLiquidationThreshold() != 0 && oldDebtCeiling == 0) { // <= FOUND
310:       _checkNoSuppliers(asset);
311:     }

['136']

136:     if (isCollateral && amountToWithdraw == userBalance) { // <= FOUND
137:       userConfig.setUsingAsCollateral(reserve.id, false);
138:       emit ReserveUsedAsCollateralDisabled(params.asset, msg.sender);
139:     }

['148']

148:     if (isCollateral && userConfig.isBorrowingAny()) { // <= FOUND
149:       ValidationLogic.validateHFAndLtv(
150:         reservesData,
151:         reservesList,
152:         eModeCategories,
153:         userConfig,
154:         params.asset,
155:         msg.sender,
156:         params.reservesCount,
157:         params.oracle,
158:         params.userEModeCategory
159:       );
160:     }

['193']

193:     if (params.from != params.to && scaledAmount != 0) { // <= FOUND
194:       DataTypes.UserConfigurationMap storage fromConfig = usersConfig[params.from];
195: 
196:       if (fromConfig.isUsingAsCollateral(reserveId)) {
197:         if (fromConfig.isBorrowingAny()) {
198:           ValidationLogic.validateHFAndLtv(
199:             reservesData,
200:             reservesList,
201:             eModeCategories,
202:             usersConfig[params.from],
203:             params.asset,
204:             params.from,
205:             params.reservesCount,
206:             params.oracle,
207:             params.fromEModeCategory
208:           );
209:         }
210:         if (params.balanceFromBefore == params.amount) {
211:           fromConfig.setUsingAsCollateral(reserveId, false);
212:           emit ReserveUsedAsCollateralDisabled(params.asset, params.from);
213:         }
214:       }
215: 
216:       if (params.balanceToBefore == 0) {
217:         DataTypes.UserConfigurationMap storage toConfig = usersConfig[params.to];
218:         if (
219:           ValidationLogic.validateAutomaticUseAsCollateral(
220:             reservesData,
221:             reservesList,
222:             toConfig,
223:             reserve.configuration,
224:             reserve.aTokenAddress
225:           )
226:         ) {
227:           toConfig.setUsingAsCollateral(reserveId, true);
228:           emit ReserveUsedAsCollateralEnabled(params.asset, params.to);
229:         }
230:       }
231:     }

['210']

210:     
211:     if (params.useATokens && params.amount == type(uint256).max) { // <= FOUND

['264']

264:     if (!paused && gracePeriod != 0) { // <= FOUND

['309']

309:     if (currentConfig.getLiquidationThreshold() != 0 && oldDebtCeiling == 0) { // <= FOUND

['579']

579:     require(
580:       totalSupplied == 0 && reserveData.accruedToTreasury == 0, // <= FOUND
581:       Errors.RESERVE_LIQUIDITY_NOT_ZERO
582:     );

['136']

136:     if (isCollateral && amountToWithdraw == userBalance) { // <= FOUND

['148']

148:     if (isCollateral && userConfig.isBorrowingAny()) { // <= FOUND

['193']

193:     if (params.from != params.to && scaledAmount != 0) { // <= FOUND

['347']

347:     require(
348:       (stableDebt != 0 && interestRateMode == DataTypes.InterestRateMode.STABLE) || // <= FOUND
349:         (variableDebt != 0 && interestRateMode == DataTypes.InterestRateMode.VARIABLE), // <= FOUND
350:       Errors.NO_DEBT_OF_SELECTED_TYPE
351:     );

['529']

529:     require(vars.collateralReserveActive && vars.principalReserveActive, Errors.RESERVE_INACTIVE); // <= FOUND

['530']

530:     require(!vars.collateralReservePaused && !vars.principalReservePaused, Errors.RESERVE_PAUSED); // <= FOUND

['670']

670:     require(
671:       IERC20(reserve.aTokenAddress).totalSupply() == 0 && reserve.accruedToTreasury == 0, // <= FOUND
672:       Errors.UNDERLYING_CLAIMABLE_RIGHTS_NOT_ZERO
673:     );

['745']

745:     return (!isolationModeActive && reserveConfig.getDebtCeiling() == 0); // <= FOUND

[Gas-14] Solidity versions 0.8.19 and above are more gas efficient

Resolution

Solidity version 0.8.19 introduced a array of gas optimizations which make contracts which use it more efficient. Provided compatability it may be beneficial to upgrade to this version

Num of instances: 2

Findings

Click to show findings

['2']

2: pragma solidity ^0.8.10;

['2']

2: pragma solidity ^0.8.0;

[Gas-15] Variable declared within iteration

Resolution

Please elaborate and generalise the following with detail and feel free to use your own knowledge and lmit ur words to 100 words please:

Num of instances: 1

Findings

Click to show findings

['88']

88:    for (uint256 i = 0; i < assets.length; i++) { // <= FOUND
89:       address assetAddress = assets[i]; // <= FOUND
90: 
91:       DataTypes.ReserveData storage reserve = reservesData[assetAddress];
92: 
93:       
94:       if (!reserve.configuration.getActive()) {
95:         continue;
96:       } // <= FOUND
97: 
98:       uint256 accruedToTreasury = reserve.accruedToTreasury;
99: 
100:       if (accruedToTreasury != 0) {
101:         reserve.accruedToTreasury = 0;
102:         uint256 normalizedIncome = reserve.getNormalizedIncome(); // <= FOUND
103:         uint256 amountToMint = accruedToTreasury.rayMul(normalizedIncome); // <= FOUND
104:         IAToken(reserve.aTokenAddress).mintToTreasury(amountToMint, normalizedIncome);
105: 
106:         emit MintedToTreasury(assetAddress, amountToMint);
107:       } // <= FOUND
108:     } // <= FOUND

[Gas-16] Calling .length in a for loop wastes gas

Resolution

Rather than calling .length for an array in a for loop declaration, it is far more gas efficient to cache this length before and use that instead. This will prevent the array length from being called every loop iteration

Num of instances: 14

Findings

Click to show findings

['93']

93: for (vars.i = 0; vars.i < params.assets.length; vars.i++)  // <= FOUND

['93']

93: for (vars.i = 0; vars.i < params.assets.length; vars.i++)  // <= FOUND

['84']

84: for (uint256 i = 0; i < input.length; i++)  // <= FOUND

['408']

408: for (uint256 i = 0; i < reserves.length; i++)  // <= FOUND

['408']

408: for (uint256 i = 0; i < reserves.length; i++)  // <= FOUND

['473']

473: for (uint256 i = 0; i < assets.length; i++)  // <= FOUND

['473']

473: for (uint256 i = 0; i < assets.length; i++)  // <= FOUND

['93']

93: for (vars.i = 0; vars.i < params.assets.length; vars.i++)  // <= FOUND

['93']

93: for (vars.i = 0; vars.i < params.assets.length; vars.i++)  // <= FOUND

['84']

84: for (uint256 i = 0; i < input.length; i++)  // <= FOUND

['408']

408: for (uint256 i = 0; i < reserves.length; i++)  // <= FOUND

['408']

408: for (uint256 i = 0; i < reserves.length; i++)  // <= FOUND

['473']

473: for (uint256 i = 0; i < assets.length; i++)  // <= FOUND

['473']

473: for (uint256 i = 0; i < assets.length; i++)  // <= FOUND

[Gas-17] Internal functions only used once can be inlined to save gas

Resolution

If a internal function is only used once it doesn't make sense to modularise it unless the function which does call the function would be overly long and complex otherwise

Num of instances: 57

Findings

Click to show findings

['184']

184:   function _getOverallBorrowRate( // <= FOUND
185:     uint256 totalStableDebt,
186:     uint256 totalVariableDebt,
187:     uint256 currentVariableBorrowRate,
188:     uint256 currentAverageStableBorrowRate
189:   ) internal pure returns (uint256) 

['252']

252:   function _burnCollateralATokens( // <= FOUND
253:     DataTypes.ReserveData storage collateralReserve,
254:     DataTypes.ExecuteLiquidationCallParams memory params,
255:     LiquidationCallLocalVars memory vars
256:   ) internal 

['286']

286:   function _liquidateATokens( // <= FOUND
287:     mapping(address => DataTypes.ReserveData) storage reservesData,
288:     mapping(uint256 => address) storage reservesList,
289:     mapping(address => DataTypes.UserConfigurationMap) storage usersConfig,
290:     DataTypes.ReserveData storage collateralReserve,
291:     DataTypes.ExecuteLiquidationCallParams memory params,
292:     LiquidationCallLocalVars memory vars
293:   ) internal 

['324']

324:   function _burnDebtTokens( // <= FOUND
325:     DataTypes.ExecuteLiquidationCallParams memory params,
326:     LiquidationCallLocalVars memory vars
327:   ) internal 

['364']

364:   function _calculateDebt( // <= FOUND
365:     DataTypes.ReserveCache memory debtReserveCache,
366:     DataTypes.ExecuteLiquidationCallParams memory params,
367:     uint256 healthFactor
368:   ) internal view returns (uint256, uint256, uint256) 

['399']

399:   function _getConfigurationData( // <= FOUND
400:     mapping(uint8 => DataTypes.EModeCategory) storage eModeCategories,
401:     DataTypes.ReserveData storage collateralReserve,
402:     DataTypes.ExecuteLiquidationCallParams memory params
403:   ) internal view returns (IAToken, address, address, uint256) 

['467']

467:   function _calculateAvailableCollateralToLiquidate( // <= FOUND
468:     DataTypes.ReserveData storage collateralReserve,
469:     DataTypes.ReserveCache memory debtReserveCache,
470:     address collateralAsset,
471:     address debtAsset,
472:     uint256 debtToCover,
473:     uint256 userCollateralBalance,
474:     uint256 liquidationBonus,
475:     IPriceOracleGetter oracle
476:   ) internal view returns (uint256, uint256, uint256) 

['68']

68:   function _onlyPoolConfigurator() internal view virtual  // <= FOUND

['82']

82:   function _onlyBridge() internal view virtual  // <= FOUND

['585']

585:   function _checkNoBorrowers(address asset) internal view  // <= FOUND

['597']

597:   function _onlyPoolOrEmergencyAdmin() internal view  // <= FOUND

['605']

605:   function _onlyAssetListingOrPoolAdmins() internal view  // <= FOUND

['613']

613:   function _onlyRiskOrPoolAdmins() internal view  // <= FOUND

['621']

621:   function _onlyRiskOrPoolOrEmergencyAdmins() internal view  // <= FOUND

['95']

95:   function setLiquidationThreshold( // <= FOUND
96:     DataTypes.ReserveConfigurationMap memory self,
97:     uint256 threshold
98:   ) internal pure 

['122']

122:   function setLiquidationBonus( // <= FOUND
123:     DataTypes.ReserveConfigurationMap memory self,
124:     uint256 bonus
125:   ) internal pure 

['138']

138:   function getLiquidationBonus( // <= FOUND
139:     DataTypes.ReserveConfigurationMap memory self
140:   ) internal pure returns (uint256) 

['205']

205:   function getFrozen(DataTypes.ReserveConfigurationMap memory self) internal pure returns (bool)  // <= FOUND

['248']

248:   function setBorrowableInIsolation( // <= FOUND
249:     address asset,
250:     bool borrowable
251:   ) external override onlyRiskOrPoolAdmins 

['238']

238:   function setBorrowableInIsolation( // <= FOUND
239:     DataTypes.ReserveConfigurationMap memory self,
240:     bool borrowable
241:   ) internal pure 

['256']

256:   function getBorrowableInIsolation( // <= FOUND
257:     DataTypes.ReserveConfigurationMap memory self
258:   ) internal pure returns (bool) 

['323']

323:   function setSiloedBorrowing( // <= FOUND
324:     address asset,
325:     bool newSiloed
326:   ) external override onlyRiskOrPoolAdmins 

['268']

268:   function setSiloedBorrowing( // <= FOUND
269:     DataTypes.ReserveConfigurationMap memory self,
270:     bool siloed
271:   ) internal pure 

['294']

294:   function setBorrowingEnabled( // <= FOUND
295:     DataTypes.ReserveConfigurationMap memory self,
296:     bool enabled
297:   ) internal pure 

['308']

308:   function getBorrowingEnabled( // <= FOUND
309:     DataTypes.ReserveConfigurationMap memory self
310:   ) internal pure returns (bool) 

['319']

319:   function setStableRateBorrowingEnabled( // <= FOUND
320:     DataTypes.ReserveConfigurationMap memory self,
321:     bool enabled
322:   ) internal pure 

['333']

333:   function getStableRateBorrowingEnabled( // <= FOUND
334:     DataTypes.ReserveConfigurationMap memory self
335:   ) internal pure returns (bool) 

['284']

284:   function setReserveFactor( // <= FOUND
285:     address asset,
286:     uint256 newReserveFactor
287:   ) external override onlyRiskOrPoolAdmins 

['344']

344:   function setReserveFactor( // <= FOUND
345:     DataTypes.ReserveConfigurationMap memory self,
346:     uint256 reserveFactor
347:   ) internal pure 

['342']

342:   function setBorrowCap( // <= FOUND
343:     address asset,
344:     uint256 newBorrowCap
345:   ) external override onlyRiskOrPoolAdmins 

['371']

371:   function setBorrowCap( // <= FOUND
372:     DataTypes.ReserveConfigurationMap memory self,
373:     uint256 borrowCap
374:   ) internal pure 

['354']

354:   function setSupplyCap( // <= FOUND
355:     address asset,
356:     uint256 newSupplyCap
357:   ) external override onlyRiskOrPoolAdmins 

['396']

396:   function setSupplyCap( // <= FOUND
397:     DataTypes.ReserveConfigurationMap memory self,
398:     uint256 supplyCap
399:   ) internal pure 

['302']

302:   function setDebtCeiling( // <= FOUND
303:     address asset,
304:     uint256 newDebtCeiling
305:   ) external override onlyRiskOrPoolAdmins 

['421']

421:   function setDebtCeiling( // <= FOUND
422:     DataTypes.ReserveConfigurationMap memory self,
423:     uint256 ceiling
424:   ) internal pure 

['366']

366:   function setLiquidationProtocolFee( // <= FOUND
367:     address asset,
368:     uint256 newFee
369:   ) external override onlyRiskOrPoolAdmins 

['446']

446:   function setLiquidationProtocolFee( // <= FOUND
447:     DataTypes.ReserveConfigurationMap memory self,
448:     uint256 liquidationProtocolFee
449:   ) internal pure 

['453']

453:   function setUnbackedMintCap( // <= FOUND
454:     address asset,
455:     uint256 newUnbackedMintCap
456:   ) external override onlyRiskOrPoolAdmins 

['477']

477:   function setUnbackedMintCap( // <= FOUND
478:     DataTypes.ReserveConfigurationMap memory self,
479:     uint256 unbackedMintCap
480:   ) internal pure 

['379']

379:   function setEModeCategory( // <= FOUND
380:     uint8 categoryId,
381:     uint16 ltv,
382:     uint16 liquidationThreshold,
383:     uint16 liquidationBonus,
384:     address oracle,
385:     string calldata label
386:   ) external override onlyRiskOrPoolAdmins 

['504']

504:   function setEModeCategory( // <= FOUND
505:     DataTypes.ReserveConfigurationMap memory self,
506:     uint256 category
507:   ) internal pure 

['529']

529:   function setFlashLoanEnabled( // <= FOUND
530:     DataTypes.ReserveConfigurationMap memory self,
531:     bool flashLoanEnabled
532:   ) internal pure 

['543']

543:   function getFlashLoanEnabled( // <= FOUND
544:     DataTypes.ReserveConfigurationMap memory self
545:   ) internal pure returns (bool) 

['554']

554:   function setVirtualAccActive( // <= FOUND
555:     DataTypes.ReserveConfigurationMap memory self,
556:     bool active
557:   ) internal pure 

['71']

71:   function getNormalizedDebt( // <= FOUND
72:     DataTypes.ReserveData storage reserve
73:   ) internal view returns (uint256) 

['243']

243:   function _accrueToTreasury( // <= FOUND
244:     DataTypes.ReserveData storage reserve,
245:     DataTypes.ReserveCache memory reserveCache
246:   ) internal 

['296']

296:   function _updateIndexes( // <= FOUND
297:     DataTypes.ReserveData storage reserve,
298:     DataTypes.ReserveCache memory reserveCache
299:   ) internal 

['98']

98:   function validateWithdraw( // <= FOUND
99:     DataTypes.ReserveCache memory reserveCache,
100:     uint256 amount,
101:     uint256 userBalance
102:   ) internal pure 

['141']

141:   function validateBorrow( // <= FOUND
142:     mapping(address => DataTypes.ReserveData) storage reservesData,
143:     mapping(uint256 => address) storage reservesList,
144:     mapping(uint8 => DataTypes.EModeCategory) storage eModeCategories,
145:     DataTypes.ValidateBorrowParams memory params
146:   ) internal view 

['329']

329:   function validateRepay( // <= FOUND
330:     DataTypes.ReserveCache memory reserveCache,
331:     uint256 amountSent,
332:     DataTypes.InterestRateMode interestRateMode,
333:     address onBehalfOf,
334:     uint256 stableDebt,
335:     uint256 variableDebt
336:   ) internal view 

['363']

363:   function validateSwapRateMode( // <= FOUND
364:     DataTypes.ReserveData storage reserve,
365:     DataTypes.ReserveCache memory reserveCache,
366:     DataTypes.UserConfigurationMap storage userConfig,
367:     uint256 stableDebt,
368:     uint256 variableDebt,
369:     DataTypes.InterestRateMode currentRateMode
370:   ) internal view 

['409']

409:   function validateRebalanceStableBorrowRate( // <= FOUND
410:     DataTypes.ReserveData storage reserve,
411:     DataTypes.ReserveCache memory reserveCache,
412:     address reserveAddress
413:   ) internal view 

['450']

450:   function validateSetUseReserveAsCollateral( // <= FOUND
451:     DataTypes.ReserveCache memory reserveCache,
452:     uint256 userBalance
453:   ) internal pure 

['512']

512:   function validateLiquidationCall( // <= FOUND
513:     DataTypes.UserConfigurationMap storage userConfig,
514:     DataTypes.ReserveData storage collateralReserve,
515:     DataTypes.ReserveData storage debtReserve,
516:     DataTypes.ValidateLiquidationCallParams memory params
517:   ) internal view 

['570']

570:   function validateHealthFactor( // <= FOUND
571:     mapping(address => DataTypes.ReserveData) storage reservesData,
572:     mapping(uint256 => address) storage reservesList,
573:     mapping(uint8 => DataTypes.EModeCategory) storage eModeCategories,
574:     DataTypes.UserConfigurationMap memory userConfig,
575:     address user,
576:     uint8 userEModeCategory,
577:     uint256 reservesCount,
578:     address oracle
579:   ) internal view returns (uint256, bool) 

['648']

648:   function validateTransfer(DataTypes.ReserveData storage reserve) internal view  // <= FOUND

['658']

658:   function validateDropReserve( // <= FOUND
659:     mapping(uint256 => address) storage reservesList,
660:     DataTypes.ReserveData storage reserve,
661:     address asset
662:   ) internal view 

[Gas-18] Constructors can be marked as payable to save deployment gas

Num of instances: 4

Findings

Click to show findings

['43']

43:   constructor(address provider) {
44:     require(provider != address(0), Errors.INVALID_ADDRESSES_PROVIDER);
45:     ADDRESSES_PROVIDER = IPoolAddressesProvider(provider);
46:   }

['9']

9:   constructor(IPoolAddressesProvider provider) PoolInstance(provider) {}

['93']

93:   constructor(IPoolAddressesProvider provider) {
94:     ADDRESSES_PROVIDER = provider;
95:   }

['11']

11:   constructor(IPoolAddressesProvider provider) Pool(provider) {}

[Gas-19] Assigning to structs can be more efficient

Resolution

Rather defining the struct in a single line, it is more efficient to declare an empty struct and then assign each struct element individually. This can net quite a large gas saving of 130 per instance.

Num of instances: 2

Findings

Click to show findings

['265']

265:   function repayWithPermit( // <= FOUND
266:     address asset,
267:     uint256 amount,
268:     uint256 interestRateMode,
269:     address onBehalfOf,
270:     uint256 deadline,
271:     uint8 permitV,
272:     bytes32 permitR,
273:     bytes32 permitS
274:   ) public virtual override returns (uint256) { // <= FOUND
275:     try
276:       IERC20WithPermit(asset).permit( // <= FOUND
277:         msg.sender,
278:         address(this), // <= FOUND
279:         amount,
280:         deadline,
281:         permitV,
282:         permitR,
283:         permitS
284:       )
285:     {} catch {}
286: 
287:     {
288:       DataTypes.ExecuteRepayParams memory params = DataTypes.ExecuteRepayParams({ // <= FOUND
289:         asset: asset,
290:         amount: amount,
291:         interestRateMode: DataTypes.InterestRateMode(interestRateMode), // <= FOUND
292:         onBehalfOf: onBehalfOf,
293:         useATokens: false
294:       });
295:       return BorrowLogic.executeRepay(_reserves, _reservesList, _usersConfig[onBehalfOf], params); // <= FOUND
296:     }
297:   }

['432']

432:   function flashLoanSimple( // <= FOUND
433:     address receiverAddress,
434:     address asset,
435:     uint256 amount,
436:     bytes calldata params,
437:     uint16 referralCode
438:   ) public virtual override {
439:     DataTypes.FlashloanSimpleParams memory flashParams = DataTypes.FlashloanSimpleParams({ // <= FOUND
440:       receiverAddress: receiverAddress,
441:       asset: asset,
442:       amount: amount,
443:       params: params,
444:       referralCode: referralCode,
445:       flashLoanPremiumToProtocol: _flashLoanPremiumToProtocol,
446:       flashLoanPremiumTotal: _flashLoanPremiumTotal
447:     });
448:     FlashLoanLogic.executeFlashLoanSimple(_reserves[asset], flashParams); // <= FOUND
449:   }

[Gas-20] Only emit event in setter function if the state variable was changed

Resolution

Emitting events in setter functions of smart contracts only when state variables change saves gas. This is because emitting events consumes gas, and unnecessary events, where no actual state change occurs, lead to wasteful consumption.

Num of instances: 16

Findings

Click to show findings

['124']

124:   function setReserveBorrowing(address asset, bool enabled) external override onlyRiskOrPoolAdmins { // <= FOUND
125:     DataTypes.ReserveConfigurationMap memory currentConfig = _pool.getConfiguration(asset);
126:     if (!enabled) {
127:       require(!currentConfig.getStableRateBorrowingEnabled(), Errors.STABLE_BORROWING_ENABLED);
128:     }
129:     currentConfig.setBorrowingEnabled(enabled);
130:     _pool.setConfiguration(asset, currentConfig);
131:     emit ReserveBorrowing(asset, enabled); // <= FOUND
132:   }

['185']

185:   function setReserveStableRateBorrowing( // <= FOUND
186:     address asset,
187:     bool enabled
188:   ) external override onlyRiskOrPoolAdmins {
189:     DataTypes.ReserveConfigurationMap memory currentConfig = _pool.getConfiguration(asset);
190:     if (enabled) {
191:       require(currentConfig.getBorrowingEnabled(), Errors.BORROWING_NOT_ENABLED);
192:     }
193:     currentConfig.setStableRateBorrowingEnabled(enabled);
194:     _pool.setConfiguration(asset, currentConfig);
195:     emit ReserveStableRateBorrowing(asset, enabled); // <= FOUND
196:   }

['199']

199:   function setReserveFlashLoaning( // <= FOUND
200:     address asset,
201:     bool enabled
202:   ) external override onlyRiskOrPoolAdmins {
203:     DataTypes.ReserveConfigurationMap memory currentConfig = _pool.getConfiguration(asset);
204: 
205:     currentConfig.setFlashLoanEnabled(enabled);
206:     _pool.setConfiguration(asset, currentConfig);
207:     emit ReserveFlashLoaning(asset, enabled); // <= FOUND
208:   }

['211']

211:   function setReserveActive(address asset, bool active) external override onlyPoolAdmin { // <= FOUND
212:     if (!active) _checkNoSuppliers(asset);
213:     DataTypes.ReserveConfigurationMap memory currentConfig = _pool.getConfiguration(asset);
214:     currentConfig.setActive(active);
215:     _pool.setConfiguration(asset, currentConfig);
216:     emit ReserveActive(asset, active); // <= FOUND
217:   }

['220']

220:   function setReserveFreeze( // <= FOUND
221:     address asset,
222:     bool freeze
223:   ) external override onlyRiskOrPoolOrEmergencyAdmins {
224:     DataTypes.ReserveConfigurationMap memory currentConfig = _pool.getConfiguration(asset);
225:     currentConfig.setFrozen(freeze);
226: 
227:     if (freeze) {
228:       _pendingLtv[asset] = currentConfig.getLtv();
229:       _isPendingLtvSet[asset] = true;
230:       currentConfig.setLtv(0);
231: 
232:       emit PendingLtvChanged(asset, currentConfig.getLtv()); // <= FOUND
233:     } else if (_isPendingLtvSet[asset]) {
234:       uint256 ltv = _pendingLtv[asset];
235:       currentConfig.setLtv(ltv);
236: 
237:       delete _pendingLtv[asset];
238:       delete _isPendingLtvSet[asset];
239: 
240:       emit PendingLtvRemoved(asset); // <= FOUND
241:     }
242: 
243:     _pool.setConfiguration(asset, currentConfig);
244:     emit ReserveFrozen(asset, freeze); // <= FOUND
245:   }

['248']

248:   function setBorrowableInIsolation( // <= FOUND
249:     address asset,
250:     bool borrowable
251:   ) external override onlyRiskOrPoolAdmins {
252:     DataTypes.ReserveConfigurationMap memory currentConfig = _pool.getConfiguration(asset);
253:     currentConfig.setBorrowableInIsolation(borrowable);
254:     _pool.setConfiguration(asset, currentConfig);
255:     emit BorrowableInIsolationChanged(asset, borrowable); // <= FOUND
256:   }

['284']

284:   function setReserveFactor( // <= FOUND
285:     address asset,
286:     uint256 newReserveFactor
287:   ) external override onlyRiskOrPoolAdmins {
288:     require(newReserveFactor <= PercentageMath.PERCENTAGE_FACTOR, Errors.INVALID_RESERVE_FACTOR);
289: 
290:     _pool.syncIndexesState(asset);
291: 
292:     DataTypes.ReserveConfigurationMap memory currentConfig = _pool.getConfiguration(asset);
293:     uint256 oldReserveFactor = currentConfig.getReserveFactor();
294:     currentConfig.setReserveFactor(newReserveFactor);
295:     _pool.setConfiguration(asset, currentConfig);
296:     emit ReserveFactorChanged(asset, oldReserveFactor, newReserveFactor); // <= FOUND
297: 
298:     _pool.syncRatesState(asset);
299:   }

['323']

323:   function setSiloedBorrowing( // <= FOUND
324:     address asset,
325:     bool newSiloed
326:   ) external override onlyRiskOrPoolAdmins {
327:     if (newSiloed) {
328:       _checkNoBorrowers(asset);
329:     }
330:     DataTypes.ReserveConfigurationMap memory currentConfig = _pool.getConfiguration(asset);
331: 
332:     bool oldSiloed = currentConfig.getSiloedBorrowing();
333: 
334:     currentConfig.setSiloedBorrowing(newSiloed);
335: 
336:     _pool.setConfiguration(asset, currentConfig);
337: 
338:     emit SiloedBorrowingChanged(asset, oldSiloed, newSiloed); // <= FOUND
339:   }

['342']

342:   function setBorrowCap( // <= FOUND
343:     address asset,
344:     uint256 newBorrowCap
345:   ) external override onlyRiskOrPoolAdmins {
346:     DataTypes.ReserveConfigurationMap memory currentConfig = _pool.getConfiguration(asset);
347:     uint256 oldBorrowCap = currentConfig.getBorrowCap();
348:     currentConfig.setBorrowCap(newBorrowCap);
349:     _pool.setConfiguration(asset, currentConfig);
350:     emit BorrowCapChanged(asset, oldBorrowCap, newBorrowCap); // <= FOUND
351:   }

['354']

354:   function setSupplyCap( // <= FOUND
355:     address asset,
356:     uint256 newSupplyCap
357:   ) external override onlyRiskOrPoolAdmins {
358:     DataTypes.ReserveConfigurationMap memory currentConfig = _pool.getConfiguration(asset);
359:     uint256 oldSupplyCap = currentConfig.getSupplyCap();
360:     currentConfig.setSupplyCap(newSupplyCap);
361:     _pool.setConfiguration(asset, currentConfig);
362:     emit SupplyCapChanged(asset, oldSupplyCap, newSupplyCap); // <= FOUND
363:   }

['366']

366:   function setLiquidationProtocolFee( // <= FOUND
367:     address asset,
368:     uint256 newFee
369:   ) external override onlyRiskOrPoolAdmins {
370:     require(newFee <= PercentageMath.PERCENTAGE_FACTOR, Errors.INVALID_LIQUIDATION_PROTOCOL_FEE);
371:     DataTypes.ReserveConfigurationMap memory currentConfig = _pool.getConfiguration(asset);
372:     uint256 oldFee = currentConfig.getLiquidationProtocolFee();
373:     currentConfig.setLiquidationProtocolFee(newFee);
374:     _pool.setConfiguration(asset, currentConfig);
375:     emit LiquidationProtocolFeeChanged(asset, oldFee, newFee); // <= FOUND
376:   }

['453']

453:   function setUnbackedMintCap( // <= FOUND
454:     address asset,
455:     uint256 newUnbackedMintCap
456:   ) external override onlyRiskOrPoolAdmins {
457:     DataTypes.ReserveConfigurationMap memory currentConfig = _pool.getConfiguration(asset);
458:     uint256 oldUnbackedMintCap = currentConfig.getUnbackedMintCap();
459:     currentConfig.setUnbackedMintCap(newUnbackedMintCap);
460:     _pool.setConfiguration(asset, currentConfig);
461:     emit UnbackedMintCapChanged(asset, oldUnbackedMintCap, newUnbackedMintCap); // <= FOUND
462:   }

['500']

500:   function updateBridgeProtocolFee(uint256 newBridgeProtocolFee) external override onlyPoolAdmin { // <= FOUND
501:     require(
502:       newBridgeProtocolFee <= PercentageMath.PERCENTAGE_FACTOR,
503:       Errors.BRIDGE_PROTOCOL_FEE_INVALID
504:     );
505:     uint256 oldBridgeProtocolFee = _pool.BRIDGE_PROTOCOL_FEE();
506:     _pool.updateBridgeProtocolFee(newBridgeProtocolFee);
507:     emit BridgeProtocolFeeUpdated(oldBridgeProtocolFee, newBridgeProtocolFee); // <= FOUND
508:   }

['511']

511:   function updateFlashloanPremiumTotal( // <= FOUND
512:     uint128 newFlashloanPremiumTotal
513:   ) external override onlyPoolAdmin {
514:     require(
515:       newFlashloanPremiumTotal <= PercentageMath.PERCENTAGE_FACTOR,
516:       Errors.FLASHLOAN_PREMIUM_INVALID
517:     );
518:     uint128 oldFlashloanPremiumTotal = _pool.FLASHLOAN_PREMIUM_TOTAL();
519:     _pool.updateFlashloanPremiums(newFlashloanPremiumTotal, _pool.FLASHLOAN_PREMIUM_TO_PROTOCOL());
520:     emit FlashloanPremiumTotalUpdated(oldFlashloanPremiumTotal, newFlashloanPremiumTotal); // <= FOUND
521:   }

['524']

524:   function updateFlashloanPremiumToProtocol( // <= FOUND
525:     uint128 newFlashloanPremiumToProtocol
526:   ) external override onlyPoolAdmin {
527:     require(
528:       newFlashloanPremiumToProtocol <= PercentageMath.PERCENTAGE_FACTOR,
529:       Errors.FLASHLOAN_PREMIUM_INVALID
530:     );
531:     uint128 oldFlashloanPremiumToProtocol = _pool.FLASHLOAN_PREMIUM_TO_PROTOCOL();
532:     _pool.updateFlashloanPremiums(_pool.FLASHLOAN_PREMIUM_TOTAL(), newFlashloanPremiumToProtocol);
533:     emit FlashloanPremiumToProtocolUpdated( // <= FOUND
534:       oldFlashloanPremiumToProtocol,
535:       newFlashloanPremiumToProtocol
536:     );
537:   }

['172']

172:   function updateInterestRatesAndVirtualBalance( // <= FOUND
173:     DataTypes.ReserveData storage reserve,
174:     DataTypes.ReserveCache memory reserveCache,
175:     address reserveAddress,
176:     uint256 liquidityAdded,
177:     uint256 liquidityTaken
178:   ) internal {
179:     UpdateInterestRatesAndVirtualBalanceLocalVars memory vars;
180: 
181:     vars.totalVariableDebt = reserveCache.nextScaledVariableDebt.rayMul(
182:       reserveCache.nextVariableBorrowIndex
183:     );
184: 
185:     (
186:       vars.nextLiquidityRate,
187:       vars.nextStableRate,
188:       vars.nextVariableRate
189:     ) = IReserveInterestRateStrategy(reserve.interestRateStrategyAddress).calculateInterestRates(
190:       DataTypes.CalculateInterestRatesParams({
191:         unbacked: reserve.unbacked,
192:         liquidityAdded: liquidityAdded,
193:         liquidityTaken: liquidityTaken,
194:         totalStableDebt: reserveCache.nextTotalStableDebt,
195:         totalVariableDebt: vars.totalVariableDebt,
196:         averageStableBorrowRate: reserveCache.nextAvgStableBorrowRate,
197:         reserveFactor: reserveCache.reserveFactor,
198:         reserve: reserveAddress,
199:         usingVirtualBalance: reserve.configuration.getIsVirtualAccActive(),
200:         virtualUnderlyingBalance: reserve.virtualUnderlyingBalance
201:       })
202:     );
203: 
204:     reserve.currentLiquidityRate = vars.nextLiquidityRate.toUint128();
205:     reserve.currentStableBorrowRate = vars.nextStableRate.toUint128();
206:     reserve.currentVariableBorrowRate = vars.nextVariableRate.toUint128();
207: 
209:     if (reserve.configuration.getIsVirtualAccActive()) {
210:       if (liquidityAdded > 0) {
211:         reserve.virtualUnderlyingBalance += liquidityAdded.toUint128();
212:       }
213:       if (liquidityTaken > 0) {
214:         reserve.virtualUnderlyingBalance -= liquidityTaken.toUint128();
215:       }
216:     }
217: 
218:     emit ReserveDataUpdated( // <= FOUND
219:       reserveAddress,
220:       vars.nextLiquidityRate,
221:       vars.nextStableRate,
222:       vars.nextVariableRate,
223:       reserveCache.nextLiquidityIndex,
224:       reserveCache.nextVariableBorrowIndex
225:     );
226:   }

[Gas-21] It is a waste of GAS to emit variable literals

Resolution

Emitting variable literals (true, false, 'hello', 1 etc...) in events is inefficient, as it consumes extra gas without providing added value. These literals are fixed values that can be accessed or hardcoded elsewhere in the smart contract or application, making their inclusion in events redundant and an unnecessary drain on resources during transaction execution.

Num of instances: 2

Findings

Click to show findings

['168']

168:         
169:         emit FlashLoan( // <= FOUND
170:           params.receiverAddress,
171:           msg.sender,
172:           vars.currentAsset,
173:           vars.currentAmount,
174:           DataTypes.InterestRateMode(params.interestRateModes[vars.i]),
175:           0, // <= FOUND
176:           params.referralCode
177:         );

['123']

123:     emit IsolationModeTotalDebtUpdated(asset, 0); // <= FOUND

[Gas-22] Use OZ Array.unsafeAccess() to avoid repeated array length checks

Resolution

The OpenZeppelin Array.unsafeAccess() method is a optimization strategy for Solidity, aimed at reducing gas costs by bypassing automatic length checks on storage array accesses. In Solidity, every access to an array element involves a hidden gas cost due to a length check, ensuring that accesses do not exceed the array bounds. However, if a developer has already verified the array's bounds earlier in the function or knows through logic that the access is safe, directly accessing the array elements without redundant length checks can save gas. This approach requires careful consideration to avoid out-of-bounds errors, as it trades off safety checks for efficiency.

Num of instances: 13

Findings

Click to show findings

['562']

562:       if (_reservesList[i] != address(0)) { // <= FOUND

['563']

563:         reservesList[i - droppedReservesCount] = _reservesList[i]; // <= FOUND

['85']

85:       require(IERC20Detailed(input[i].underlyingAsset).decimals() > 5, Errors.INVALID_DECIMALS); // <= FOUND

['87']

87:       ConfiguratorLogic.executeInitReserve(cachedPool, input[i]); // <= FOUND

['88']

88:       emit ReserveInterestRateDataChanged(
89:         input[i].underlyingAsset, // <= FOUND
90:         input[i].interestRateStrategyAddress, // <= FOUND
91:         input[i].interestRateData // <= FOUND
92:       );

['409']

409:       DataTypes.ReserveConfigurationMap memory currentConfig = _pool.getConfiguration(reserves[i]); // <= FOUND

['488']

488:       if (reserves[i] != address(0)) { // <= FOUND

['489']

489:         setReservePause(reserves[i], paused, gracePeriod); // <= FOUND

['56']

56:       if (reservesList[i] == address(0)) { // <= FOUND

['58']

58:         reservesList[i] = params.asset; // <= FOUND

['89']

89:       address assetAddress = assets[i]; // <= FOUND

['474']

474:       validateFlashloanSimple(reservesData[assets[i]], amounts[i]); // <= FOUND

['710']

710:             DataTypes.ReserveConfigurationMap memory configuration = reservesData[reservesList[i]] // <= FOUND
711:               .configuration;

[Gas-23] Use uint256(1)/uint256(2) instead of true/false to save gas for changes

Resolution

In Solidity, the use of uint256 values instead of boolean for certain state variables can result in gas savings. This is due to how Ethereum's storage optimization works: changing a variable from 0 to a non-zero value (like flipping false to true) incurs a higher gas cost compared to modifying an already non-zero value. By using uint256 with values 1 and 2 instead of true and false, you avoid the higher cost associated with the 0 to non-zero change, since 1 and 2 are both non-zero. This approach is notably used in OpenZeppelin's ReentrancyGuard as a gas optimization technique. However, this should be applied where it makes sense and where gas optimization is critical, as it can decrease code readability.

Num of instances: 1

Findings

Click to show findings

['169']

169:       _isPendingLtvSet[asset] = true; // <= FOUND

[Gas-24] Avoid emitting events in loops

Resolution

Emitting events inside loops can significantly increase gas costs in Ethereum smart contracts, as each event emission consumes gas. This practice can quickly escalate transaction fees, especially with a high number of iterations. To optimize for efficiency and cost, it's advisable to minimize event emissions within loops, possibly aggregating data to emit a single event post-loop or reconsidering the design to reduce looped emissions. This approach helps maintain manageable transaction costs and enhances contract performance.

Num of instances: 10

Findings

Click to show findings

['84']

84:    for (uint256 i = 0; i < input.length; i++) {
85:       require(IERC20Detailed(input[i].underlyingAsset).decimals() > 5, Errors.INVALID_DECIMALS);
86: 
87:       ConfiguratorLogic.executeInitReserve(cachedPool, input[i]);
88:       emit ReserveInterestRateDataChanged( // <= FOUND
89:         input[i].underlyingAsset,
90:         input[i].interestRateStrategyAddress,
91:         input[i].interestRateData
92:       );
93:     }

['88']

88:    for (uint256 i = 0; i < assets.length; i++) {
89:       address assetAddress = assets[i];
90: 
91:       DataTypes.ReserveData storage reserve = reservesData[assetAddress];
92: 
93:       
94:       if (!reserve.configuration.getActive()) {
95:         continue;
96:       }
97: 
98:       uint256 accruedToTreasury = reserve.accruedToTreasury;
99: 
100:       if (accruedToTreasury != 0) {
101:         reserve.accruedToTreasury = 0;
102:         uint256 normalizedIncome = reserve.getNormalizedIncome();
103:         uint256 amountToMint = accruedToTreasury.rayMul(normalizedIncome);
104:         IAToken(reserve.aTokenAddress).mintToTreasury(amountToMint, normalizedIncome);
105: 
106:         emit MintedToTreasury(assetAddress, amountToMint); // <= FOUND
107:       }
108:     }

['123']

123:     for (vars.i = 0; vars.i < params.assets.length; vars.i++) {
124:       vars.currentAsset = params.assets[vars.i];
125:       vars.currentAmount = params.amounts[vars.i];
126: 
127:       if (
128:         DataTypes.InterestRateMode(params.interestRateModes[vars.i]) ==
129:         DataTypes.InterestRateMode.NONE
130:       ) {
131:         _handleFlashLoanRepayment(
132:           reservesData[vars.currentAsset],
133:           DataTypes.FlashLoanRepaymentParams({
134:             asset: vars.currentAsset,
135:             receiverAddress: params.receiverAddress,
136:             amount: vars.currentAmount,
137:             totalPremium: vars.totalPremiums[vars.i],
138:             flashLoanPremiumToProtocol: vars.flashloanPremiumToProtocol,
139:             referralCode: params.referralCode
140:           })
141:         );
142:       } else {
143:         
144:         
145:         BorrowLogic.executeBorrow(
146:           reservesData,
147:           reservesList,
148:           eModeCategories,
149:           userConfig,
150:           DataTypes.ExecuteBorrowParams({
151:             asset: vars.currentAsset,
152:             user: msg.sender,
153:             onBehalfOf: params.onBehalfOf,
154:             amount: vars.currentAmount,
155:             interestRateMode: DataTypes.InterestRateMode(params.interestRateModes[vars.i]),
156:             referralCode: params.referralCode,
157:             releaseUnderlying: false,
158:             maxStableRateBorrowSizePercent: IPool(params.pool)
159:               .MAX_STABLE_RATE_BORROW_SIZE_PERCENT(),
160:             reservesCount: IPool(params.pool).getReservesCount(),
161:             oracle: IPoolAddressesProvider(params.addressesProvider).getPriceOracle(),
162:             userEModeCategory: IPool(params.pool).getUserEMode(params.onBehalfOf).toUint8(),
163:             priceOracleSentinel: IPoolAddressesProvider(params.addressesProvider)
164:               .getPriceOracleSentinel()
165:           })
166:         );
167:         
168:         emit FlashLoan( // <= FOUND
169:           params.receiverAddress,
170:           msg.sender,
171:           vars.currentAsset,
172:           vars.currentAmount,
173:           DataTypes.InterestRateMode(params.interestRateModes[vars.i]),
174:           0,
175:           params.referralCode
176:         );
177:       }
178:     }

['84']

84:     for (uint256 i = 0; i < input.length; i++) {
85:       require(IERC20Detailed(input[i].underlyingAsset).decimals() > 5, Errors.INVALID_DECIMALS);
86: 
87:       ConfiguratorLogic.executeInitReserve(cachedPool, input[i]);
88:       emit ReserveInterestRateDataChanged( // <= FOUND
89:         input[i].underlyingAsset,
90:         input[i].interestRateStrategyAddress,
91:         input[i].interestRateData
92:       );
93:     }

['88']

88:     for (uint256 i = 0; i < assets.length; i++) {
89:       address assetAddress = assets[i];
90: 
91:       DataTypes.ReserveData storage reserve = reservesData[assetAddress];
92: 
93:       
94:       if (!reserve.configuration.getActive()) {
95:         continue;
96:       }
97: 
98:       uint256 accruedToTreasury = reserve.accruedToTreasury;
99: 
100:       if (accruedToTreasury != 0) {
101:         reserve.accruedToTreasury = 0;
102:         uint256 normalizedIncome = reserve.getNormalizedIncome();
103:         uint256 amountToMint = accruedToTreasury.rayMul(normalizedIncome);
104:         IAToken(reserve.aTokenAddress).mintToTreasury(amountToMint, normalizedIncome);
105: 
106:         emit MintedToTreasury(assetAddress, amountToMint); // <= FOUND
107:       }
108:     }

['84']

84:    for (uint256 i = 0; i < input.length; i++) {
85:       require(IERC20Detailed(input[i].underlyingAsset).decimals() > 5, Errors.INVALID_DECIMALS);
86: 
87:       ConfiguratorLogic.executeInitReserve(cachedPool, input[i]);
88:       emit ReserveInterestRateDataChanged( // <= FOUND
89:         input[i].underlyingAsset,
90:         input[i].interestRateStrategyAddress,
91:         input[i].interestRateData
92:       );
93:     }

['88']

88:    for (uint256 i = 0; i < assets.length; i++) {
89:       address assetAddress = assets[i];
90: 
91:       DataTypes.ReserveData storage reserve = reservesData[assetAddress];
92: 
93:       
94:       if (!reserve.configuration.getActive()) {
95:         continue;
96:       }
97: 
98:       uint256 accruedToTreasury = reserve.accruedToTreasury;
99: 
100:       if (accruedToTreasury != 0) {
101:         reserve.accruedToTreasury = 0;
102:         uint256 normalizedIncome = reserve.getNormalizedIncome();
103:         uint256 amountToMint = accruedToTreasury.rayMul(normalizedIncome);
104:         IAToken(reserve.aTokenAddress).mintToTreasury(amountToMint, normalizedIncome);
105: 
106:         emit MintedToTreasury(assetAddress, amountToMint); // <= FOUND
107:       }
108:     }

['123']

123:     for (vars.i = 0; vars.i < params.assets.length; vars.i++) {
124:       vars.currentAsset = params.assets[vars.i];
125:       vars.currentAmount = params.amounts[vars.i];
126: 
127:       if (
128:         DataTypes.InterestRateMode(params.interestRateModes[vars.i]) ==
129:         DataTypes.InterestRateMode.NONE
130:       ) {
131:         _handleFlashLoanRepayment(
132:           reservesData[vars.currentAsset],
133:           DataTypes.FlashLoanRepaymentParams({
134:             asset: vars.currentAsset,
135:             receiverAddress: params.receiverAddress,
136:             amount: vars.currentAmount,
137:             totalPremium: vars.totalPremiums[vars.i],
138:             flashLoanPremiumToProtocol: vars.flashloanPremiumToProtocol,
139:             referralCode: params.referralCode
140:           })
141:         );
142:       } else {
143:         
144:         
145:         BorrowLogic.executeBorrow(
146:           reservesData,
147:           reservesList,
148:           eModeCategories,
149:           userConfig,
150:           DataTypes.ExecuteBorrowParams({
151:             asset: vars.currentAsset,
152:             user: msg.sender,
153:             onBehalfOf: params.onBehalfOf,
154:             amount: vars.currentAmount,
155:             interestRateMode: DataTypes.InterestRateMode(params.interestRateModes[vars.i]),
156:             referralCode: params.referralCode,
157:             releaseUnderlying: false,
158:             maxStableRateBorrowSizePercent: IPool(params.pool)
159:               .MAX_STABLE_RATE_BORROW_SIZE_PERCENT(),
160:             reservesCount: IPool(params.pool).getReservesCount(),
161:             oracle: IPoolAddressesProvider(params.addressesProvider).getPriceOracle(),
162:             userEModeCategory: IPool(params.pool).getUserEMode(params.onBehalfOf).toUint8(),
163:             priceOracleSentinel: IPoolAddressesProvider(params.addressesProvider)
164:               .getPriceOracleSentinel()
165:           })
166:         );
167:         
168:         emit FlashLoan( // <= FOUND
169:           params.receiverAddress,
170:           msg.sender,
171:           vars.currentAsset,
172:           vars.currentAmount,
173:           DataTypes.InterestRateMode(params.interestRateModes[vars.i]),
174:           0,
175:           params.referralCode
176:         );
177:       }
178:     }

['84']

84:     for (uint256 i = 0; i < input.length; i++) {
85:       require(IERC20Detailed(input[i].underlyingAsset).decimals() > 5, Errors.INVALID_DECIMALS);
86: 
87:       ConfiguratorLogic.executeInitReserve(cachedPool, input[i]);
88:       emit ReserveInterestRateDataChanged( // <= FOUND
89:         input[i].underlyingAsset,
90:         input[i].interestRateStrategyAddress,
91:         input[i].interestRateData
92:       );
93:     }

['88']

88:     for (uint256 i = 0; i < assets.length; i++) {
89:       address assetAddress = assets[i];
90: 
91:       DataTypes.ReserveData storage reserve = reservesData[assetAddress];
92: 
93:       
94:       if (!reserve.configuration.getActive()) {
95:         continue;
96:       }
97: 
98:       uint256 accruedToTreasury = reserve.accruedToTreasury;
99: 
100:       if (accruedToTreasury != 0) {
101:         reserve.accruedToTreasury = 0;
102:         uint256 normalizedIncome = reserve.getNormalizedIncome();
103:         uint256 amountToMint = accruedToTreasury.rayMul(normalizedIncome);
104:         IAToken(reserve.aTokenAddress).mintToTreasury(amountToMint, normalizedIncome);
105: 
106:         emit MintedToTreasury(assetAddress, amountToMint); // <= FOUND
107:       }
108:     }

[Gas-25] Use constants instead of type(uint).max

Resolution

In smart contract development, utilizing constants for known maximum or minimum values, rather than computing type(uint<n>).max or assuming 0 for .min, can significantly reduce gas costs. Constants require less runtime computation and storage, optimizing contract efficiency—a crucial strategy for developers aiming for cost-effective and performant code.

Num of instances: 3

Findings

Click to show findings

['210']

210:     if (params.useATokens && params.amount == type(uint256).max) { // <= FOUND

['126']

126:     if (params.amount == type(uint256).max) { // <= FOUND

['339']

339:       amountSent != type(uint256).max || msg.sender == onBehalfOf, // <= FOUND
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment