LCOV - code coverage report
Current view: top level - protocol/libraries/logic - BorrowLogic.sol (source / functions) Coverage Total Hit
Test: lcov.info.p Lines: 100.0 % 41 41
Test Date: 2024-09-24 09:34:24 Functions: 100.0 % 2 2
Branches: - 0 0

             Branch data     Line data    Source code
       1                 :             : // SPDX-License-Identifier: BUSL-1.1
       2                 :             : pragma solidity ^0.8.10;
       3                 :             : 
       4                 :             : import {GPv2SafeERC20} from '../../../dependencies/gnosis/contracts/GPv2SafeERC20.sol';
       5                 :             : import {SafeCast} from '../../../dependencies/openzeppelin/contracts/SafeCast.sol';
       6                 :             : import {IERC20} from '../../../dependencies/openzeppelin/contracts/IERC20.sol';
       7                 :             : import {IVariableDebtToken} from '../../../interfaces/IVariableDebtToken.sol';
       8                 :             : import {IAToken} from '../../../interfaces/IAToken.sol';
       9                 :             : import {UserConfiguration} from '../configuration/UserConfiguration.sol';
      10                 :             : import {ReserveConfiguration} from '../configuration/ReserveConfiguration.sol';
      11                 :             : import {DataTypes} from '../types/DataTypes.sol';
      12                 :             : import {ValidationLogic} from './ValidationLogic.sol';
      13                 :             : import {ReserveLogic} from './ReserveLogic.sol';
      14                 :             : import {IsolationModeLogic} from './IsolationModeLogic.sol';
      15                 :             : 
      16                 :             : /**
      17                 :             :  * @title BorrowLogic library
      18                 :             :  * @author Aave
      19                 :             :  * @notice Implements the base logic for all the actions related to borrowing
      20                 :             :  */
      21                 :             : library BorrowLogic {
      22                 :             :   using ReserveLogic for DataTypes.ReserveCache;
      23                 :             :   using ReserveLogic for DataTypes.ReserveData;
      24                 :             :   using GPv2SafeERC20 for IERC20;
      25                 :             :   using UserConfiguration for DataTypes.UserConfigurationMap;
      26                 :             :   using ReserveConfiguration for DataTypes.ReserveConfigurationMap;
      27                 :             :   using SafeCast for uint256;
      28                 :             : 
      29                 :             :   // See `IPool` for descriptions
      30                 :             :   event Borrow(
      31                 :             :     address indexed reserve,
      32                 :             :     address user,
      33                 :             :     address indexed onBehalfOf,
      34                 :             :     uint256 amount,
      35                 :             :     DataTypes.InterestRateMode interestRateMode,
      36                 :             :     uint256 borrowRate,
      37                 :             :     uint16 indexed referralCode
      38                 :             :   );
      39                 :             :   event Repay(
      40                 :             :     address indexed reserve,
      41                 :             :     address indexed user,
      42                 :             :     address indexed repayer,
      43                 :             :     uint256 amount,
      44                 :             :     bool useATokens
      45                 :             :   );
      46                 :             :   event IsolationModeTotalDebtUpdated(address indexed asset, uint256 totalDebt);
      47                 :             :   event ReserveUsedAsCollateralDisabled(address indexed reserve, address indexed user);
      48                 :             : 
      49                 :             :   /**
      50                 :             :    * @notice Implements the borrow feature. Borrowing allows users that provided collateral to draw liquidity from the
      51                 :             :    * Aave protocol proportionally to their collateralization power. For isolated positions, it also increases the
      52                 :             :    * isolated debt.
      53                 :             :    * @dev  Emits the `Borrow()` event
      54                 :             :    * @param reservesData The state of all the reserves
      55                 :             :    * @param reservesList The addresses of all the active reserves
      56                 :             :    * @param eModeCategories The configuration of all the efficiency mode categories
      57                 :             :    * @param userConfig The user configuration mapping that tracks the supplied/borrowed assets
      58                 :             :    * @param params The additional parameters needed to execute the borrow function
      59                 :             :    */
      60                 :             :   function executeBorrow(
      61                 :             :     mapping(address => DataTypes.ReserveData) storage reservesData,
      62                 :             :     mapping(uint256 => address) storage reservesList,
      63                 :             :     mapping(uint8 => DataTypes.EModeCategory) storage eModeCategories,
      64                 :             :     DataTypes.UserConfigurationMap storage userConfig,
      65                 :             :     DataTypes.ExecuteBorrowParams memory params
      66                 :             :   ) external {
      67                 :       16110 :     DataTypes.ReserveData storage reserve = reservesData[params.asset];
      68                 :       16110 :     DataTypes.ReserveCache memory reserveCache = reserve.cache();
      69                 :             : 
      70                 :       16110 :     reserve.updateState(reserveCache);
      71                 :             : 
      72                 :       16110 :     (
      73                 :             :       bool isolationModeActive,
      74                 :             :       address isolationModeCollateralAddress,
      75                 :             :       uint256 isolationModeDebtCeiling
      76                 :       16110 :     ) = userConfig.getIsolationModeState(reservesData, reservesList);
      77                 :             : 
      78                 :       16110 :     ValidationLogic.validateBorrow(
      79                 :             :       reservesData,
      80                 :             :       reservesList,
      81                 :             :       eModeCategories,
      82                 :             :       DataTypes.ValidateBorrowParams({
      83                 :             :         reserveCache: reserveCache,
      84                 :             :         userConfig: userConfig,
      85                 :             :         asset: params.asset,
      86                 :             :         userAddress: params.onBehalfOf,
      87                 :             :         amount: params.amount,
      88                 :             :         interestRateMode: params.interestRateMode,
      89                 :             :         reservesCount: params.reservesCount,
      90                 :             :         oracle: params.oracle,
      91                 :             :         userEModeCategory: params.userEModeCategory,
      92                 :             :         priceOracleSentinel: params.priceOracleSentinel,
      93                 :             :         isolationModeActive: isolationModeActive,
      94                 :             :         isolationModeCollateralAddress: isolationModeCollateralAddress,
      95                 :             :         isolationModeDebtCeiling: isolationModeDebtCeiling
      96                 :             :       })
      97                 :             :     );
      98                 :             : 
      99                 :       15091 :     bool isFirstBorrowing = false;
     100                 :             : 
     101                 :       15091 :     (isFirstBorrowing, reserveCache.nextScaledVariableDebt) = IVariableDebtToken(
     102                 :             :       reserveCache.variableDebtTokenAddress
     103                 :             :     ).mint(params.user, params.onBehalfOf, params.amount, reserveCache.nextVariableBorrowIndex);
     104                 :             : 
     105                 :       15091 :     if (isFirstBorrowing) {
     106                 :       15090 :       userConfig.setBorrowing(reserve.id, true);
     107                 :             :     }
     108                 :             : 
     109                 :       15091 :     if (isolationModeActive) {
     110                 :           8 :       uint256 nextIsolationModeTotalDebt = reservesData[isolationModeCollateralAddress]
     111                 :             :         .isolationModeTotalDebt += (params.amount /
     112                 :             :         10 **
     113                 :             :           (reserveCache.reserveConfiguration.getDecimals() -
     114                 :             :             ReserveConfiguration.DEBT_CEILING_DECIMALS)).toUint128();
     115                 :           8 :       emit IsolationModeTotalDebtUpdated(
     116                 :             :         isolationModeCollateralAddress,
     117                 :             :         nextIsolationModeTotalDebt
     118                 :             :       );
     119                 :             :     }
     120                 :             : 
     121                 :       15091 :     reserve.updateInterestRatesAndVirtualBalance(
     122                 :             :       reserveCache,
     123                 :             :       params.asset,
     124                 :             :       0,
     125                 :             :       params.releaseUnderlying ? params.amount : 0
     126                 :             :     );
     127                 :             : 
     128                 :       15090 :     if (params.releaseUnderlying) {
     129                 :       15089 :       IAToken(reserveCache.aTokenAddress).transferUnderlyingTo(params.user, params.amount);
     130                 :             :     }
     131                 :             : 
     132                 :       15090 :     emit Borrow(
     133                 :             :       params.asset,
     134                 :             :       params.user,
     135                 :             :       params.onBehalfOf,
     136                 :             :       params.amount,
     137                 :             :       DataTypes.InterestRateMode.VARIABLE,
     138                 :             :       reserve.currentVariableBorrowRate,
     139                 :             :       params.referralCode
     140                 :             :     );
     141                 :             :   }
     142                 :             : 
     143                 :             :   /**
     144                 :             :    * @notice Implements the repay feature. Repaying transfers the underlying back to the aToken and clears the
     145                 :             :    * equivalent amount of debt for the user by burning the corresponding debt token. For isolated positions, it also
     146                 :             :    * reduces the isolated debt.
     147                 :             :    * @dev  Emits the `Repay()` event
     148                 :             :    * @param reservesData The state of all the reserves
     149                 :             :    * @param reservesList The addresses of all the active reserves
     150                 :             :    * @param userConfig The user configuration mapping that tracks the supplied/borrowed assets
     151                 :             :    * @param params The additional parameters needed to execute the repay function
     152                 :             :    * @return The actual amount being repaid
     153                 :             :    */
     154                 :             :   function executeRepay(
     155                 :             :     mapping(address => DataTypes.ReserveData) storage reservesData,
     156                 :             :     mapping(uint256 => address) storage reservesList,
     157                 :             :     DataTypes.UserConfigurationMap storage userConfig,
     158                 :             :     DataTypes.ExecuteRepayParams memory params
     159                 :             :   ) external returns (uint256) {
     160                 :        5030 :     DataTypes.ReserveData storage reserve = reservesData[params.asset];
     161                 :        5030 :     DataTypes.ReserveCache memory reserveCache = reserve.cache();
     162                 :        5030 :     reserve.updateState(reserveCache);
     163                 :             : 
     164                 :        5030 :     uint256 variableDebt = IERC20(reserveCache.variableDebtTokenAddress).balanceOf(
     165                 :             :       params.onBehalfOf
     166                 :             :     );
     167                 :             : 
     168                 :        5030 :     ValidationLogic.validateRepay(
     169                 :             :       reserveCache,
     170                 :             :       params.amount,
     171                 :             :       params.interestRateMode,
     172                 :             :       params.onBehalfOf,
     173                 :             :       variableDebt
     174                 :             :     );
     175                 :             : 
     176                 :        5024 :     uint256 paybackAmount = variableDebt;
     177                 :             : 
     178                 :             :     // Allows a user to repay with aTokens without leaving dust from interest.
     179                 :        5024 :     if (params.useATokens && params.amount == type(uint256).max) {
     180                 :           4 :       params.amount = IAToken(reserveCache.aTokenAddress).balanceOf(msg.sender);
     181                 :             :     }
     182                 :             : 
     183                 :        5024 :     if (params.amount < paybackAmount) {
     184                 :        4971 :       paybackAmount = params.amount;
     185                 :             :     }
     186                 :             : 
     187                 :        5024 :     reserveCache.nextScaledVariableDebt = IVariableDebtToken(reserveCache.variableDebtTokenAddress)
     188                 :             :       .burn(params.onBehalfOf, paybackAmount, reserveCache.nextVariableBorrowIndex);
     189                 :             : 
     190                 :        5024 :     reserve.updateInterestRatesAndVirtualBalance(
     191                 :             :       reserveCache,
     192                 :             :       params.asset,
     193                 :             :       params.useATokens ? 0 : paybackAmount,
     194                 :             :       0
     195                 :             :     );
     196                 :             : 
     197                 :        5024 :     if (variableDebt - paybackAmount == 0) {
     198                 :          53 :       userConfig.setBorrowing(reserve.id, false);
     199                 :             :     }
     200                 :             : 
     201                 :        5024 :     IsolationModeLogic.updateIsolatedDebtIfIsolated(
     202                 :             :       reservesData,
     203                 :             :       reservesList,
     204                 :             :       userConfig,
     205                 :             :       reserveCache,
     206                 :             :       paybackAmount
     207                 :             :     );
     208                 :             : 
     209                 :        5024 :     if (params.useATokens) {
     210                 :        1006 :       IAToken(reserveCache.aTokenAddress).burn(
     211                 :             :         msg.sender,
     212                 :             :         reserveCache.aTokenAddress,
     213                 :             :         paybackAmount,
     214                 :             :         reserveCache.nextLiquidityIndex
     215                 :             :       );
     216                 :             :       // in case of aToken repayment the msg.sender must always repay on behalf of itself
     217                 :        1005 :       if (IAToken(reserveCache.aTokenAddress).scaledBalanceOf(msg.sender) == 0) {
     218                 :           2 :         userConfig.setUsingAsCollateral(reserve.id, false);
     219                 :           2 :         emit ReserveUsedAsCollateralDisabled(params.asset, msg.sender);
     220                 :             :       }
     221                 :             :     } else {
     222                 :        4018 :       IERC20(params.asset).safeTransferFrom(msg.sender, reserveCache.aTokenAddress, paybackAmount);
     223                 :        3018 :       IAToken(reserveCache.aTokenAddress).handleRepayment(
     224                 :             :         msg.sender,
     225                 :             :         params.onBehalfOf,
     226                 :             :         paybackAmount
     227                 :             :       );
     228                 :             :     }
     229                 :             : 
     230                 :        4023 :     emit Repay(params.asset, params.onBehalfOf, msg.sender, paybackAmount, params.useATokens);
     231                 :             : 
     232                 :        4023 :     return paybackAmount;
     233                 :             :   }
     234                 :             : }
        

Generated by: LCOV version 2.1-1