mirror of
				https://github.com/Instadapp/aave-protocol-v2.git
				synced 2024-07-29 21:47:30 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			199 lines
		
	
	
		
			6.9 KiB
		
	
	
	
		
			Solidity
		
	
	
	
	
	
			
		
		
	
	
			199 lines
		
	
	
		
			6.9 KiB
		
	
	
	
		
			Solidity
		
	
	
	
	
	
| // SPDX-License-Identifier: agpl-3.0
 | |
| pragma solidity 0.6.12;
 | |
| pragma experimental ABIEncoderV2;
 | |
| 
 | |
| import {SafeMath} from '../../../dependencies/openzeppelin/contracts/SafeMath.sol';
 | |
| import {IERC20} from '../../../dependencies/openzeppelin/contracts/IERC20.sol';
 | |
| import {IScaledBalanceToken} from '../../../interfaces/IScaledBalanceToken.sol';
 | |
| import {ReserveLogic} from './ReserveLogic.sol';
 | |
| import {ReserveConfiguration} from '../configuration/ReserveConfiguration.sol';
 | |
| import {UserConfiguration} from '../configuration/UserConfiguration.sol';
 | |
| import {WadRayMath} from '../math/WadRayMath.sol';
 | |
| import {PercentageMath} from '../math/PercentageMath.sol';
 | |
| import {IPriceOracleGetter} from '../../../interfaces/IPriceOracleGetter.sol';
 | |
| import {DataTypes} from '../types/DataTypes.sol';
 | |
| 
 | |
| /**
 | |
|  * @title GenericLogic library
 | |
|  * @author Aave
 | |
|  * @title Implements protocol-level logic to calculate and validate the state of a user
 | |
|  */
 | |
