LCOV - code coverage report
Current view: top level - protocol/libraries/logic - SupplyLogic.sol (source / functions) Coverage Total Hit
Test: lcov.info.p Lines: 100.0 % 60 60
Test Date: 2024-09-24 09:34:24 Functions: 100.0 % 4 4
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 {IERC20} from '../../../dependencies/openzeppelin/contracts/IERC20.sol';
       5                 :             : import {GPv2SafeERC20} from '../../../dependencies/gnosis/contracts/GPv2SafeERC20.sol';
       6                 :             : import {IAToken} from '../../../interfaces/IAToken.sol';
       7                 :             : import {Errors} from '../helpers/Errors.sol';
       8                 :             : import {UserConfiguration} from '../configuration/UserConfiguration.sol';
       9                 :             : import {DataTypes} from '../types/DataTypes.sol';
      10                 :             : import {WadRayMath} from '../math/WadRayMath.sol';
      11                 :             : import {PercentageMath} from '../math/PercentageMath.sol';
      12                 :             : import {ValidationLogic} from './ValidationLogic.sol';
      13                 :             : import {ReserveLogic} from './ReserveLogic.sol';
      14                 :             : import {ReserveConfiguration} from '../configuration/ReserveConfiguration.sol';
      15                 :             : 
      16                 :             : /**
      17                 :             :  * @title SupplyLogic library
      18                 :             :  * @author Aave
      19                 :             :  * @notice Implements the base logic for supply/withdraw
      20                 :             :  */
      21                 :             : library SupplyLogic {
      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 WadRayMath for uint256;
      28                 :             :   using PercentageMath for uint256;
      29                 :             : 
      30                 :             :   // See `IPool` for descriptions
      31                 :             :   event ReserveUsedAsCollateralEnabled(address indexed reserve, address indexed user);
      32                 :             :   event ReserveUsedAsCollateralDisabled(address indexed reserve, address indexed user);
      33                 :             :   event Withdraw(address indexed reserve, address indexed user, address indexed to, uint256 amount);
      34                 :             :   event Supply(
      35                 :             :     address indexed reserve,
      36                 :             :     address user,
      37                 :             :     address indexed onBehalfOf,
      38                 :             :     uint256 amount,
      39                 :             :     uint16 indexed referralCode
      40                 :             :   );
      41                 :             : 
      42                 :             :   /**
      43                 :             :    * @notice Implements the supply feature. Through `supply()`, users supply assets to the Aave protocol.
      44                 :             :    * @dev Emits the `Supply()` event.
      45                 :             :    * @dev In the first supply action, `ReserveUsedAsCollateralEnabled()` is emitted, if the asset can be enabled as
      46                 :             :    * collateral.
      47                 :             :    * @param reservesData The state of all the reserves
      48                 :             :    * @param reservesList The addresses of all the active reserves
      49                 :             :    * @param userConfig The user configuration mapping that tracks the supplied/borrowed assets
      50                 :             :    * @param params The additional parameters needed to execute the supply function
      51                 :             :    */
      52                 :             :   function executeSupply(
      53                 :             :     mapping(address => DataTypes.ReserveData) storage reservesData,
      54                 :             :     mapping(uint256 => address) storage reservesList,
      55                 :             :     DataTypes.UserConfigurationMap storage userConfig,
      56                 :             :     DataTypes.ExecuteSupplyParams memory params
      57                 :             :   ) external {
      58                 :       44515 :     DataTypes.ReserveData storage reserve = reservesData[params.asset];
      59                 :       44515 :     DataTypes.ReserveCache memory reserveCache = reserve.cache();
      60                 :             : 
      61                 :       44515 :     reserve.updateState(reserveCache);
      62                 :             : 
      63                 :       44515 :     ValidationLogic.validateSupply(reserveCache, reserve, params.amount, params.onBehalfOf);
      64                 :             : 
      65                 :       44507 :     reserve.updateInterestRatesAndVirtualBalance(reserveCache, params.asset, params.amount, 0);
      66                 :             : 
      67                 :       44506 :     IERC20(params.asset).safeTransferFrom(msg.sender, reserveCache.aTokenAddress, params.amount);
      68                 :             : 
      69                 :       43506 :     bool isFirstSupply = IAToken(reserveCache.aTokenAddress).mint(
      70                 :             :       msg.sender,
      71                 :             :       params.onBehalfOf,
      72                 :             :       params.amount,
      73                 :             :       reserveCache.nextLiquidityIndex
      74                 :             :     );
      75                 :             : 
      76                 :       43506 :     if (isFirstSupply) {
      77                 :             :       if (
      78                 :       43501 :         ValidationLogic.validateAutomaticUseAsCollateral(
      79                 :             :           reservesData,
      80                 :             :           reservesList,
      81                 :             :           userConfig,
      82                 :             :           reserveCache.reserveConfiguration,
      83                 :             :           reserveCache.aTokenAddress
      84                 :             :         )
      85                 :             :       ) {
      86                 :       43488 :         userConfig.setUsingAsCollateral(reserve.id, true);
      87                 :       43488 :         emit ReserveUsedAsCollateralEnabled(params.asset, params.onBehalfOf);
      88                 :             :       }
      89                 :             :     }
      90                 :             : 
      91                 :       43506 :     emit Supply(params.asset, msg.sender, params.onBehalfOf, params.amount, params.referralCode);
      92                 :             :   }
      93                 :             : 
      94                 :             :   /**
      95                 :             :    * @notice Implements the withdraw feature. Through `withdraw()`, users redeem their aTokens for the underlying asset
      96                 :             :    * previously supplied in the Aave protocol.
      97                 :             :    * @dev Emits the `Withdraw()` event.
      98                 :             :    * @dev If the user withdraws everything, `ReserveUsedAsCollateralDisabled()` is emitted.
      99                 :             :    * @param reservesData The state of all the reserves
     100                 :             :    * @param reservesList The addresses of all the active reserves
     101                 :             :    * @param eModeCategories The configuration of all the efficiency mode categories
     102                 :             :    * @param userConfig The user configuration mapping that tracks the supplied/borrowed assets
     103                 :             :    * @param params The additional parameters needed to execute the withdraw function
     104                 :             :    * @return The actual amount withdrawn
     105                 :             :    */
     106                 :             :   function executeWithdraw(
     107                 :             :     mapping(address => DataTypes.ReserveData) storage reservesData,
     108                 :             :     mapping(uint256 => address) storage reservesList,
     109                 :             :     mapping(uint8 => DataTypes.EModeCategory) storage eModeCategories,
     110                 :             :     DataTypes.UserConfigurationMap storage userConfig,
     111                 :             :     DataTypes.ExecuteWithdrawParams memory params
     112                 :             :   ) external returns (uint256) {
     113                 :        2045 :     DataTypes.ReserveData storage reserve = reservesData[params.asset];
     114                 :        2045 :     DataTypes.ReserveCache memory reserveCache = reserve.cache();
     115                 :             : 
     116                 :        2045 :     require(params.to != reserveCache.aTokenAddress, Errors.WITHDRAW_TO_ATOKEN);
     117                 :             : 
     118                 :        2044 :     reserve.updateState(reserveCache);
     119                 :             : 
     120                 :        2044 :     uint256 userBalance = IAToken(reserveCache.aTokenAddress).scaledBalanceOf(msg.sender).rayMul(
     121                 :             :       reserveCache.nextLiquidityIndex
     122                 :             :     );
     123                 :             : 
     124                 :        2044 :     uint256 amountToWithdraw = params.amount;
     125                 :             : 
     126                 :        2044 :     if (params.amount == type(uint256).max) {
     127                 :           5 :       amountToWithdraw = userBalance;
     128                 :             :     }
     129                 :             : 
     130                 :        2044 :     ValidationLogic.validateWithdraw(reserveCache, amountToWithdraw, userBalance);
     131                 :             : 
     132                 :        2040 :     reserve.updateInterestRatesAndVirtualBalance(reserveCache, params.asset, 0, amountToWithdraw);
     133                 :             : 
     134                 :        2037 :     bool isCollateral = userConfig.isUsingAsCollateral(reserve.id);
     135                 :             : 
     136                 :        2037 :     if (isCollateral && amountToWithdraw == userBalance) {
     137                 :        2030 :       userConfig.setUsingAsCollateral(reserve.id, false);
     138                 :        2030 :       emit ReserveUsedAsCollateralDisabled(params.asset, msg.sender);
     139                 :             :     }
     140                 :             : 
     141                 :        2037 :     IAToken(reserveCache.aTokenAddress).burn(
     142                 :             :       msg.sender,
     143                 :             :       params.to,
     144                 :             :       amountToWithdraw,
     145                 :             :       reserveCache.nextLiquidityIndex
     146                 :             :     );
     147                 :             : 
     148                 :        2037 :     if (isCollateral && userConfig.isBorrowingAny()) {
     149                 :           1 :       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                 :        2036 :     emit Withdraw(params.asset, msg.sender, params.to, amountToWithdraw);
     163                 :             : 
     164                 :        2036 :     return amountToWithdraw;
     165                 :             :   }
     166                 :             : 
     167                 :             :   /**
     168                 :             :    * @notice Validates a transfer of aTokens. The sender is subjected to health factor validation to avoid
     169                 :             :    * collateralization constraints violation.
     170                 :             :    * @dev Emits the `ReserveUsedAsCollateralEnabled()` event for the `to` account, if the asset is being activated as
     171                 :             :    * collateral.
     172                 :             :    * @dev In case the `from` user transfers everything, `ReserveUsedAsCollateralDisabled()` is emitted for `from`.
     173                 :             :    * @param reservesData The state of all the reserves
     174                 :             :    * @param reservesList The addresses of all the active reserves
     175                 :             :    * @param eModeCategories The configuration of all the efficiency mode categories
     176                 :             :    * @param usersConfig The users configuration mapping that track the supplied/borrowed assets
     177                 :             :    * @param params The additional parameters needed to execute the finalizeTransfer function
     178                 :             :    */
     179                 :             :   function executeFinalizeTransfer(
     180                 :             :     mapping(address => DataTypes.ReserveData) storage reservesData,
     181                 :             :     mapping(uint256 => address) storage reservesList,
     182                 :             :     mapping(uint8 => DataTypes.EModeCategory) storage eModeCategories,
     183                 :             :     mapping(address => DataTypes.UserConfigurationMap) storage usersConfig,
     184                 :             :     DataTypes.FinalizeTransferParams memory params
     185                 :             :   ) external {
     186                 :       17042 :     DataTypes.ReserveData storage reserve = reservesData[params.asset];
     187                 :             : 
     188                 :       17042 :     ValidationLogic.validateTransfer(reserve);
     189                 :             : 
     190                 :       17042 :     uint256 reserveId = reserve.id;
     191                 :       17042 :     uint256 scaledAmount = params.amount.rayDiv(reserve.getNormalizedIncome());
     192                 :             : 
     193                 :       17042 :     if (params.from != params.to && scaledAmount != 0) {
     194                 :       16898 :       DataTypes.UserConfigurationMap storage fromConfig = usersConfig[params.from];
     195                 :             : 
     196                 :       16898 :       if (fromConfig.isUsingAsCollateral(reserveId)) {
     197                 :       16898 :         if (fromConfig.isBorrowingAny()) {
     198                 :           6 :           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                 :       16897 :         if (params.balanceFromBefore == params.amount) {
     211                 :       15013 :           fromConfig.setUsingAsCollateral(reserveId, false);
     212                 :       15013 :           emit ReserveUsedAsCollateralDisabled(params.asset, params.from);
     213                 :             :         }
     214                 :             :       }
     215                 :             : 
     216                 :       16897 :       if (params.balanceToBefore == 0) {
     217                 :       15893 :         DataTypes.UserConfigurationMap storage toConfig = usersConfig[params.to];
     218                 :             :         if (
     219                 :       15893 :           ValidationLogic.validateAutomaticUseAsCollateral(
     220                 :             :             reservesData,
     221                 :             :             reservesList,
     222                 :             :             toConfig,
     223                 :             :             reserve.configuration,
     224                 :             :             reserve.aTokenAddress
     225                 :             :           )
     226                 :             :         ) {
     227                 :       15893 :           toConfig.setUsingAsCollateral(reserveId, true);
     228                 :       15893 :           emit ReserveUsedAsCollateralEnabled(params.asset, params.to);
     229                 :             :         }
     230                 :             :       }
     231                 :             :     }
     232                 :             :   }
     233                 :             : 
     234                 :             :   /**
     235                 :             :    * @notice Executes the 'set as collateral' feature. A user can choose to activate or deactivate an asset as
     236                 :             :    * collateral at any point in time. Deactivating an asset as collateral is subjected to the usual health factor
     237                 :             :    * checks to ensure collateralization.
     238                 :             :    * @dev Emits the `ReserveUsedAsCollateralEnabled()` event if the asset can be activated as collateral.
     239                 :             :    * @dev In case the asset is being deactivated as collateral, `ReserveUsedAsCollateralDisabled()` is emitted.
     240                 :             :    * @param reservesData The state of all the reserves
     241                 :             :    * @param reservesList The addresses of all the active reserves
     242                 :             :    * @param eModeCategories The configuration of all the efficiency mode categories
     243                 :             :    * @param userConfig The users configuration mapping that track the supplied/borrowed assets
     244                 :             :    * @param asset The address of the asset being configured as collateral
     245                 :             :    * @param useAsCollateral True if the user wants to set the asset as collateral, false otherwise
     246                 :             :    * @param reservesCount The number of initialized reserves
     247                 :             :    * @param priceOracle The address of the price oracle
     248                 :             :    * @param userEModeCategory The eMode category chosen by the user
     249                 :             :    */
     250                 :             :   function executeUseReserveAsCollateral(
     251                 :             :     mapping(address => DataTypes.ReserveData) storage reservesData,
     252                 :             :     mapping(uint256 => address) storage reservesList,
     253                 :             :     mapping(uint8 => DataTypes.EModeCategory) storage eModeCategories,
     254                 :             :     DataTypes.UserConfigurationMap storage userConfig,
     255                 :             :     address asset,
     256                 :             :     bool useAsCollateral,
     257                 :             :     uint256 reservesCount,
     258                 :             :     address priceOracle,
     259                 :             :     uint8 userEModeCategory
     260                 :             :   ) external {
     261                 :          43 :     DataTypes.ReserveData storage reserve = reservesData[asset];
     262                 :          43 :     DataTypes.ReserveCache memory reserveCache = reserve.cache();
     263                 :             : 
     264                 :          43 :     uint256 userBalance = IERC20(reserveCache.aTokenAddress).balanceOf(msg.sender);
     265                 :             : 
     266                 :          43 :     ValidationLogic.validateSetUseReserveAsCollateral(reserveCache, userBalance);
     267                 :             : 
     268                 :          37 :     if (useAsCollateral == userConfig.isUsingAsCollateral(reserve.id)) return;
     269                 :             : 
     270                 :          35 :     if (useAsCollateral) {
     271                 :          19 :       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                 :          15 :       userConfig.setUsingAsCollateral(reserve.id, true);
     282                 :          15 :       emit ReserveUsedAsCollateralEnabled(asset, msg.sender);
     283                 :             :     } else {
     284                 :          16 :       userConfig.setUsingAsCollateral(reserve.id, false);
     285                 :          16 :       ValidationLogic.validateHFAndLtv(
     286                 :             :         reservesData,
     287                 :             :         reservesList,
     288                 :             :         eModeCategories,
     289                 :             :         userConfig,
     290                 :             :         asset,
     291                 :             :         msg.sender,
     292                 :             :         reservesCount,
     293                 :             :         priceOracle,
     294                 :             :         userEModeCategory
     295                 :             :       );
     296                 :             : 
     297                 :          14 :       emit ReserveUsedAsCollateralDisabled(asset, msg.sender);
     298                 :             :     }
     299                 :             :   }
     300                 :             : }
        

Generated by: LCOV version 2.1-1