Merge local branch

This commit is contained in:
The3D 2020-09-10 12:51:52 +02:00
parent 3df87a8e5d
commit 4a1e1156f4
13 changed files with 158 additions and 35 deletions

View File

@ -305,7 +305,6 @@ interface ILendingPool {
uint256 principalVariableDebt,
uint256 stableBorrowRate,
uint256 liquidityRate,
uint256 variableBorrowIndex,
uint40 stableRateLastUpdated,
bool usageAsCollateralEnabled
);

View File

@ -23,7 +23,8 @@ interface IReserveInterestRateStrategy {
uint256 utilizationRate,
uint256 totalBorrowsStable,
uint256 totalBorrowsVariable,
uint256 averageStableBorrowRate
uint256 averageStableBorrowRate,
uint256 reserveFactor
)
external
view

View File

@ -49,6 +49,7 @@ contract DefaultReserveInterestRateStrategy is IReserveInterestRateStrategy {
//slope of the stable interest curve when utilization rate > OPTIMAL_UTILIZATION_RATE. Expressed in ray
uint256 internal immutable _stableRateSlope2;
constructor(
LendingPoolAddressesProvider provider,
uint256 baseVariableBorrowRate,
@ -89,6 +90,15 @@ contract DefaultReserveInterestRateStrategy is IReserveInterestRateStrategy {
return _baseVariableBorrowRate;
}
struct CalcInterestRatesLocalVars {
uint256 totalBorrows;
uint256 currentVariableBorrowRate;
uint256 currentStableBorrowRate;
uint256 currentLiquidityRate;
uint256 utilizationRate;
}
/**
* @dev calculates the interest rates depending on the available liquidity and the total borrowed.
* @param reserve the address of the reserve
@ -96,6 +106,7 @@ contract DefaultReserveInterestRateStrategy is IReserveInterestRateStrategy {
* @param totalBorrowsStable the total borrowed from the reserve a stable rate
* @param totalBorrowsVariable the total borrowed from the reserve at a variable rate
* @param averageStableBorrowRate the weighted average of all the stable rate borrows
* @param reserveFactor the reserve portion of the interest to redirect to the reserve treasury
* @return currentLiquidityRate the liquidity rate
* @return currentStableBorrowRate stable borrow rate
* @return currentVariableBorrowRate variable borrow rate
@ -105,7 +116,8 @@ contract DefaultReserveInterestRateStrategy is IReserveInterestRateStrategy {
uint256 availableLiquidity,
uint256 totalBorrowsStable,
uint256 totalBorrowsVariable,
uint256 averageStableBorrowRate
uint256 averageStableBorrowRate,
uint256 reserveFactor
)
external
override
@ -116,16 +128,19 @@ contract DefaultReserveInterestRateStrategy is IReserveInterestRateStrategy {
uint256
)
{
uint256 totalBorrows = totalBorrowsStable.add(totalBorrowsVariable);
uint256 currentVariableBorrowRate = 0;
uint256 currentStableBorrowRate = 0;
uint256 currentLiquidityRate = 0;
uint256 utilizationRate = totalBorrows == 0
CalcInterestRatesLocalVars memory vars;
vars.totalBorrows = totalBorrowsStable.add(totalBorrowsVariable);
vars.currentVariableBorrowRate = 0;
vars.currentStableBorrowRate = 0;
vars.currentLiquidityRate = 0;
uint256 utilizationRate = vars.totalBorrows == 0
? 0
: totalBorrows.rayDiv(availableLiquidity.add(totalBorrows));
: vars.totalBorrows.rayDiv(availableLiquidity.add(vars.totalBorrows));
currentStableBorrowRate = ILendingRateOracle(addressesProvider.getLendingRateOracle())
vars.currentStableBorrowRate = ILendingRateOracle(addressesProvider.getLendingRateOracle())
.getMarketBorrowRate(reserve);
if (utilizationRate > OPTIMAL_UTILIZATION_RATE) {
@ -133,31 +148,32 @@ contract DefaultReserveInterestRateStrategy is IReserveInterestRateStrategy {
EXCESS_UTILIZATION_RATE
);
currentStableBorrowRate = currentStableBorrowRate.add(_stableRateSlope1).add(
vars.currentStableBorrowRate = vars.currentStableBorrowRate.add(_stableRateSlope1).add(
_stableRateSlope2.rayMul(excessUtilizationRateRatio)
);
currentVariableBorrowRate = _baseVariableBorrowRate.add(_variableRateSlope1).add(
vars.currentVariableBorrowRate = _baseVariableBorrowRate.add(_variableRateSlope1).add(
_variableRateSlope2.rayMul(excessUtilizationRateRatio)
);
} else {
currentStableBorrowRate = currentStableBorrowRate.add(
vars.currentStableBorrowRate = vars.currentStableBorrowRate.add(
_stableRateSlope1.rayMul(utilizationRate.rayDiv(OPTIMAL_UTILIZATION_RATE))
);
currentVariableBorrowRate = _baseVariableBorrowRate.add(
vars.currentVariableBorrowRate = _baseVariableBorrowRate.add(
utilizationRate.rayDiv(OPTIMAL_UTILIZATION_RATE).rayMul(_variableRateSlope1)
);
}
currentLiquidityRate = _getOverallBorrowRate(
vars.currentLiquidityRate = _getOverallBorrowRate(
totalBorrowsStable,
totalBorrowsVariable,
currentVariableBorrowRate,
vars.currentVariableBorrowRate,
averageStableBorrowRate
)
.rayMul(utilizationRate);
.rayMul(utilizationRate)
.rayMul(WadRayMath.ray().sub(reserveFactor));
return (currentLiquidityRate, currentStableBorrowRate, currentVariableBorrowRate);
return (vars.currentLiquidityRate, vars.currentStableBorrowRate, vars.currentVariableBorrowRate);
}
/**

View File

@ -12,6 +12,7 @@ import {IAToken} from '../tokenization/interfaces/IAToken.sol';
import {Helpers} from '../libraries/helpers/Helpers.sol';
import {Errors} from '../libraries/helpers/Errors.sol';
import {WadRayMath} from '../libraries/math/WadRayMath.sol';
import {PercentageMath} from '../libraries/math/PercentageMath.sol';
import {ReserveLogic} from '../libraries/logic/ReserveLogic.sol';
import {GenericLogic} from '../libraries/logic/GenericLogic.sol';
import {ValidationLogic} from '../libraries/logic/ValidationLogic.sol';
@ -19,12 +20,12 @@ import {ReserveConfiguration} from '../libraries/configuration/ReserveConfigurat
import {UserConfiguration} from '../libraries/configuration/UserConfiguration.sol';
import {IStableDebtToken} from '../tokenization/interfaces/IStableDebtToken.sol';
import {IVariableDebtToken} from '../tokenization/interfaces/IVariableDebtToken.sol';
import {DebtTokenBase} from '../tokenization/base/DebtTokenBase.sol';
import {IFlashLoanReceiver} from '../flashloan/interfaces/IFlashLoanReceiver.sol';
import {LendingPoolLiquidationManager} from './LendingPoolLiquidationManager.sol';
import {IPriceOracleGetter} from '../interfaces/IPriceOracleGetter.sol';
import {SafeERC20} from '@openzeppelin/contracts/token/ERC20/SafeERC20.sol';
import {ILendingPool} from '../interfaces/ILendingPool.sol';
/**
* @title LendingPool contract
* @notice Implements the actions of the LendingPool, and exposes accessory methods to fetch the users and reserve data
@ -34,6 +35,7 @@ import {ILendingPool} from '../interfaces/ILendingPool.sol';
contract LendingPool is VersionedInitializable, ILendingPool {
using SafeMath for uint256;
using WadRayMath for uint256;
using PercentageMath for uint256;
using ReserveLogic for ReserveLogic.ReserveData;
using ReserveConfiguration for ReserveConfiguration.Map;
using UserConfiguration for UserConfiguration.Map;
@ -224,6 +226,9 @@ contract LendingPool is VersionedInitializable, ILendingPool {
reserve.updateCumulativeIndexesAndTimestamp();
address debtTokenAddress = interestRateMode == ReserveLogic.InterestRateMode.STABLE ? reserve.stableDebtTokenAddress : reserve.variableDebtTokenAddress;
_mintToReserveTreasury(reserve, onBehalfOf, debtTokenAddress);
//burns an equivalent amount of debt tokens
if (interestRateMode == ReserveLogic.InterestRateMode.STABLE) {
IStableDebtToken(reserve.stableDebtTokenAddress).burn(onBehalfOf, paybackAmount);
@ -265,6 +270,10 @@ contract LendingPool is VersionedInitializable, ILendingPool {
reserve.updateCumulativeIndexesAndTimestamp();
address debtTokenAddress = interestRateMode == ReserveLogic.InterestRateMode.STABLE ? reserve.stableDebtTokenAddress : reserve.variableDebtTokenAddress;
_mintToReserveTreasury(reserve, msg.sender, debtTokenAddress);
if (interestRateMode == ReserveLogic.InterestRateMode.STABLE) {
//burn stable rate tokens, mint variable rate tokens
IStableDebtToken(reserve.stableDebtTokenAddress).burn(msg.sender, stableDebt);
@ -321,6 +330,9 @@ contract LendingPool is VersionedInitializable, ILendingPool {
reserve.updateCumulativeIndexesAndTimestamp();
_mintToReserveTreasury(reserve, user, address(stableDebtToken));
stableDebtToken.burn(user, stableBorrowBalance);
stableDebtToken.mint(user, stableBorrowBalance, reserve.currentStableBorrowRate);
@ -609,7 +621,6 @@ contract LendingPool is VersionedInitializable, ILendingPool {
uint256 principalVariableDebt,
uint256 stableBorrowRate,
uint256 liquidityRate,
uint256 variableBorrowIndex,
uint40 stableRateLastUpdated,
bool usageAsCollateralEnabled
)
@ -625,7 +636,6 @@ contract LendingPool is VersionedInitializable, ILendingPool {
user
);
usageAsCollateralEnabled = _usersConfig[user].isUsingAsCollateral(reserve.index);
variableBorrowIndex = IVariableDebtToken(reserve.variableDebtTokenAddress).getUserIndex(user);
}
function getReserves() external override view returns (address[] memory) {
@ -706,6 +716,7 @@ contract LendingPool is VersionedInitializable, ILendingPool {
* @param vars Input struct for the borrowing action, in order to avoid STD errors
**/
function _executeBorrow(ExecuteBorrowParams memory vars) internal {
ReserveLogic.ReserveData storage reserve = _reserves[vars.asset];
UserConfiguration.Map storage userConfig = _usersConfig[msg.sender];
@ -730,13 +741,21 @@ contract LendingPool is VersionedInitializable, ILendingPool {
uint256 reserveIndex = reserve.index;
if (!userConfig.isBorrowing(reserveIndex)) {
userConfig.setBorrowing(reserveIndex, true);
}
address debtTokenAddress = ReserveLogic.InterestRateMode(vars.interestRateMode) == ReserveLogic.InterestRateMode.STABLE ?
reserve.stableDebtTokenAddress
:
reserve.variableDebtTokenAddress;
reserve.updateCumulativeIndexesAndTimestamp();
_mintToReserveTreasury(reserve, vars.user, debtTokenAddress);
//caching the current stable borrow rate
uint256 currentStableRate = 0;
@ -745,13 +764,13 @@ contract LendingPool is VersionedInitializable, ILendingPool {
) {
currentStableRate = reserve.currentStableBorrowRate;
IStableDebtToken(reserve.stableDebtTokenAddress).mint(
IStableDebtToken(debtTokenAddress).mint(
vars.user,
vars.amount,
currentStableRate
);
} else {
IVariableDebtToken(reserve.variableDebtTokenAddress).mint(vars.user, vars.amount);
IVariableDebtToken(debtTokenAddress).mint(vars.user, vars.amount);
}
reserve.updateInterestRates(vars.asset, vars.aTokenAddress, 0, vars.releaseUnderlying ? vars.amount : 0);
@ -848,4 +867,19 @@ contract LendingPool is VersionedInitializable, ILendingPool {
function getAddressesProvider() external view returns (ILendingPoolAddressesProvider) {
return _addressesProvider;
}
function _mintToReserveTreasury(ReserveLogic.ReserveData storage reserve, address user, address debtTokenAddress) internal {
uint256 currentPrincipalBalance = DebtTokenBase(debtTokenAddress).principalBalanceOf(user);
//calculating the interest accrued since the last borrow and minting the equivalent amount to the reserve factor
if(currentPrincipalBalance > 0){
uint256 balanceIncrease = IERC20(debtTokenAddress).balanceOf(user).sub(currentPrincipalBalance);
uint256 amountForReserveFactor = balanceIncrease.percentMul(reserve.configuration.getReserveFactor());
IAToken(reserve.aTokenAddress).mintToReserve(amountForReserveFactor);
}
}
}

View File

@ -10,6 +10,7 @@ import {LendingPoolAddressesProvider} from '../configuration/LendingPoolAddresse
import {IAToken} from '../tokenization/interfaces/IAToken.sol';
import {IStableDebtToken} from '../tokenization/interfaces/IStableDebtToken.sol';
import {IVariableDebtToken} from '../tokenization/interfaces/IVariableDebtToken.sol';
import {DebtTokenBase} from '../tokenization/base/DebtTokenBase.sol';
import {IPriceOracleGetter} from '../interfaces/IPriceOracleGetter.sol';
import {GenericLogic} from '../libraries/logic/GenericLogic.sol';
import {ReserveLogic} from '../libraries/logic/ReserveLogic.sol';
@ -208,6 +209,9 @@ contract LendingPoolLiquidationManager is VersionedInitializable {
//update the principal reserve
principalReserve.updateCumulativeIndexesAndTimestamp();
principalReserve.updateInterestRates(
principal,
principalReserve.aTokenAddress,
@ -216,16 +220,29 @@ contract LendingPoolLiquidationManager is VersionedInitializable {
);
if (vars.userVariableDebt >= vars.actualAmountToLiquidate) {
IVariableDebtToken(principalReserve.variableDebtTokenAddress).burn(
address tokenAddress = principalReserve.variableDebtTokenAddress;
_mintToReserveTreasury(principalReserve, user, tokenAddress);
IVariableDebtToken(tokenAddress).burn(
user,
vars.actualAmountToLiquidate
);
} else {
IVariableDebtToken(principalReserve.variableDebtTokenAddress).burn(
address tokenAddress = principalReserve.variableDebtTokenAddress;
_mintToReserveTreasury(principalReserve, user, tokenAddress);
IVariableDebtToken(tokenAddress).burn(
user,
vars.userVariableDebt
);
IStableDebtToken(principalReserve.stableDebtTokenAddress).burn(
tokenAddress = principalReserve.stableDebtTokenAddress;
IStableDebtToken(tokenAddress).burn(
user,
vars.actualAmountToLiquidate.sub(vars.userVariableDebt)
);
@ -337,4 +354,19 @@ contract LendingPoolLiquidationManager is VersionedInitializable {
}
return (collateralAmount, principalAmountNeeded);
}
function _mintToReserveTreasury(ReserveLogic.ReserveData storage reserve, address user, address debtTokenAddress) internal {
uint256 currentPrincipalBalance = DebtTokenBase(debtTokenAddress).principalBalanceOf(user);
//calculating the interest accrued since the last borrow and minting the equivalent amount to the reserve factor
if(currentPrincipalBalance > 0){
uint256 balanceIncrease = IERC20(debtTokenAddress).balanceOf(user).sub(currentPrincipalBalance);
uint256 amountForReserveFactor = balanceIncrease.percentMul(reserve.configuration.getReserveFactor());
IAToken(reserve.aTokenAddress).mintToReserve(amountForReserveFactor);
}
}
}

View File

@ -21,6 +21,7 @@ library ReserveConfiguration {
uint256 constant FROZEN_MASK = 0xDFFFFFFFFFFFFFF;
uint256 constant BORROWING_MASK = 0xBFFFFFFFFFFFFFF;
uint256 constant STABLE_BORROWING_MASK = 0x7FFFFFFFFFFFFFF;
uint256 constant RESERVE_FACTOR_MASK = 0xFFFFFFFFFFFFFFFF;
struct Map {
//bit 0-15: LTV
@ -31,9 +32,27 @@ library ReserveConfiguration {
//bit 57: reserve is freezed
//bit 58: borrowing is enabled
//bit 59: stable rate borrowing enabled
//bit 64-79: reserve factor
uint256 data;
}
/**
* @dev sets the reserve factor of the reserve
* @param self the reserve configuration
* @param ltv the new ltv
**/
function setReserveFactor(ReserveConfiguration.Map memory self, uint256 ltv) internal pure {
self.data = (self.data & RESERVE_FACTOR_MASK) | ltv;
}
/**
* @dev gets the reserve factor of the reserve
* @param self the reserve configuration
* @return the reserve factor
**/
function getReserveFactor(ReserveConfiguration.Map storage self) internal view returns (uint256) {
return self.data & ~RESERVE_FACTOR_MASK;
}
/**
* @dev sets the Loan to Value of the reserve
* @param self the reserve configuration

View File

@ -246,7 +246,8 @@ library ReserveLogic {
vars.availableLiquidity.add(liquidityAdded).sub(liquidityTaken),
IERC20(vars.stableDebtTokenAddress).totalSupply(),
IERC20(reserve.variableDebtTokenAddress).totalSupply(),
vars.currentAvgStableRate
vars.currentAvgStableRate,
reserve.configuration.getReserveFactor()
);
require(vars.newLiquidityRate < (1 << 128), "ReserveLogic: Liquidity rate overflow");
require(vars.newStableRate < (1 << 128), "ReserveLogic: Stable borrow rate overflow");

View File

@ -10,7 +10,7 @@ contract MockAToken is AToken {
address _underlyingAssetAddress,
string memory _tokenName,
string memory _tokenSymbol
) public AToken(_pool, _underlyingAssetAddress, _tokenName, _tokenSymbol) {}
) public AToken(_pool, _underlyingAssetAddress,address(0), _tokenName, _tokenSymbol) {}
function getRevision() internal override pure returns (uint256) {
return 0x2;

View File

@ -25,6 +25,7 @@ contract AToken is VersionedInitializable, ERC20, IAToken {
uint256 public constant UINT_MAX_VALUE = uint256(-1);
address public immutable UNDERLYING_ASSET_ADDRESS;
address public immutable RESERVE_TREASURY_ADDRESS;
mapping(address => uint256) private _userIndexes;
mapping(address => address) private _interestRedirectionAddresses;
@ -48,11 +49,13 @@ contract AToken is VersionedInitializable, ERC20, IAToken {
constructor(
LendingPool pool,
address underlyingAssetAddress,
address reserveTreasuryAddress,
string memory tokenName,
string memory tokenSymbol
) public ERC20(tokenName, tokenSymbol, 18) {
_pool = pool;
UNDERLYING_ASSET_ADDRESS = underlyingAssetAddress;
RESERVE_TREASURY_ADDRESS = reserveTreasuryAddress;
}
function getRevision() internal virtual override pure returns (uint256) {
@ -183,6 +186,11 @@ contract AToken is VersionedInitializable, ERC20, IAToken {
emit Mint(user, amount, balanceIncrease, index);
}
function mintToReserve(uint256 amount) external override onlyLendingPool {
uint256 index = _pool.getReserveNormalizedIncome(UNDERLYING_ASSET_ADDRESS);
_mint(RESERVE_TREASURY_ADDRESS, amount.div(index));
}
/**
* @dev transfers tokens in the event of a borrow being liquidated, in case the liquidators reclaims the aToken
* only lending pools can call this function

View File

@ -17,6 +17,7 @@ contract VariableDebtToken is DebtTokenBase, IVariableDebtToken {
using WadRayMath for uint256;
uint256 public constant DEBT_TOKEN_REVISION = 0x1;
mapping(address => uint256) _userIndexes;
constructor(
address pool,
@ -59,6 +60,7 @@ contract VariableDebtToken is DebtTokenBase, IVariableDebtToken {
uint256 index = POOL.getReserveNormalizedVariableDebt(UNDERLYING_ASSET);
_mint(user, amount.rayDiv(index));
_userIndexes[user] = index;
emit MintDebt(user, amount, index);
}
@ -71,7 +73,15 @@ contract VariableDebtToken is DebtTokenBase, IVariableDebtToken {
uint256 index = POOL.getReserveNormalizedVariableDebt(UNDERLYING_ASSET);
_burn(user, amount.rayDiv(index));
_userIndexes[user] = index;
emit BurnDebt(user, amount, index);
}
/**
* @dev Returns the principal debt balance of the user from
* @return The debt balance of the user since the last burn/mint action
**/
function principalBalanceOf(address user) public virtual override view returns (uint256) {
return super.balanceOf(user).rayMul(_userIndexes[user]);
}
}

View File

@ -67,7 +67,7 @@ abstract contract DebtTokenBase is ERC20, VersionedInitializable {
* @dev Returns the principal debt balance of the user from
* @return The debt balance of the user since the last burn/mint action
**/
function principalBalanceOf(address user) public view returns (uint256) {
function principalBalanceOf(address user) public virtual view returns (uint256) {
return super.balanceOf(user);
}

View File

@ -127,6 +127,14 @@ interface IAToken is IERC20 {
*/
function mint(address user, uint256 amount) external;
/**
* @dev mints aTokens to reserve, based on the reserveFactor value
* only lending pools can call this function
* @param amount the amount of tokens to mint
*/
function mintToReserve(uint256 amount) external;
/**
* @dev transfers tokens in the event of a borrow being liquidated, in case the liquidators reclaims the aToken
* only lending pools can call this function

View File

@ -46,9 +46,4 @@ interface IVariableDebtToken {
**/
function burn(address user, uint256 amount) external;
/**
* @dev returns the last index of the user
* @return the index of the user
**/
function getUserIndex(address user) external view returns (uint256);
}