aave-protocol-v2/contracts/libraries/ReserveLogic.sol
2020-07-03 23:20:02 +02:00

221 lines
8.1 KiB
Solidity

// SPDX-License-Identifier: agpl-3.0
pragma solidity ^0.6.8;
import {SafeMath} from "@openzeppelin/contracts/math/SafeMath.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {CoreLibrary} from "./CoreLibrary.sol";
import {UserLogic} from "./UserLogic.sol";
import {IPriceOracleGetter} from "../interfaces/IPriceOracleGetter.sol";
import {UniversalERC20} from "./UniversalERC20.sol";
import {IStableDebtToken} from '../tokenization/interfaces/IStableDebtToken.sol';
import "../configuration/LendingPoolAddressesProvider.sol";
import "../interfaces/ILendingRateOracle.sol";
import "../interfaces/IReserveInterestRateStrategy.sol";
import "../tokenization/AToken.sol";
import "./WadRayMath.sol";
/**
* @title ReserveLogic library
* @author Aave
* @notice Implements the logic to update the state of the reserves
*/
library ReserveLogic {
using SafeMath for uint256;
using WadRayMath for uint256;
using CoreLibrary for CoreLibrary.ReserveData;
using CoreLibrary for CoreLibrary.UserReserveData;
using UniversalERC20 for IERC20;
using Address for address;
using UserLogic for CoreLibrary.UserReserveData;
/**
* @dev Emitted when the state of a reserve is updated
* @dev NOTE: This event replaces the Deprecated ReserveUpdated() event, which didn't emit the average stable borrow rate
* @param reserve the address of the reserve
* @param liquidityRate the new liquidity rate
* @param stableBorrowRate the new stable borrow rate
* @param averageStableBorrowRate the new average stable borrow rate
* @param variableBorrowRate the new variable borrow rate
* @param liquidityIndex the new liquidity index
* @param variableBorrowIndex the new variable borrow index
**/
event ReserveDataUpdated(
address indexed reserve,
uint256 liquidityRate,
uint256 stableBorrowRate,
uint256 averageStableBorrowRate,
uint256 variableBorrowRate,
uint256 liquidityIndex,
uint256 variableBorrowIndex
);
/**
* @dev updates the state of the core as a result of a flashloan action
* @param _reserve the address of the reserve in which the flashloan is happening
* @param _income the income of the protocol as a result of the action
**/
function updateStateOnFlashLoan(
CoreLibrary.ReserveData storage _reserve,
address _reserveAddress,
uint256 _availableLiquidityBefore,
uint256 _income,
uint256 _protocolFee
) external {
//compounding the cumulated interest
_reserve.updateCumulativeIndexesAndTimestamp();
uint256 totalLiquidityBefore = _availableLiquidityBefore.add(_reserve.getTotalBorrows());
//compounding the received fee into the reserve
_reserve.cumulateToLiquidityIndex(totalLiquidityBefore, _income);
//refresh interest rates
updateInterestRates(_reserve, _reserveAddress, _income, 0);
}
/**
* @dev updates the state of the core as a consequence of a liquidation action.
* @param _collateralReserve the collateral reserve that is being liquidated
* @param _collateralToLiquidate the amount of collateral being liquidated
* @param _liquidatorReceivesAToken true if the liquidator will receive aTokens, false otherwise
**/
function updateStateOnLiquidationAsCollateral(
CoreLibrary.ReserveData storage _collateralReserve,
address _collateralReserveAddress,
uint256 _collateralToLiquidate,
bool _liquidatorReceivesAToken
) external {
_collateralReserve.updateCumulativeIndexesAndTimestamp();
if (!_liquidatorReceivesAToken) {
updateInterestRates(
_collateralReserve,
_collateralReserveAddress,
0,
_collateralToLiquidate
);
}
}
/**
* @dev gets the total liquidity in the reserve. The total liquidity is the balance of the core contract + total borrows
* @param _reserve the reserve address
* @return the total liquidity
**/
function getTotalLiquidity(CoreLibrary.ReserveData storage _reserve, address _reserveAddress)
public
view
returns (uint256)
{
return
IERC20(_reserveAddress).universalBalanceOf(address(this)).add(
_reserve.getTotalBorrows()
);
}
/**
* @dev Updates the reserve current stable borrow rate Rf, the current variable borrow rate Rv and the current liquidity rate Rl.
* Also updates the lastUpdateTimestamp value. Please refer to the whitepaper for further information.
* @param _reserve the address of the reserve to be updated
* @param _liquidityAdded the amount of liquidity added to the protocol (deposit or repay) in the previous action
* @param _liquidityTaken the amount of liquidity taken from the protocol (redeem or borrow)
**/
function updateInterestRates(
CoreLibrary.ReserveData storage _reserve,
address _reserveAddress,
uint256 _liquidityAdded,
uint256 _liquidityTaken
) internal {
uint256 currentAvgStableRate = IStableDebtToken(_reserve.stableDebtTokenAddress).getAverageStableRate();
uint256 balance = IERC20(_reserveAddress).universalBalanceOf(address(this));
//if the reserve is ETH, the msg.value has already been cumulated to the balance of the reserve
if(IERC20(_reserveAddress).isETH()){
balance = balance.sub(msg.value);
}
(uint256 newLiquidityRate, uint256 newStableRate, uint256 newVariableRate) = IReserveInterestRateStrategy(
_reserve
.interestRateStrategyAddress
)
.calculateInterestRates(
_reserveAddress,
balance.add(_liquidityAdded).sub(_liquidityTaken),
IERC20(_reserve.stableDebtTokenAddress).totalSupply(),
IERC20(_reserve.variableDebtTokenAddress).totalSupply(),
currentAvgStableRate
);
_reserve.currentLiquidityRate = newLiquidityRate;
_reserve.currentStableBorrowRate = newStableRate;
_reserve.currentVariableBorrowRate = newVariableRate;
emit ReserveDataUpdated(
_reserveAddress,
newLiquidityRate,
newStableRate,
currentAvgStableRate,
newVariableRate,
_reserve.lastLiquidityCumulativeIndex,
_reserve.lastVariableBorrowCumulativeIndex
);
}
/**
* @dev gets the reserve current variable borrow rate. Is the base variable borrow rate if the reserve is empty
* @param _reserve the reserve address
* @return the reserve current variable borrow rate
**/
function getReserveCurrentVariableBorrowRate(CoreLibrary.ReserveData storage _reserve)
external
view
returns (uint256)
{
if (_reserve.currentVariableBorrowRate == 0) {
return
IReserveInterestRateStrategy(_reserve.interestRateStrategyAddress)
.getBaseVariableBorrowRate();
}
return _reserve.currentVariableBorrowRate;
}
/**
* @dev gets the reserve current stable borrow rate. Is the market rate if the reserve is empty
* @param _reserve the reserve address
* @return the reserve current stable borrow rate
**/
function getReserveCurrentStableBorrowRate(
CoreLibrary.ReserveData storage _reserve,
uint256 _baseRate
) public view returns (uint256) {
return _reserve.currentStableBorrowRate == 0 ? _baseRate : _reserve.currentStableBorrowRate;
}
/**
* @dev returns the utilization rate U of a specific reserve
* @param _reserve the reserve for which the information is needed
* @return the utilization rate in ray
**/
function getUtilizationRate(CoreLibrary.ReserveData storage _reserve, address _reserveAddress)
public
view
returns (uint256)
{
uint256 totalBorrows = _reserve.getTotalBorrows();
if (totalBorrows == 0) {
return 0;
}
uint256 availableLiquidity = IERC20(_reserveAddress).universalBalanceOf(address(this));
return totalBorrows.rayDiv(availableLiquidity.add(totalBorrows));
}
}