| library GenericLogic {
 | |
|   using ReserveLogic for DataTypes.ReserveData;
 | |
|   using SafeMath for uint256;
 | |
|   using WadRayMath for uint256;
 | |
|   using PercentageMath for uint256;
 | |
|   using ReserveConfiguration for DataTypes.ReserveConfigurationMap;
 | |
|   using UserConfiguration for DataTypes.UserConfigurationMap;
 | |
| 
 | |
|   uint256 public constant HEALTH_FACTOR_LIQUIDATION_THRESHOLD = 1 ether;
 | |
| 
 | |
|   struct CalculateUserAccountDataVars {
 | |
|     uint256 assetPrice;
 | |
|     uint256 assetUnit;
 | |
|     uint256 userBalance;
 | |
|     uint256 userBalanceETH;
 | |
|     uint256 userDebt;
 | |
|     uint256 userDebtETH;
 | |
|     uint256 decimals;
 | |
|     uint256 ltv;
 | |
|     uint256 liquidationThreshold;
 | |
|     uint256 i;
 | |
|     uint256 healthFactor;
 | |
|     uint256 totalCollateralInETH;
 | |
|     uint256 totalDebtInETH;
 | |
|     uint256 avgLtv;
 | |
|     uint256 avgLiquidationThreshold;
 | |
|     uint256 reservesLength;
 | |
|     uint256 normalizedIncome;
 | |
|     uint256 normalizedDebt;
 | |
|     bool healthFactorBelowThreshold;
 | |
|     address currentReserveAddress;
 | |
|     bool usageAsCollateralEnabled;
 | |
|     bool userUsesReserveAsCollateral;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * @dev Calculates the user data across the reserves.
 | |
|    * this includes the total liquidity/collateral/borrow balances in ETH,
 | |
|    * the average Loan To Value, the average Liquidation Ratio, and the Health factor.
 | |
|    * @param user The address of the user
 | |
|    * @param reservesData Data of all the reserves
 | |
|    * @param userConfig The configuration of the user
 | |
|    * @param reserves The list of the available reserves
 | |
|    * @param oracle The price oracle address
 | |
|    * @return The total collateral and total debt of the user in ETH, the avg ltv, liquidation threshold and the HF
 | |
|    **/
 | |
|   function calculateUserAccountData(
 | |
|     address user,
 | |
|     mapping(address => DataTypes.ReserveData) storage reservesData,
 | |
|     DataTypes.UserConfigurationMap memory userConfig,
 | |
|     mapping(uint256 => address) storage reserves,
 | |
|     uint256 reservesCount,
 | |
|     address oracle
 | |
|   )
 | |
|     internal
 | |
|     view
 | |
|     returns (
 | |
|       uint256,
 | |
|       uint256,
 | |
|       uint256,
 | |
|       uint256,
 | |
|       uint256
 | |
|     )
 | |
|   {
 | |
|     CalculateUserAccountDataVars memory vars;
 | |
| 
 | |
|     if (userConfig.isEmpty()) {
 | |
|       return (0, 0, 0, 0, uint256(-1));
 | |
|     }
 | |
|     for (vars.i = 0; vars.i < reservesCount; vars.i++) {
 | |
|       if (!userConfig.isUsingAsCollateralOrBorrowing(vars.i)) {
 | |
|         continue;
 | |
|       }
 | |
| 
 | |
|       vars.currentReserveAddress = reserves[vars.i];
 | |
|       DataTypes.ReserveData storage currentReserve = reservesData[vars.currentReserveAddress];
 | |
| 
 | |
|       (vars.ltv, vars.liquidationThreshold, , vars.decimals, ) = currentReserve
 | |
|         .configuration
 | |
|         .getParams();
 | |
| 
 | |
|       vars.assetUnit = 10**vars.decimals;
 | |
|       vars.assetPrice = IPriceOracleGetter(oracle).getAssetPrice(vars.currentReserveAddress);
 | |
| 
 | |
|       if (vars.liquidationThreshold != 0 && userConfig.isUsingAsCollateral(vars.i)) {
 | |
|         vars.userBalance = IScaledBalanceToken(currentReserve.aTokenAddress).scaledBalanceOf(user);
 | |
|         if (vars.userBalance > 0) {
 | |
|           vars.normalizedIncome = currentReserve.getNormalizedIncome();
 | |
|           vars.userBalance = vars.userBalance.rayMul(vars.normalizedIncome);
 | |
|         }
 | |
| 
 | |
|         vars.userBalanceETH = vars.assetPrice.mul(vars.userBalance).div(vars.assetUnit);
 | |
| 
 | |
|         vars.totalCollateralInETH = vars.totalCollateralInETH.add(vars.userBalanceETH);
 | |
| 
 | |
|         vars.avgLtv = vars.avgLtv.add(vars.userBalanceETH.mul(vars.ltv));
 | |
|         vars.avgLiquidationThreshold = vars.avgLiquidationThreshold.add(
 | |
|           vars.userBalanceETH.mul(vars.liquidationThreshold)
 | |
|         );
 | |
|       }
 | |
| 
 | |
|       if (userConfig.isBorrowing(vars.i)) {
 | |
|         vars.userDebt = IScaledBalanceToken(currentReserve.variableDebtTokenAddress)
 | |
|           .scaledBalanceOf(user);
 | |
| 
 | |
|         if (vars.userDebt > 0) {
 | |
|           vars.normalizedDebt = currentReserve.getNormalizedDebt();
 | |
|           vars.userDebt = vars.userDebt.rayMul(vars.normalizedDebt);
 | |
|         }
 | |
| 
 | |
|         vars.userDebt = vars.userDebt.add(
 | |
|           IERC20(currentReserve.stableDebtTokenAddress).balanceOf(user)
 | |
|         );
 | |
|         vars.userDebtETH = vars.assetPrice.mul(vars.userDebt).div(vars.assetUnit);
 | |
|         vars.totalDebtInETH = vars.totalDebtInETH.add(vars.userDebtETH);         
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     vars.avgLtv = vars.totalCollateralInETH > 0 ? vars.avgLtv.div(vars.totalCollateralInETH) : 0;
 | |
|     vars.avgLiquidationThreshold = vars.totalCollateralInETH > 0
 | |
|       ? vars.avgLiquidationThreshold.div(vars.totalCollateralInETH)
 | |
|       : 0;
 | |
| 
 | |
|     vars.healthFactor = calculateHealthFactorFromBalances(
 | |
|       vars.totalCollateralInETH,
 | |
|       vars.totalDebtInETH,
 | |
|       vars.avgLiquidationThreshold
 | |
|     );
 | |
|     return (
 | |
|       vars.totalCollateralInETH,
 | |
|       vars.totalDebtInETH,
 | |
|       vars.avgLtv,
 | |
|       vars.avgLiquidationThreshold,
 | |
|       vars.healthFactor
 | |
|     );
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * @dev Calculates the health factor from the corresponding balances
 | |
|    * @param totalCollateralInETH The total collateral in ETH
 | |
|    * @param totalDebtInETH The total debt in ETH
 | |
|    * @param liquidationThreshold The avg liquidation threshold
 | |
|    * @return The health factor calculated from the balances provided
 | |
|    **/
 | |
|   function calculateHealthFactorFromBalances(
 | |
|     uint256 totalCollateralInETH,
 | |
|     uint256 totalDebtInETH,
 | |
|     uint256 liquidationThreshold
 | |
|   ) internal pure returns (uint256) {
 | |
|     if (totalDebtInETH == 0) return uint256(-1);
 | |
| 
 | |
|     return (totalCollateralInETH.percentMul(liquidationThreshold)).wadDiv(totalDebtInETH);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * @dev Calculates the equivalent amount in ETH that an user can borrow, depending on the available collateral and the
 | |
|    * average Loan To Value
 | |
|    * @param totalCollateralInETH The total collateral in ETH
 | |
|    * @param totalDebtInETH The total borrow balance
 | |
|    * @param ltv The average loan to value
 | |
|    * @return the amount available to borrow in ETH for the user
 | |
|    **/
 | |
| 
 | |
|   function calculateAvailableBorrowsETH(
 | |
|     uint256 totalCollateralInETH,
 | |
|     uint256 totalDebtInETH,
 | |
|     uint256 ltv
 | |
|   ) internal pure returns (uint256) {
 | |
|     uint256 availableBorrowsETH = totalCollateralInETH.percentMul(ltv);
 | |
| 
 | |
|     if (availableBorrowsETH < totalDebtInETH) {
 | |
|       return 0;
 | |
|     }
 | |
| 
 | |
|     availableBorrowsETH = availableBorrowsETH.sub(totalDebtInETH);
 | |
|     return availableBorrowsETH;
 | |
|   }
 | |
| }
 | 
