mirror of
https://github.com/Instadapp/aave-protocol-v2.git
synced 2024-07-29 21:47:30 +00:00
Merge branch 'master' into fix/42
This commit is contained in:
commit
45e4e0b5fe
|
@ -10,6 +10,7 @@ usePlugin('solidity-coverage');
|
|||
usePlugin('@nomiclabs/buidler-waffle');
|
||||
usePlugin('@nomiclabs/buidler-etherscan');
|
||||
//usePlugin('buidler-gas-reporter');
|
||||
|
||||
const DEFAULT_BLOCK_GAS_LIMIT = 10000000;
|
||||
const DEFAULT_GAS_PRICE = 10;
|
||||
const HARDFORK = 'istanbul';
|
||||
|
|
|
@ -327,6 +327,7 @@ interface ILendingPool {
|
|||
uint256 ltv,
|
||||
uint256 liquidationThreshold,
|
||||
uint256 liquidationBonus,
|
||||
uint256 reserveFactor,
|
||||
address interestRateStrategyAddress,
|
||||
bool usageAsCollateralEnabled,
|
||||
bool borrowingEnabled,
|
||||
|
@ -349,8 +350,8 @@ interface ILendingPool {
|
|||
view
|
||||
returns (
|
||||
uint256 availableLiquidity,
|
||||
uint256 totalBorrowsStable,
|
||||
uint256 totalBorrowsVariable,
|
||||
uint256 totalStableDebt,
|
||||
uint256 totalVariableDebt,
|
||||
uint256 liquidityRate,
|
||||
uint256 variableBorrowRate,
|
||||
uint256 stableBorrowRate,
|
||||
|
@ -380,10 +381,9 @@ interface ILendingPool {
|
|||
uint256 currentStableDebt,
|
||||
uint256 currentVariableDebt,
|
||||
uint256 principalStableDebt,
|
||||
uint256 principalVariableDebt,
|
||||
uint256 scaledVariableDebt,
|
||||
uint256 stableBorrowRate,
|
||||
uint256 liquidityRate,
|
||||
uint256 variableBorrowIndex,
|
||||
uint40 stableRateLastUpdated,
|
||||
bool usageAsCollateralEnabled
|
||||
);
|
||||
|
|
|
@ -21,9 +21,10 @@ interface IReserveInterestRateStrategy {
|
|||
function calculateInterestRates(
|
||||
address reserve,
|
||||
uint256 utilizationRate,
|
||||
uint256 totalBorrowsStable,
|
||||
uint256 totalBorrowsVariable,
|
||||
uint256 averageStableBorrowRate
|
||||
uint256 totalStableDebt,
|
||||
uint256 totalVariableDebt,
|
||||
uint256 averageStableBorrowRate,
|
||||
uint256 reserveFactor
|
||||
)
|
||||
external
|
||||
view
|
||||
|
|
|
@ -4,6 +4,7 @@ pragma solidity ^0.6.8;
|
|||
import {SafeMath} from '@openzeppelin/contracts/math/SafeMath.sol';
|
||||
import {IReserveInterestRateStrategy} from '../interfaces/IReserveInterestRateStrategy.sol';
|
||||
import {WadRayMath} from '../libraries/math/WadRayMath.sol';
|
||||
import {PercentageMath} from '../libraries/math/PercentageMath.sol';
|
||||
import {LendingPoolAddressesProvider} from '../configuration/LendingPoolAddressesProvider.sol';
|
||||
import {ILendingRateOracle} from '../interfaces/ILendingRateOracle.sol';
|
||||
|
||||
|
@ -17,7 +18,7 @@ import {ILendingRateOracle} from '../interfaces/ILendingRateOracle.sol';
|
|||
contract DefaultReserveInterestRateStrategy is IReserveInterestRateStrategy {
|
||||
using WadRayMath for uint256;
|
||||
using SafeMath for uint256;
|
||||
|
||||
using PercentageMath for uint256;
|
||||
/**
|
||||
* @dev this constant represents the utilization rate at which the pool aims to obtain most competitive borrow rates
|
||||
* expressed in ray
|
||||
|
@ -49,6 +50,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,13 +91,23 @@ 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
|
||||
* @param availableLiquidity the liquidity available in the reserve
|
||||
* @param totalBorrowsStable the total borrowed from the reserve a stable rate
|
||||
* @param totalBorrowsVariable the total borrowed from the reserve at a variable rate
|
||||
* @param totalStableDebt the total borrowed from the reserve a stable rate
|
||||
* @param totalVariableDebt 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
|
||||
|
@ -103,9 +115,10 @@ contract DefaultReserveInterestRateStrategy is IReserveInterestRateStrategy {
|
|||
function calculateInterestRates(
|
||||
address reserve,
|
||||
uint256 availableLiquidity,
|
||||
uint256 totalBorrowsStable,
|
||||
uint256 totalBorrowsVariable,
|
||||
uint256 averageStableBorrowRate
|
||||
uint256 totalStableDebt,
|
||||
uint256 totalVariableDebt,
|
||||
uint256 averageStableBorrowRate,
|
||||
uint256 reserveFactor
|
||||
)
|
||||
external
|
||||
override
|
||||
|
@ -116,16 +129,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 = totalStableDebt.add(totalVariableDebt);
|
||||
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,56 +149,57 @@ 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(
|
||||
totalBorrowsStable,
|
||||
totalBorrowsVariable,
|
||||
currentVariableBorrowRate,
|
||||
vars.currentLiquidityRate = _getOverallBorrowRate(
|
||||
totalStableDebt,
|
||||
totalVariableDebt,
|
||||
vars.currentVariableBorrowRate,
|
||||
averageStableBorrowRate
|
||||
)
|
||||
.rayMul(utilizationRate);
|
||||
.rayMul(utilizationRate)
|
||||
.percentMul(PercentageMath.PERCENTAGE_FACTOR.sub(reserveFactor));
|
||||
|
||||
return (currentLiquidityRate, currentStableBorrowRate, currentVariableBorrowRate);
|
||||
return (vars.currentLiquidityRate, vars.currentStableBorrowRate, vars.currentVariableBorrowRate);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev calculates the overall borrow rate as the weighted average between the total variable borrows and total stable borrows.
|
||||
* @param totalBorrowsStable the total borrowed from the reserve a stable rate
|
||||
* @param totalBorrowsVariable the total borrowed from the reserve at a variable rate
|
||||
* @param totalStableDebt the total borrowed from the reserve a stable rate
|
||||
* @param totalVariableDebt the total borrowed from the reserve at a variable rate
|
||||
* @param currentVariableBorrowRate the current variable borrow rate
|
||||
* @param currentAverageStableBorrowRate the weighted average of all the stable rate borrows
|
||||
* @return the weighted averaged borrow rate
|
||||
**/
|
||||
function _getOverallBorrowRate(
|
||||
uint256 totalBorrowsStable,
|
||||
uint256 totalBorrowsVariable,
|
||||
uint256 totalStableDebt,
|
||||
uint256 totalVariableDebt,
|
||||
uint256 currentVariableBorrowRate,
|
||||
uint256 currentAverageStableBorrowRate
|
||||
) internal pure returns (uint256) {
|
||||
uint256 totalBorrows = totalBorrowsStable.add(totalBorrowsVariable);
|
||||
uint256 totalBorrows = totalStableDebt.add(totalVariableDebt);
|
||||
|
||||
if (totalBorrows == 0) return 0;
|
||||
|
||||
uint256 weightedVariableRate = totalBorrowsVariable.wadToRay().rayMul(
|
||||
uint256 weightedVariableRate = totalVariableDebt.wadToRay().rayMul(
|
||||
currentVariableBorrowRate
|
||||
);
|
||||
|
||||
uint256 weightedStableRate = totalBorrowsStable.wadToRay().rayMul(
|
||||
uint256 weightedStableRate = totalStableDebt.wadToRay().rayMul(
|
||||
currentAverageStableBorrowRate
|
||||
);
|
||||
|
||||
|
|
|
@ -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,14 @@ 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 {ISwapAdapter} from '../interfaces/ISwapAdapter.sol';
|
||||
import {LendingPoolCollateralManager} from './LendingPoolCollateralManager.sol';
|
||||
import {IPriceOracleGetter} from '../interfaces/IPriceOracleGetter.sol';
|
||||
import {SafeERC20} from '@openzeppelin/contracts/token/ERC20/SafeERC20.sol';
|
||||
import {ILendingPool} from '../interfaces/ILendingPool.sol';
|
||||
import {LendingPoolStorage} from './LendingPoolStorage.sol';
|
||||
|
||||
/**
|
||||
* @title LendingPool contract
|
||||
|
@ -32,12 +35,9 @@ import {ILendingPool} from '../interfaces/ILendingPool.sol';
|
|||
* @author Aave
|
||||
**/
|
||||
|
||||
contract LendingPool is VersionedInitializable, ILendingPool {
|
||||
contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage {
|
||||
using SafeMath for uint256;
|
||||
using WadRayMath for uint256;
|
||||
using ReserveLogic for ReserveLogic.ReserveData;
|
||||
using ReserveConfiguration for ReserveConfiguration.Map;
|
||||
using UserConfiguration for UserConfiguration.Map;
|
||||
using SafeERC20 for IERC20;
|
||||
|
||||
//main configuration parameters
|
||||
|
@ -45,18 +45,7 @@ contract LendingPool is VersionedInitializable, ILendingPool {
|
|||
uint256 public constant MAX_STABLE_RATE_BORROW_SIZE_PERCENT = 25;
|
||||
uint256 public constant FLASHLOAN_PREMIUM_TOTAL = 9;
|
||||
uint256 public constant MAX_NUMBER_RESERVES = 128;
|
||||
|
||||
ILendingPoolAddressesProvider internal _addressesProvider;
|
||||
|
||||
mapping(address => ReserveLogic.ReserveData) internal _reserves;
|
||||
mapping(address => UserConfiguration.Map) internal _usersConfig;
|
||||
// debt token address => user who gives allowance => user who receives allowance => amount
|
||||
mapping(address => mapping(address => mapping(address => uint256))) internal _borrowAllowance;
|
||||
|
||||
address[] internal _reservesList;
|
||||
|
||||
bool internal _flashLiquidationLocked;
|
||||
bool internal _paused;
|
||||
uint256 public constant LENDINGPOOL_REVISION = 0x2;
|
||||
|
||||
/**
|
||||
* @dev only lending pools configurator can use functions affected by this modifier
|
||||
|
@ -79,10 +68,6 @@ contract LendingPool is VersionedInitializable, ILendingPool {
|
|||
require(!_paused, Errors.IS_PAUSED);
|
||||
}
|
||||
|
||||
uint256 public constant UINT_MAX_VALUE = uint256(-1);
|
||||
|
||||
uint256 public constant LENDINGPOOL_REVISION = 0x2;
|
||||
|
||||
function getRevision() internal override pure returns (uint256) {
|
||||
return LENDINGPOOL_REVISION;
|
||||
}
|
||||
|
@ -116,7 +101,7 @@ contract LendingPool is VersionedInitializable, ILendingPool {
|
|||
|
||||
address aToken = reserve.aTokenAddress;
|
||||
|
||||
reserve.updateCumulativeIndexesAndTimestamp();
|
||||
reserve.updateState();
|
||||
reserve.updateInterestRates(asset, aToken, amount, 0);
|
||||
|
||||
bool isFirstDeposit = IAToken(aToken).balanceOf(onBehalfOf) == 0;
|
||||
|
@ -148,7 +133,7 @@ contract LendingPool is VersionedInitializable, ILendingPool {
|
|||
uint256 amountToWithdraw = amount;
|
||||
|
||||
//if amount is equal to uint(-1), the user wants to redeem everything
|
||||
if (amount == UINT_MAX_VALUE) {
|
||||
if (amount == type(uint256).max) {
|
||||
amountToWithdraw = userBalance;
|
||||
}
|
||||
|
||||
|
@ -163,7 +148,7 @@ contract LendingPool is VersionedInitializable, ILendingPool {
|
|||
_addressesProvider.getPriceOracle()
|
||||
);
|
||||
|
||||
reserve.updateCumulativeIndexesAndTimestamp();
|
||||
reserve.updateState();
|
||||
|
||||
reserve.updateInterestRates(asset, aToken, 0, amountToWithdraw);
|
||||
|
||||
|
@ -263,16 +248,7 @@ contract LendingPool is VersionedInitializable, ILendingPool {
|
|||
address onBehalfOf
|
||||
) external override {
|
||||
whenNotPaused();
|
||||
_executeRepay(asset, msg.sender, amount, rateMode, onBehalfOf);
|
||||
}
|
||||
|
||||
function _executeRepay(
|
||||
address asset,
|
||||
address user,
|
||||
uint256 amount,
|
||||
uint256 rateMode,
|
||||
address onBehalfOf
|
||||
) internal {
|
||||
ReserveLogic.ReserveData storage reserve = _reserves[asset];
|
||||
|
||||
(uint256 stableDebt, uint256 variableDebt) = Helpers.getUserCurrentDebt(onBehalfOf, reserve);
|
||||
|
@ -284,7 +260,7 @@ contract LendingPool is VersionedInitializable, ILendingPool {
|
|||
? stableDebt
|
||||
: variableDebt;
|
||||
|
||||
if (amount != UINT_MAX_VALUE && amount < paybackAmount) {
|
||||
if (amount != type(uint256).max && amount < paybackAmount) {
|
||||
paybackAmount = amount;
|
||||
}
|
||||
|
||||
|
@ -297,13 +273,17 @@ contract LendingPool is VersionedInitializable, ILendingPool {
|
|||
variableDebt
|
||||
);
|
||||
|
||||
reserve.updateCumulativeIndexesAndTimestamp();
|
||||
reserve.updateState();
|
||||
|
||||
//burns an equivalent amount of debt tokens
|
||||
if (interestRateMode == ReserveLogic.InterestRateMode.STABLE) {
|
||||
IStableDebtToken(reserve.stableDebtTokenAddress).burn(onBehalfOf, paybackAmount);
|
||||
} else {
|
||||
IVariableDebtToken(reserve.variableDebtTokenAddress).burn(onBehalfOf, paybackAmount);
|
||||
IVariableDebtToken(reserve.variableDebtTokenAddress).burn(
|
||||
onBehalfOf,
|
||||
paybackAmount,
|
||||
reserve.variableBorrowIndex
|
||||
);
|
||||
}
|
||||
|
||||
address aToken = reserve.aTokenAddress;
|
||||
|
@ -313,9 +293,9 @@ contract LendingPool is VersionedInitializable, ILendingPool {
|
|||
_usersConfig[onBehalfOf].setBorrowing(reserve.id, false);
|
||||
}
|
||||
|
||||
IERC20(asset).safeTransferFrom(user, aToken, paybackAmount);
|
||||
IERC20(asset).safeTransferFrom(msg.sender, aToken, paybackAmount);
|
||||
|
||||
emit Repay(asset, onBehalfOf, user, paybackAmount);
|
||||
emit Repay(asset, onBehalfOf, msg.sender, paybackAmount);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -339,15 +319,23 @@ contract LendingPool is VersionedInitializable, ILendingPool {
|
|||
interestRateMode
|
||||
);
|
||||
|
||||
reserve.updateCumulativeIndexesAndTimestamp();
|
||||
reserve.updateState();
|
||||
|
||||
if (interestRateMode == ReserveLogic.InterestRateMode.STABLE) {
|
||||
//burn stable rate tokens, mint variable rate tokens
|
||||
IStableDebtToken(reserve.stableDebtTokenAddress).burn(msg.sender, stableDebt);
|
||||
IVariableDebtToken(reserve.variableDebtTokenAddress).mint(msg.sender, stableDebt);
|
||||
IVariableDebtToken(reserve.variableDebtTokenAddress).mint(
|
||||
msg.sender,
|
||||
stableDebt,
|
||||
reserve.variableBorrowIndex
|
||||
);
|
||||
} else {
|
||||
//do the opposite
|
||||
IVariableDebtToken(reserve.variableDebtTokenAddress).burn(msg.sender, variableDebt);
|
||||
IVariableDebtToken(reserve.variableDebtTokenAddress).burn(
|
||||
msg.sender,
|
||||
variableDebt,
|
||||
reserve.variableBorrowIndex
|
||||
);
|
||||
IStableDebtToken(reserve.stableDebtTokenAddress).mint(
|
||||
msg.sender,
|
||||
variableDebt,
|
||||
|
@ -394,10 +382,9 @@ contract LendingPool is VersionedInitializable, ILendingPool {
|
|||
Errors.INTEREST_RATE_REBALANCE_CONDITIONS_NOT_MET
|
||||
);
|
||||
|
||||
reserve.updateState();
|
||||
|
||||
//burn old debt tokens, mint new ones
|
||||
|
||||
reserve.updateCumulativeIndexesAndTimestamp();
|
||||
|
||||
stableDebtToken.burn(user, stableBorrowBalance);
|
||||
stableDebtToken.mint(user, stableBorrowBalance, reserve.currentStableBorrowRate);
|
||||
|
||||
|
@ -475,19 +462,6 @@ contract LendingPool is VersionedInitializable, ILendingPool {
|
|||
}
|
||||
}
|
||||
|
||||
struct FlashLoanLocalVars {
|
||||
uint256 premium;
|
||||
uint256 amountPlusPremium;
|
||||
uint256 amountPlusPremiumInETH;
|
||||
uint256 receiverBalance;
|
||||
uint256 receiverAllowance;
|
||||
uint256 availableBalance;
|
||||
uint256 assetPrice;
|
||||
IFlashLoanReceiver receiver;
|
||||
address aTokenAddress;
|
||||
address oracle;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev flashes the underlying collateral on an user to swap for the owed asset and repay
|
||||
* - Both the owner of the position and other liquidators can execute it
|
||||
|
@ -537,6 +511,14 @@ contract LendingPool is VersionedInitializable, ILendingPool {
|
|||
_flashLiquidationLocked = false;
|
||||
}
|
||||
|
||||
struct FlashLoanLocalVars {
|
||||
uint256 premium;
|
||||
uint256 amountPlusPremium;
|
||||
IFlashLoanReceiver receiver;
|
||||
address aTokenAddress;
|
||||
address oracle;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev allows smartcontracts to access the liquidity of the pool within one transaction,
|
||||
* as long as the amount taken plus a fee is returned. NOTE There are security concerns for developers of flashloan receiver contracts
|
||||
|
@ -581,7 +563,7 @@ contract LendingPool is VersionedInitializable, ILendingPool {
|
|||
if (debtMode == ReserveLogic.InterestRateMode.NONE) {
|
||||
IERC20(asset).transferFrom(receiverAddress, vars.aTokenAddress, vars.amountPlusPremium);
|
||||
|
||||
reserve.updateCumulativeIndexesAndTimestamp();
|
||||
reserve.updateState();
|
||||
reserve.cumulateToLiquidityIndex(IERC20(vars.aTokenAddress).totalSupply(), vars.premium);
|
||||
reserve.updateInterestRates(asset, vars.aTokenAddress, vars.premium, 0);
|
||||
|
||||
|
@ -593,7 +575,7 @@ contract LendingPool is VersionedInitializable, ILendingPool {
|
|||
asset,
|
||||
msg.sender,
|
||||
msg.sender,
|
||||
vars.amountPlusPremium.sub(vars.availableBalance),
|
||||
vars.amountPlusPremium,
|
||||
mode,
|
||||
vars.aTokenAddress,
|
||||
referralCode,
|
||||
|
@ -654,6 +636,7 @@ contract LendingPool is VersionedInitializable, ILendingPool {
|
|||
uint256 ltv,
|
||||
uint256 liquidationThreshold,
|
||||
uint256 liquidationBonus,
|
||||
uint256 reserveFactor,
|
||||
address interestRateStrategyAddress,
|
||||
bool usageAsCollateralEnabled,
|
||||
bool borrowingEnabled,
|
||||
|
@ -669,6 +652,7 @@ contract LendingPool is VersionedInitializable, ILendingPool {
|
|||
reserve.configuration.getLtv(),
|
||||
reserve.configuration.getLiquidationThreshold(),
|
||||
reserve.configuration.getLiquidationBonus(),
|
||||
reserve.configuration.getReserveFactor(),
|
||||
reserve.interestRateStrategyAddress,
|
||||
reserve.configuration.getLtv() != 0,
|
||||
reserve.configuration.getBorrowingEnabled(),
|
||||
|
@ -703,8 +687,8 @@ contract LendingPool is VersionedInitializable, ILendingPool {
|
|||
view
|
||||
returns (
|
||||
uint256 availableLiquidity,
|
||||
uint256 totalBorrowsStable,
|
||||
uint256 totalBorrowsVariable,
|
||||
uint256 totalStableDebt,
|
||||
uint256 totalVariableDebt,
|
||||
uint256 liquidityRate,
|
||||
uint256 variableBorrowRate,
|
||||
uint256 stableBorrowRate,
|
||||
|
@ -715,6 +699,7 @@ contract LendingPool is VersionedInitializable, ILendingPool {
|
|||
)
|
||||
{
|
||||
ReserveLogic.ReserveData memory reserve = _reserves[asset];
|
||||
|
||||
return (
|
||||
IERC20(asset).balanceOf(reserve.aTokenAddress),
|
||||
IERC20(reserve.stableDebtTokenAddress).totalSupply(),
|
||||
|
@ -772,10 +757,9 @@ contract LendingPool is VersionedInitializable, ILendingPool {
|
|||
uint256 currentStableDebt,
|
||||
uint256 currentVariableDebt,
|
||||
uint256 principalStableDebt,
|
||||
uint256 principalVariableDebt,
|
||||
uint256 scaledVariableDebt,
|
||||
uint256 stableBorrowRate,
|
||||
uint256 liquidityRate,
|
||||
uint256 variableBorrowIndex,
|
||||
uint40 stableRateLastUpdated,
|
||||
bool usageAsCollateralEnabled
|
||||
)
|
||||
|
@ -784,14 +768,14 @@ contract LendingPool is VersionedInitializable, ILendingPool {
|
|||
|
||||
currentATokenBalance = IERC20(reserve.aTokenAddress).balanceOf(user);
|
||||
(currentStableDebt, currentVariableDebt) = Helpers.getUserCurrentDebt(user, reserve);
|
||||
(principalStableDebt, principalVariableDebt) = Helpers.getUserPrincipalDebt(user, reserve);
|
||||
principalStableDebt = IStableDebtToken(reserve.stableDebtTokenAddress).principalBalanceOf(user);
|
||||
scaledVariableDebt = IVariableDebtToken(reserve.variableDebtTokenAddress).scaledBalanceOf(user);
|
||||
liquidityRate = reserve.currentLiquidityRate;
|
||||
stableBorrowRate = IStableDebtToken(reserve.stableDebtTokenAddress).getUserStableRate(user);
|
||||
stableRateLastUpdated = IStableDebtToken(reserve.stableDebtTokenAddress).getUserLastUpdated(
|
||||
user
|
||||
);
|
||||
usageAsCollateralEnabled = _usersConfig[user].isUsingAsCollateral(reserve.id);
|
||||
variableBorrowIndex = IVariableDebtToken(reserve.variableDebtTokenAddress).getUserIndex(user);
|
||||
}
|
||||
|
||||
function getReserves() external override view returns (address[] memory) {
|
||||
|
@ -893,12 +877,12 @@ contract LendingPool is VersionedInitializable, ILendingPool {
|
|||
oracle
|
||||
);
|
||||
|
||||
uint256 reserveIndex = reserve.id;
|
||||
if (!userConfig.isBorrowing(reserveIndex)) {
|
||||
userConfig.setBorrowing(reserveIndex, true);
|
||||
uint256 reserveId = reserve.id;
|
||||
if (!userConfig.isBorrowing(reserveId)) {
|
||||
userConfig.setBorrowing(reserveId, true);
|
||||
}
|
||||
|
||||
reserve.updateCumulativeIndexesAndTimestamp();
|
||||
reserve.updateState();
|
||||
|
||||
//caching the current stable borrow rate
|
||||
uint256 currentStableRate = 0;
|
||||
|
@ -914,7 +898,11 @@ contract LendingPool is VersionedInitializable, ILendingPool {
|
|||
currentStableRate
|
||||
);
|
||||
} else {
|
||||
IVariableDebtToken(reserve.variableDebtTokenAddress).mint(vars.onBehalfOf, vars.amount);
|
||||
IVariableDebtToken(reserve.variableDebtTokenAddress).mint(
|
||||
vars.onBehalfOf,
|
||||
vars.amount,
|
||||
reserve.variableBorrowIndex
|
||||
);
|
||||
}
|
||||
|
||||
reserve.updateInterestRates(
|
||||
|
@ -1005,20 +993,6 @@ contract LendingPool is VersionedInitializable, ILendingPool {
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev returns the list of the initialized reserves
|
||||
**/
|
||||
function getReservesList() external view returns (address[] memory) {
|
||||
return _reservesList;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev returns the addresses provider
|
||||
**/
|
||||
function getAddressesProvider() external view returns (ILendingPoolAddressesProvider) {
|
||||
return _addressesProvider;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Set the _pause state
|
||||
* @param val the boolean value to set the current pause state of LendingPool
|
||||
|
|
|
@ -6,14 +6,13 @@ import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol';
|
|||
import {
|
||||
VersionedInitializable
|
||||
} from '../libraries/openzeppelin-upgradeability/VersionedInitializable.sol';
|
||||
import {LendingPoolAddressesProvider} from '../configuration/LendingPoolAddressesProvider.sol';
|
||||
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';
|
||||
import {ReserveConfiguration} from '../libraries/configuration/ReserveConfiguration.sol';
|
||||
import {UserConfiguration} from '../libraries/configuration/UserConfiguration.sol';
|
||||
import {Helpers} from '../libraries/helpers/Helpers.sol';
|
||||
import {WadRayMath} from '../libraries/math/WadRayMath.sol';
|
||||
|
@ -22,6 +21,7 @@ import {SafeERC20} from '@openzeppelin/contracts/token/ERC20/SafeERC20.sol';
|
|||
import {ISwapAdapter} from '../interfaces/ISwapAdapter.sol';
|
||||
import {Errors} from '../libraries/helpers/Errors.sol';
|
||||
import {ValidationLogic} from '../libraries/logic/ValidationLogic.sol';
|
||||
import {LendingPoolStorage} from './LendingPoolStorage.sol';
|
||||
|
||||
/**
|
||||
* @title LendingPoolCollateralManager contract
|
||||
|
@ -30,29 +30,15 @@ import {ValidationLogic} from '../libraries/logic/ValidationLogic.sol';
|
|||
* @notice this contract will be ran always through delegatecall
|
||||
* @dev LendingPoolCollateralManager inherits VersionedInitializable from OpenZeppelin to have the same storage layout as LendingPool
|
||||
**/
|
||||
contract LendingPoolCollateralManager is VersionedInitializable {
|
||||
contract LendingPoolCollateralManager is VersionedInitializable, LendingPoolStorage {
|
||||
using SafeERC20 for IERC20;
|
||||
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;
|
||||
|
||||
// IMPORTANT The storage layout of the LendingPool is reproduced here because this contract
|
||||
// is gonna be used through DELEGATECALL
|
||||
|
||||
LendingPoolAddressesProvider internal addressesProvider;
|
||||
|
||||
mapping(address => ReserveLogic.ReserveData) internal reserves;
|
||||
mapping(address => UserConfiguration.Map) internal usersConfig;
|
||||
mapping(address => mapping(address => mapping(address => uint256))) internal _borrowAllowance;
|
||||
|
||||
address[] internal reservesList;
|
||||
|
||||
bool internal _flashLiquidationLocked;
|
||||
bool public _paused;
|
||||
|
||||
uint256 internal constant LIQUIDATION_CLOSE_FACTOR_PERCENT = 5000;
|
||||
|
||||
/**
|
||||
|
@ -157,18 +143,18 @@ contract LendingPoolCollateralManager is VersionedInitializable {
|
|||
uint256 purchaseAmount,
|
||||
bool receiveAToken
|
||||
) external returns (uint256, string memory) {
|
||||
ReserveLogic.ReserveData storage collateralReserve = reserves[collateral];
|
||||
ReserveLogic.ReserveData storage principalReserve = reserves[principal];
|
||||
UserConfiguration.Map storage userConfig = usersConfig[user];
|
||||
ReserveLogic.ReserveData storage collateralReserve = _reserves[collateral];
|
||||
ReserveLogic.ReserveData storage principalReserve = _reserves[principal];
|
||||
UserConfiguration.Map storage userConfig = _usersConfig[user];
|
||||
|
||||
LiquidationCallLocalVars memory vars;
|
||||
|
||||
(, , , , vars.healthFactor) = GenericLogic.calculateUserAccountData(
|
||||
user,
|
||||
reserves,
|
||||
usersConfig[user],
|
||||
reservesList,
|
||||
addressesProvider.getPriceOracle()
|
||||
_reserves,
|
||||
_usersConfig[user],
|
||||
_reservesList,
|
||||
_addressesProvider.getPriceOracle()
|
||||
);
|
||||
|
||||
//if the user hasn't borrowed the specific currency defined by asset, it cannot be liquidated
|
||||
|
@ -236,7 +222,8 @@ contract LendingPoolCollateralManager is VersionedInitializable {
|
|||
}
|
||||
|
||||
//update the principal reserve
|
||||
principalReserve.updateCumulativeIndexesAndTimestamp();
|
||||
principalReserve.updateState();
|
||||
|
||||
principalReserve.updateInterestRates(
|
||||
principal,
|
||||
principalReserve.aTokenAddress,
|
||||
|
@ -247,13 +234,16 @@ contract LendingPoolCollateralManager is VersionedInitializable {
|
|||
if (vars.userVariableDebt >= vars.actualAmountToLiquidate) {
|
||||
IVariableDebtToken(principalReserve.variableDebtTokenAddress).burn(
|
||||
user,
|
||||
vars.actualAmountToLiquidate
|
||||
vars.actualAmountToLiquidate,
|
||||
principalReserve.variableBorrowIndex
|
||||
);
|
||||
} else {
|
||||
IVariableDebtToken(principalReserve.variableDebtTokenAddress).burn(
|
||||
user,
|
||||
vars.userVariableDebt
|
||||
vars.userVariableDebt,
|
||||
principalReserve.variableBorrowIndex
|
||||
);
|
||||
|
||||
IStableDebtToken(principalReserve.stableDebtTokenAddress).burn(
|
||||
user,
|
||||
vars.actualAmountToLiquidate.sub(vars.userVariableDebt)
|
||||
|
@ -267,7 +257,7 @@ contract LendingPoolCollateralManager is VersionedInitializable {
|
|||
//otherwise receives the underlying asset
|
||||
|
||||
//updating collateral reserve
|
||||
collateralReserve.updateCumulativeIndexesAndTimestamp();
|
||||
collateralReserve.updateState();
|
||||
collateralReserve.updateInterestRates(
|
||||
collateral,
|
||||
address(vars.collateralAtoken),
|
||||
|
@ -324,18 +314,18 @@ contract LendingPoolCollateralManager is VersionedInitializable {
|
|||
address receiver,
|
||||
bytes calldata params
|
||||
) external returns (uint256, string memory) {
|
||||
ReserveLogic.ReserveData storage collateralReserve = reserves[collateral];
|
||||
ReserveLogic.ReserveData storage debtReserve = reserves[principal];
|
||||
UserConfiguration.Map storage userConfig = usersConfig[user];
|
||||
ReserveLogic.ReserveData storage collateralReserve = _reserves[collateral];
|
||||
ReserveLogic.ReserveData storage debtReserve = _reserves[principal];
|
||||
UserConfiguration.Map storage userConfig = _usersConfig[user];
|
||||
|
||||
LiquidationCallLocalVars memory vars;
|
||||
|
||||
(, , , , vars.healthFactor) = GenericLogic.calculateUserAccountData(
|
||||
user,
|
||||
reserves,
|
||||
usersConfig[user],
|
||||
reservesList,
|
||||
addressesProvider.getPriceOracle()
|
||||
_reserves,
|
||||
_usersConfig[user],
|
||||
_reservesList,
|
||||
_addressesProvider.getPriceOracle()
|
||||
);
|
||||
|
||||
(vars.userStableDebt, vars.userVariableDebt) = Helpers.getUserCurrentDebt(user, debtReserve);
|
||||
|
@ -382,7 +372,7 @@ contract LendingPoolCollateralManager is VersionedInitializable {
|
|||
vars.actualAmountToLiquidate = vars.principalAmountNeeded;
|
||||
}
|
||||
//updating collateral reserve indexes
|
||||
collateralReserve.updateCumulativeIndexesAndTimestamp();
|
||||
collateralReserve.updateState();
|
||||
|
||||
vars.collateralAtoken.burn(
|
||||
user,
|
||||
|
@ -392,7 +382,7 @@ contract LendingPoolCollateralManager is VersionedInitializable {
|
|||
);
|
||||
|
||||
if (vars.userCollateralBalance == vars.maxCollateralToLiquidate) {
|
||||
usersConfig[user].setUsingAsCollateral(collateralReserve.id, false);
|
||||
_usersConfig[user].setUsingAsCollateral(collateralReserve.id, false);
|
||||
}
|
||||
|
||||
vars.principalAToken = debtReserve.aTokenAddress;
|
||||
|
@ -407,7 +397,7 @@ contract LendingPoolCollateralManager is VersionedInitializable {
|
|||
);
|
||||
|
||||
//updating debt reserve
|
||||
debtReserve.updateCumulativeIndexesAndTimestamp();
|
||||
debtReserve.updateState();
|
||||
debtReserve.updateInterestRates(
|
||||
principal,
|
||||
vars.principalAToken,
|
||||
|
@ -419,10 +409,15 @@ contract LendingPoolCollateralManager is VersionedInitializable {
|
|||
if (vars.userVariableDebt >= vars.actualAmountToLiquidate) {
|
||||
IVariableDebtToken(debtReserve.variableDebtTokenAddress).burn(
|
||||
user,
|
||||
vars.actualAmountToLiquidate
|
||||
vars.actualAmountToLiquidate,
|
||||
debtReserve.variableBorrowIndex
|
||||
);
|
||||
} else {
|
||||
IVariableDebtToken(debtReserve.variableDebtTokenAddress).burn(user, vars.userVariableDebt);
|
||||
IVariableDebtToken(debtReserve.variableDebtTokenAddress).burn(
|
||||
user,
|
||||
vars.userVariableDebt,
|
||||
debtReserve.variableBorrowIndex
|
||||
);
|
||||
IStableDebtToken(debtReserve.stableDebtTokenAddress).burn(
|
||||
user,
|
||||
vars.actualAmountToLiquidate.sub(vars.userVariableDebt)
|
||||
|
@ -464,10 +459,9 @@ contract LendingPoolCollateralManager is VersionedInitializable {
|
|||
uint256 amountToSwap,
|
||||
bytes calldata params
|
||||
) external returns (uint256, string memory) {
|
||||
ReserveLogic.ReserveData storage fromReserve = reserves[fromAsset];
|
||||
ReserveLogic.ReserveData storage toReserve = reserves[toAsset];
|
||||
ReserveLogic.ReserveData storage fromReserve = _reserves[fromAsset];
|
||||
ReserveLogic.ReserveData storage toReserve = _reserves[toAsset];
|
||||
|
||||
// Usage of a memory struct of vars to avoid "Stack too deep" errors due to local variables
|
||||
SwapLiquidityLocalVars memory vars;
|
||||
|
||||
(vars.errorCode, vars.errorMsg) = ValidationLogic.validateSwapLiquidity(
|
||||
|
@ -484,11 +478,11 @@ contract LendingPoolCollateralManager is VersionedInitializable {
|
|||
vars.fromReserveAToken = IAToken(fromReserve.aTokenAddress);
|
||||
vars.toReserveAToken = IAToken(toReserve.aTokenAddress);
|
||||
|
||||
fromReserve.updateCumulativeIndexesAndTimestamp();
|
||||
toReserve.updateCumulativeIndexesAndTimestamp();
|
||||
fromReserve.updateState();
|
||||
toReserve.updateState();
|
||||
|
||||
if (vars.fromReserveAToken.balanceOf(msg.sender) == amountToSwap) {
|
||||
usersConfig[msg.sender].setUsingAsCollateral(fromReserve.id, false);
|
||||
_usersConfig[msg.sender].setUsingAsCollateral(fromReserve.id, false);
|
||||
}
|
||||
|
||||
fromReserve.updateInterestRates(fromAsset, address(vars.fromReserveAToken), 0, amountToSwap);
|
||||
|
@ -517,7 +511,7 @@ contract LendingPoolCollateralManager is VersionedInitializable {
|
|||
);
|
||||
|
||||
if (vars.toReserveAToken.balanceOf(msg.sender) == 0) {
|
||||
usersConfig[msg.sender].setUsingAsCollateral(toReserve.id, true);
|
||||
_usersConfig[msg.sender].setUsingAsCollateral(toReserve.id, true);
|
||||
}
|
||||
|
||||
vars.toReserveAToken.mint(msg.sender, vars.amountToReceive, toReserve.liquidityIndex);
|
||||
|
@ -531,10 +525,10 @@ contract LendingPoolCollateralManager is VersionedInitializable {
|
|||
|
||||
(, , , , vars.healthFactor) = GenericLogic.calculateUserAccountData(
|
||||
msg.sender,
|
||||
reserves,
|
||||
usersConfig[msg.sender],
|
||||
reservesList,
|
||||
addressesProvider.getPriceOracle()
|
||||
_reserves,
|
||||
_usersConfig[msg.sender],
|
||||
_reservesList,
|
||||
_addressesProvider.getPriceOracle()
|
||||
);
|
||||
|
||||
if (vars.healthFactor < GenericLogic.HEALTH_FACTOR_LIQUIDATION_THRESHOLD) {
|
||||
|
@ -568,9 +562,8 @@ contract LendingPoolCollateralManager is VersionedInitializable {
|
|||
) internal view returns (uint256, uint256) {
|
||||
uint256 collateralAmount = 0;
|
||||
uint256 principalAmountNeeded = 0;
|
||||
IPriceOracleGetter oracle = IPriceOracleGetter(addressesProvider.getPriceOracle());
|
||||
IPriceOracleGetter oracle = IPriceOracleGetter(_addressesProvider.getPriceOracle());
|
||||
|
||||
// Usage of a memory struct of vars to avoid "Stack too deep" errors due to local variables
|
||||
AvailableCollateralToLiquidateLocalVars memory vars;
|
||||
|
||||
vars.collateralPrice = oracle.getAssetPrice(collateralAddress);
|
||||
|
|
|
@ -118,6 +118,13 @@ contract LendingPoolConfigurator is VersionedInitializable {
|
|||
**/
|
||||
event ReserveBaseLtvChanged(address asset, uint256 ltv);
|
||||
|
||||
/**
|
||||
* @dev emitted when a reserve factor is updated
|
||||
* @param asset the address of the reserve
|
||||
* @param factor the new reserve factor
|
||||
**/
|
||||
event ReserveFactorChanged(address asset, uint256 factor);
|
||||
|
||||
/**
|
||||
* @dev emitted when a reserve liquidation threshold is updated
|
||||
* @param asset the address of the reserve
|
||||
|
@ -405,8 +412,8 @@ contract LendingPoolConfigurator is VersionedInitializable {
|
|||
function deactivateReserve(address asset) external onlyAaveAdmin {
|
||||
(
|
||||
uint256 availableLiquidity,
|
||||
uint256 totalBorrowsStable,
|
||||
uint256 totalBorrowsVariable,
|
||||
uint256 totalStableDebt,
|
||||
uint256 totalVariableDebt,
|
||||
,
|
||||
,
|
||||
,
|
||||
|
@ -416,7 +423,7 @@ contract LendingPoolConfigurator is VersionedInitializable {
|
|||
|
||||
) = pool.getReserveData(asset);
|
||||
require(
|
||||
availableLiquidity == 0 && totalBorrowsStable == 0 && totalBorrowsVariable == 0,
|
||||
availableLiquidity == 0 && totalStableDebt == 0 && totalVariableDebt == 0,
|
||||
Errors.RESERVE_LIQUIDITY_NOT_0
|
||||
);
|
||||
|
||||
|
@ -458,7 +465,7 @@ contract LendingPoolConfigurator is VersionedInitializable {
|
|||
}
|
||||
|
||||
/**
|
||||
* @dev emitted when a reserve loan to value is updated
|
||||
* @dev updates the ltv of a reserve
|
||||
* @param asset the address of the reserve
|
||||
* @param ltv the new value for the loan to value
|
||||
**/
|
||||
|
@ -472,6 +479,22 @@ contract LendingPoolConfigurator is VersionedInitializable {
|
|||
emit ReserveBaseLtvChanged(asset, ltv);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev updates the reserve factor of a reserve
|
||||
* @param asset the address of the reserve
|
||||
* @param reserveFactor the new reserve factor of the reserve
|
||||
**/
|
||||
function setReserveFactor(address asset, uint256 reserveFactor) external onlyAaveAdmin {
|
||||
ReserveConfiguration.Map memory currentConfig = pool.getConfiguration(asset);
|
||||
|
||||
currentConfig.setReserveFactor(reserveFactor);
|
||||
|
||||
pool.setConfiguration(asset, currentConfig.data);
|
||||
|
||||
emit ReserveFactorChanged(asset, reserveFactor);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @dev updates the liquidation threshold of a reserve.
|
||||
* @param asset the address of the reserve
|
||||
|
@ -559,7 +582,7 @@ contract LendingPoolConfigurator is VersionedInitializable {
|
|||
payable(proxyAddress)
|
||||
);
|
||||
|
||||
(uint256 decimals, , , , , , , , , ) = pool.getReserveConfigurationData(asset);
|
||||
(uint256 decimals, , , , , , , , , , ) = pool.getReserveConfigurationData(asset);
|
||||
|
||||
bytes memory params = abi.encodeWithSignature(
|
||||
'initialize(uint8,string,string)',
|
||||
|
|
39
contracts/lendingpool/LendingPoolStorage.sol
Normal file
39
contracts/lendingpool/LendingPoolStorage.sol
Normal file
|
@ -0,0 +1,39 @@
|
|||
// SPDX-License-Identifier: agpl-3.0
|
||||
pragma solidity ^0.6.8;
|
||||
|
||||
import {UserConfiguration} from '../libraries/configuration/UserConfiguration.sol';
|
||||
import {ReserveConfiguration} from '../libraries/configuration/ReserveConfiguration.sol';
|
||||
import {ReserveLogic} from '../libraries/logic/ReserveLogic.sol';
|
||||
import {ILendingPoolAddressesProvider} from '../interfaces/ILendingPoolAddressesProvider.sol';
|
||||
|
||||
contract LendingPoolStorage {
|
||||
using ReserveLogic for ReserveLogic.ReserveData;
|
||||
using ReserveConfiguration for ReserveConfiguration.Map;
|
||||
using UserConfiguration for UserConfiguration.Map;
|
||||
|
||||
ILendingPoolAddressesProvider internal _addressesProvider;
|
||||
|
||||
mapping(address => ReserveLogic.ReserveData) internal _reserves;
|
||||
mapping(address => UserConfiguration.Map) internal _usersConfig;
|
||||
// debt token address => user who gives allowance => user who receives allowance => amount
|
||||
mapping(address => mapping(address => mapping(address => uint256))) internal _borrowAllowance;
|
||||
|
||||
address[] internal _reservesList;
|
||||
|
||||
bool internal _flashLiquidationLocked;
|
||||
bool internal _paused;
|
||||
|
||||
/**
|
||||
* @dev returns the list of the initialized reserves
|
||||
**/
|
||||
function getReservesList() external view returns (address[] memory) {
|
||||
return _reservesList;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev returns the addresses provider
|
||||
**/
|
||||
function getAddressesProvider() external view returns (ILendingPoolAddressesProvider) {
|
||||
return _addressesProvider;
|
||||
}
|
||||
}
|
|
@ -6,6 +6,7 @@ import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol';
|
|||
import {ReserveLogic} from '../logic/ReserveLogic.sol';
|
||||
import {WadRayMath} from '../math/WadRayMath.sol';
|
||||
import {IPriceOracleGetter} from '../../interfaces/IPriceOracleGetter.sol';
|
||||
import "@nomiclabs/buidler/console.sol";
|
||||
|
||||
/**
|
||||
* @title ReserveConfiguration library
|
||||
|
@ -13,14 +14,15 @@ import {IPriceOracleGetter} from '../../interfaces/IPriceOracleGetter.sol';
|
|||
* @notice Implements the bitmap logic to handle the reserve configuration
|
||||
*/
|
||||
library ReserveConfiguration {
|
||||
uint256 constant LTV_MASK = 0xFFFFFFFFFFF0000;
|
||||
uint256 constant LIQUIDATION_THRESHOLD_MASK = 0xFFFFFFF0000FFFF;
|
||||
uint256 constant LIQUIDATION_BONUS_MASK = 0xFFF0000FFFFFFFF;
|
||||
uint256 constant DECIMALS_MASK = 0xF00FFFFFFFFFFFF;
|
||||
uint256 constant ACTIVE_MASK = 0xEFFFFFFFFFFFFFF;
|
||||
uint256 constant FROZEN_MASK = 0xDFFFFFFFFFFFFFF;
|
||||
uint256 constant BORROWING_MASK = 0xBFFFFFFFFFFFFFF;
|
||||
uint256 constant STABLE_BORROWING_MASK = 0x7FFFFFFFFFFFFFF;
|
||||
uint256 constant LTV_MASK = 0xFFFFFFFFFFFFFFFF0000;
|
||||
uint256 constant LIQUIDATION_THRESHOLD_MASK = 0xFFFFFFFFFFFF0000FFFF;
|
||||
uint256 constant LIQUIDATION_BONUS_MASK = 0xFFFFFFF0000FFFFFFFF;
|
||||
uint256 constant DECIMALS_MASK = 0xFFFFFF00FFFFFFFFFFFF;
|
||||
uint256 constant ACTIVE_MASK = 0xFFFFFEFFFFFFFFFFFFFF;
|
||||
uint256 constant FROZEN_MASK = 0xFFFFFDFFFFFFFFFFFFFF;
|
||||
uint256 constant BORROWING_MASK = 0xFFFFFBFFFFFFFFFFFFFF;
|
||||
uint256 constant STABLE_BORROWING_MASK = 0xFFFF07FFFFFFFFFFFFFF;
|
||||
uint256 constant RESERVE_FACTOR_MASK = 0xFFFFFFFFFFFFFFFF;
|
||||
|
||||
struct Map {
|
||||
//bit 0-15: LTV
|
||||
|
@ -31,9 +33,28 @@ 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 reserveFactor the reserve factor
|
||||
**/
|
||||
function setReserveFactor(ReserveConfiguration.Map memory self, uint256 reserveFactor) internal pure {
|
||||
|
||||
self.data = (self.data & RESERVE_FACTOR_MASK) | reserveFactor << 64;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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) >> 64;
|
||||
}
|
||||
/**
|
||||
* @dev sets the Loan to Value of the reserve
|
||||
* @param self the reserve configuration
|
||||
|
|
|
@ -49,7 +49,6 @@ library Errors {
|
|||
string public constant CALLER_MUST_BE_LENDING_POOL = '28'; // 'The caller of this function must be a lending pool'
|
||||
string public constant CANNOT_GIVE_ALLOWANCE_TO_HIMSELF = '30'; // 'User cannot give allowance to himself'
|
||||
string public constant TRANSFER_AMOUNT_NOT_GT_0 = '31'; // 'Transferred amount needs to be greater than zero'
|
||||
string public constant INVALID_ATOKEN_BALANCE = '52'; // balance on burning is invalid
|
||||
|
||||
// require error messages - ReserveLogic
|
||||
string public constant RESERVE_ALREADY_INITIALIZED = '34'; // 'Reserve has already been initialized'
|
||||
|
|
|
@ -26,21 +26,4 @@ library Helpers {
|
|||
DebtTokenBase(reserve.variableDebtTokenAddress).balanceOf(user)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev fetches the user principal stable and variable debt balances
|
||||
* @param user the user
|
||||
* @param reserve the reserve object
|
||||
* @return the stable and variable debt balance
|
||||
**/
|
||||
function getUserPrincipalDebt(address user, ReserveLogic.ReserveData storage reserve)
|
||||
internal
|
||||
view
|
||||
returns (uint256, uint256)
|
||||
{
|
||||
return (
|
||||
DebtTokenBase(reserve.stableDebtTokenAddress).principalBalanceOf(user),
|
||||
DebtTokenBase(reserve.variableDebtTokenAddress).principalBalanceOf(user)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -69,7 +69,6 @@ library GenericLogic {
|
|||
return true;
|
||||
}
|
||||
|
||||
// Usage of a memory struct of vars to avoid "Stack too deep" errors due to local variables
|
||||
balanceDecreaseAllowedLocalVars memory vars;
|
||||
|
||||
(vars.ltv, , , vars.decimals) = reservesData[asset].configuration.getParams();
|
||||
|
|
|
@ -6,10 +6,13 @@ import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol';
|
|||
import {MathUtils} from '../math/MathUtils.sol';
|
||||
import {IPriceOracleGetter} from '../../interfaces/IPriceOracleGetter.sol';
|
||||
import {SafeERC20} from '@openzeppelin/contracts/token/ERC20/SafeERC20.sol';
|
||||
import {IAToken} from '../../tokenization/interfaces/IAToken.sol';
|
||||
import {IStableDebtToken} from '../../tokenization/interfaces/IStableDebtToken.sol';
|
||||
import {IVariableDebtToken} from '../../tokenization/interfaces/IVariableDebtToken.sol';
|
||||
import {ReserveConfiguration} from '../configuration/ReserveConfiguration.sol';
|
||||
import {IReserveInterestRateStrategy} from '../../interfaces/IReserveInterestRateStrategy.sol';
|
||||
import {WadRayMath} from '../math/WadRayMath.sol';
|
||||
import {PercentageMath} from '../math/PercentageMath.sol';
|
||||
import {Errors} from '../helpers/Errors.sol';
|
||||
|
||||
/**
|
||||
|
@ -20,6 +23,7 @@ import {Errors} from '../helpers/Errors.sol';
|
|||
library ReserveLogic {
|
||||
using SafeMath for uint256;
|
||||
using WadRayMath for uint256;
|
||||
using PercentageMath for uint256;
|
||||
using SafeERC20 for IERC20;
|
||||
|
||||
/**
|
||||
|
@ -27,7 +31,6 @@ library ReserveLogic {
|
|||
* @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
|
||||
|
@ -36,7 +39,6 @@ library ReserveLogic {
|
|||
address indexed reserve,
|
||||
uint256 liquidityRate,
|
||||
uint256 stableBorrowRate,
|
||||
uint256 averageStableBorrowRate,
|
||||
uint256 variableBorrowRate,
|
||||
uint256 liquidityIndex,
|
||||
uint256 variableBorrowIndex
|
||||
|
@ -66,6 +68,7 @@ library ReserveLogic {
|
|||
address aTokenAddress;
|
||||
address stableDebtTokenAddress;
|
||||
address variableDebtTokenAddress;
|
||||
//address of the interest rate strategy
|
||||
address interestRateStrategyAddress;
|
||||
//the id of the reserve. Represents the position in the list of the active reserves
|
||||
uint8 id;
|
||||
|
@ -144,36 +147,25 @@ library ReserveLogic {
|
|||
* a formal specification.
|
||||
* @param reserve the reserve object
|
||||
**/
|
||||
function updateCumulativeIndexesAndTimestamp(ReserveData storage reserve) internal {
|
||||
uint256 currentLiquidityRate = reserve.currentLiquidityRate;
|
||||
function updateState(ReserveData storage reserve) external {
|
||||
address variableDebtToken = reserve.variableDebtTokenAddress;
|
||||
uint256 previousVariableBorrowIndex = reserve.variableBorrowIndex;
|
||||
uint256 previousLiquidityIndex = reserve.liquidityIndex;
|
||||
|
||||
//only cumulating if there is any income being produced
|
||||
if (currentLiquidityRate > 0) {
|
||||
uint40 lastUpdateTimestamp = reserve.lastUpdateTimestamp;
|
||||
uint256 cumulatedLiquidityInterest = MathUtils.calculateLinearInterest(
|
||||
currentLiquidityRate,
|
||||
lastUpdateTimestamp
|
||||
);
|
||||
uint256 index = cumulatedLiquidityInterest.rayMul(reserve.liquidityIndex);
|
||||
require(index < (1 << 128), Errors.LIQUIDITY_INDEX_OVERFLOW);
|
||||
(uint256 newLiquidityIndex, uint256 newVariableBorrowIndex) = _updateIndexes(
|
||||
reserve,
|
||||
variableDebtToken,
|
||||
previousLiquidityIndex,
|
||||
previousVariableBorrowIndex
|
||||
);
|
||||
|
||||
reserve.liquidityIndex = uint128(index);
|
||||
|
||||
//as the liquidity rate might come only from stable rate loans, we need to ensure
|
||||
//that there is actual variable debt before accumulating
|
||||
if (IERC20(reserve.variableDebtTokenAddress).totalSupply() > 0) {
|
||||
uint256 cumulatedVariableBorrowInterest = MathUtils.calculateCompoundedInterest(
|
||||
reserve.currentVariableBorrowRate,
|
||||
lastUpdateTimestamp
|
||||
);
|
||||
index = cumulatedVariableBorrowInterest.rayMul(reserve.variableBorrowIndex);
|
||||
require(index < (1 << 128), Errors.VARIABLE_BORROW_INDEX_OVERFLOW);
|
||||
reserve.variableBorrowIndex = uint128(index);
|
||||
}
|
||||
}
|
||||
|
||||
//solium-disable-next-line
|
||||
reserve.lastUpdateTimestamp = uint40(block.timestamp);
|
||||
_mintToTreasury(
|
||||
reserve,
|
||||
variableDebtToken,
|
||||
previousVariableBorrowIndex,
|
||||
newLiquidityIndex,
|
||||
newVariableBorrowIndex
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -228,12 +220,13 @@ library ReserveLogic {
|
|||
}
|
||||
|
||||
struct UpdateInterestRatesLocalVars {
|
||||
uint256 currentAvgStableRate;
|
||||
uint256 availableLiquidity;
|
||||
address stableDebtTokenAddress;
|
||||
uint256 availableLiquidity;
|
||||
uint256 totalStableDebt;
|
||||
uint256 newLiquidityRate;
|
||||
uint256 newStableRate;
|
||||
uint256 newVariableRate;
|
||||
uint256 avgStableRate;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -253,8 +246,10 @@ library ReserveLogic {
|
|||
UpdateInterestRatesLocalVars memory vars;
|
||||
|
||||
vars.stableDebtTokenAddress = reserve.stableDebtTokenAddress;
|
||||
vars.currentAvgStableRate = IStableDebtToken(vars.stableDebtTokenAddress)
|
||||
.getAverageStableRate();
|
||||
|
||||
(vars.totalStableDebt, vars.avgStableRate) = IStableDebtToken(vars.stableDebtTokenAddress)
|
||||
.getTotalSupplyAndAvgRate();
|
||||
|
||||
vars.availableLiquidity = IERC20(reserveAddress).balanceOf(aTokenAddress);
|
||||
|
||||
(
|
||||
|
@ -264,9 +259,10 @@ library ReserveLogic {
|
|||
) = IReserveInterestRateStrategy(reserve.interestRateStrategyAddress).calculateInterestRates(
|
||||
reserveAddress,
|
||||
vars.availableLiquidity.add(liquidityAdded).sub(liquidityTaken),
|
||||
IERC20(vars.stableDebtTokenAddress).totalSupply(),
|
||||
vars.totalStableDebt,
|
||||
IERC20(reserve.variableDebtTokenAddress).totalSupply(),
|
||||
vars.currentAvgStableRate
|
||||
vars.avgStableRate,
|
||||
reserve.configuration.getReserveFactor()
|
||||
);
|
||||
require(vars.newLiquidityRate < (1 << 128), 'ReserveLogic: Liquidity rate overflow');
|
||||
require(vars.newStableRate < (1 << 128), 'ReserveLogic: Stable borrow rate overflow');
|
||||
|
@ -280,10 +276,135 @@ library ReserveLogic {
|
|||
reserveAddress,
|
||||
vars.newLiquidityRate,
|
||||
vars.newStableRate,
|
||||
vars.currentAvgStableRate,
|
||||
vars.newVariableRate,
|
||||
reserve.liquidityIndex,
|
||||
reserve.variableBorrowIndex
|
||||
);
|
||||
}
|
||||
|
||||
struct MintToTreasuryLocalVars {
|
||||
uint256 currentStableDebt;
|
||||
uint256 principalStableDebt;
|
||||
uint256 previousStableDebt;
|
||||
uint256 currentVariableDebt;
|
||||
uint256 scaledVariableDebt;
|
||||
uint256 previousVariableDebt;
|
||||
uint256 avgStableRate;
|
||||
uint256 cumulatedStableInterest;
|
||||
uint256 totalDebtAccrued;
|
||||
uint256 amountToMint;
|
||||
uint256 reserveFactor;
|
||||
uint40 stableSupplyUpdatedTimestamp;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev mints part of the repaid interest to the reserve treasury, depending on the reserveFactor for the
|
||||
* specific asset.
|
||||
* @param reserve the reserve reserve to be updated
|
||||
* @param variableDebtToken the debt token address
|
||||
* @param previousVariableBorrowIndex the variable borrow index before the last accumulation of the interest
|
||||
* @param newLiquidityIndex the new liquidity index
|
||||
* @param newVariableBorrowIndex the variable borrow index after the last accumulation of the interest
|
||||
**/
|
||||
function _mintToTreasury(
|
||||
ReserveData storage reserve,
|
||||
address variableDebtToken,
|
||||
uint256 previousVariableBorrowIndex,
|
||||
uint256 newLiquidityIndex,
|
||||
uint256 newVariableBorrowIndex
|
||||
) internal {
|
||||
MintToTreasuryLocalVars memory vars;
|
||||
|
||||
vars.reserveFactor = reserve.configuration.getReserveFactor();
|
||||
|
||||
if (vars.reserveFactor == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
//fetching the last scaled total variable debt
|
||||
vars.scaledVariableDebt = IVariableDebtToken(variableDebtToken).scaledTotalSupply();
|
||||
|
||||
//fetching the principal, total stable debt and the avg stable rate
|
||||
(
|
||||
vars.principalStableDebt,
|
||||
vars.currentStableDebt,
|
||||
vars.avgStableRate,
|
||||
vars.stableSupplyUpdatedTimestamp
|
||||
) = IStableDebtToken(reserve.stableDebtTokenAddress).getSupplyData();
|
||||
|
||||
//calculate the last principal variable debt
|
||||
vars.previousVariableDebt = vars.scaledVariableDebt.rayMul(previousVariableBorrowIndex);
|
||||
|
||||
//calculate the new total supply after accumulation of the index
|
||||
vars.currentVariableDebt = vars.scaledVariableDebt.rayMul(newVariableBorrowIndex);
|
||||
|
||||
//calculate the stable debt until the last timestamp update
|
||||
vars.cumulatedStableInterest = MathUtils.calculateCompoundedInterest(
|
||||
vars.avgStableRate,
|
||||
vars.stableSupplyUpdatedTimestamp
|
||||
);
|
||||
|
||||
vars.previousStableDebt = vars.principalStableDebt.rayMul(vars.cumulatedStableInterest);
|
||||
|
||||
//debt accrued is the sum of the current debt minus the sum of the debt at the last update
|
||||
vars.totalDebtAccrued = vars
|
||||
.currentVariableDebt
|
||||
.add(vars.currentStableDebt)
|
||||
.sub(vars.previousVariableDebt)
|
||||
.sub(vars.previousStableDebt);
|
||||
|
||||
vars.amountToMint = vars.totalDebtAccrued.percentMul(vars.reserveFactor);
|
||||
|
||||
IAToken(reserve.aTokenAddress).mintToTreasury(vars.amountToMint, newLiquidityIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev updates the reserve indexes and the timestamp of the update
|
||||
* @param reserve the reserve reserve to be updated
|
||||
* @param variableDebtToken the debt token address
|
||||
* @param liquidityIndex the last stored liquidity index
|
||||
* @param variableBorrowIndex the last stored variable borrow index
|
||||
**/
|
||||
function _updateIndexes(
|
||||
ReserveData storage reserve,
|
||||
address variableDebtToken,
|
||||
uint256 liquidityIndex,
|
||||
uint256 variableBorrowIndex
|
||||
) internal returns (uint256, uint256) {
|
||||
|
||||
uint40 timestamp = reserve.lastUpdateTimestamp;
|
||||
|
||||
uint256 currentLiquidityRate = reserve.currentLiquidityRate;
|
||||
|
||||
uint256 newLiquidityIndex = liquidityIndex;
|
||||
uint256 newVariableBorrowIndex = variableBorrowIndex;
|
||||
|
||||
//only cumulating if there is any income being produced
|
||||
if (currentLiquidityRate > 0) {
|
||||
uint256 cumulatedLiquidityInterest = MathUtils.calculateLinearInterest(
|
||||
currentLiquidityRate,
|
||||
timestamp
|
||||
);
|
||||
newLiquidityIndex = cumulatedLiquidityInterest.rayMul(liquidityIndex);
|
||||
require(newLiquidityIndex < (1 << 128), Errors.LIQUIDITY_INDEX_OVERFLOW);
|
||||
|
||||
reserve.liquidityIndex = uint128(newLiquidityIndex);
|
||||
|
||||
//as the liquidity rate might come only from stable rate loans, we need to ensure
|
||||
//that there is actual variable debt before accumulating
|
||||
if (IERC20(variableDebtToken).totalSupply() > 0) {
|
||||
uint256 cumulatedVariableBorrowInterest = MathUtils.calculateCompoundedInterest(
|
||||
reserve.currentVariableBorrowRate,
|
||||
timestamp
|
||||
);
|
||||
newVariableBorrowIndex = cumulatedVariableBorrowInterest.rayMul(variableBorrowIndex);
|
||||
require(newVariableBorrowIndex < (1 << 128), Errors.VARIABLE_BORROW_INDEX_OVERFLOW);
|
||||
reserve.variableBorrowIndex = uint128(newVariableBorrowIndex);
|
||||
}
|
||||
}
|
||||
|
||||
//solium-disable-next-line
|
||||
reserve.lastUpdateTimestamp = uint40(block.timestamp);
|
||||
return (newLiquidityIndex, newVariableBorrowIndex);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -91,7 +91,7 @@ contract WalletBalanceProvider {
|
|||
uint256[] memory balances = new uint256[](reserves.length);
|
||||
|
||||
for (uint256 j = 0; j < reserves.length; j++) {
|
||||
(, , , , , , , , bool isActive, ) = pool.getReserveConfigurationData(reserves[j]);
|
||||
(, , , , , , , , , bool isActive, ) = pool.getReserveConfigurationData(reserves[j]);
|
||||
|
||||
if (!isActive) {
|
||||
balances[j] = 0;
|
||||
|
|
|
@ -6,12 +6,13 @@ import {LendingPool} from '../../lendingpool/LendingPool.sol';
|
|||
|
||||
contract MockAToken is AToken {
|
||||
constructor(
|
||||
LendingPool _pool,
|
||||
address _underlyingAssetAddress,
|
||||
string memory _tokenName,
|
||||
string memory _tokenSymbol,
|
||||
LendingPool pool,
|
||||
address underlyingAssetAddress,
|
||||
address reserveTreasury,
|
||||
string memory tokenName,
|
||||
string memory tokenSymbol,
|
||||
address incentivesController
|
||||
) public AToken(_pool, _underlyingAssetAddress, _tokenName, _tokenSymbol, incentivesController) {}
|
||||
) public AToken(pool, underlyingAssetAddress, reserveTreasury, tokenName, tokenSymbol, incentivesController) {}
|
||||
|
||||
function getRevision() internal override pure returns (uint256) {
|
||||
return 0x2;
|
||||
|
|
|
@ -20,18 +20,8 @@ import {SafeERC20} from '../misc/SafeERC20.sol';
|
|||
*/
|
||||
contract AToken is VersionedInitializable, IncentivizedERC20, IAToken {
|
||||
using WadRayMath for uint256;
|
||||
using SafeERC20 for IncentivizedERC20;
|
||||
using SafeERC20 for IERC20;
|
||||
|
||||
uint256 public constant UINT_MAX_VALUE = uint256(-1);
|
||||
address public immutable UNDERLYING_ASSET_ADDRESS;
|
||||
LendingPool public immutable POOL;
|
||||
|
||||
/// @dev owner => next valid nonce to submit with permit()
|
||||
mapping(address => uint256) public _nonces;
|
||||
|
||||
uint256 public constant ATOKEN_REVISION = 0x1;
|
||||
|
||||
bytes32 public DOMAIN_SEPARATOR;
|
||||
bytes public constant EIP712_REVISION = bytes('1');
|
||||
bytes32 internal constant EIP712_DOMAIN = keccak256(
|
||||
'EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)'
|
||||
|
@ -40,6 +30,17 @@ contract AToken is VersionedInitializable, IncentivizedERC20, IAToken {
|
|||
'Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)'
|
||||
);
|
||||
|
||||
uint256 public constant UINT_MAX_VALUE = uint256(-1);
|
||||
uint256 public constant ATOKEN_REVISION = 0x1;
|
||||
address public immutable UNDERLYING_ASSET_ADDRESS;
|
||||
address public immutable RESERVE_TREASURY_ADDRESS;
|
||||
LendingPool public immutable POOL;
|
||||
|
||||
/// @dev owner => next valid nonce to submit with permit()
|
||||
mapping(address => uint256) public _nonces;
|
||||
|
||||
bytes32 public DOMAIN_SEPARATOR;
|
||||
|
||||
modifier onlyLendingPool {
|
||||
require(msg.sender == address(POOL), Errors.CALLER_MUST_BE_LENDING_POOL);
|
||||
_;
|
||||
|
@ -48,12 +49,14 @@ contract AToken is VersionedInitializable, IncentivizedERC20, IAToken {
|
|||
constructor(
|
||||
LendingPool pool,
|
||||
address underlyingAssetAddress,
|
||||
address reserveTreasuryAddress,
|
||||
string memory tokenName,
|
||||
string memory tokenSymbol,
|
||||
address incentivesController
|
||||
) public IncentivizedERC20(tokenName, tokenSymbol, 18, incentivesController) {
|
||||
POOL = pool;
|
||||
UNDERLYING_ASSET_ADDRESS = underlyingAssetAddress;
|
||||
RESERVE_TREASURY_ADDRESS = reserveTreasuryAddress;
|
||||
}
|
||||
|
||||
function getRevision() internal virtual override pure returns (uint256) {
|
||||
|
@ -98,20 +101,13 @@ contract AToken is VersionedInitializable, IncentivizedERC20, IAToken {
|
|||
uint256 amount,
|
||||
uint256 index
|
||||
) external override onlyLendingPool {
|
||||
uint256 currentBalance = balanceOf(user);
|
||||
|
||||
require(amount <= currentBalance, Errors.INVALID_ATOKEN_BALANCE);
|
||||
|
||||
uint256 scaledAmount = amount.rayDiv(index);
|
||||
|
||||
_burn(user, scaledAmount);
|
||||
_burn(user, amount.rayDiv(index));
|
||||
|
||||
//transfers the underlying to the target
|
||||
IncentivizedERC20(UNDERLYING_ASSET_ADDRESS).safeTransfer(receiverOfUnderlying, amount);
|
||||
IERC20(UNDERLYING_ASSET_ADDRESS).safeTransfer(receiverOfUnderlying, amount);
|
||||
|
||||
//transfer event to track balances
|
||||
emit Transfer(user, address(0), amount);
|
||||
|
||||
emit Burn(msg.sender, receiverOfUnderlying, amount, index);
|
||||
}
|
||||
|
||||
|
@ -126,16 +122,22 @@ contract AToken is VersionedInitializable, IncentivizedERC20, IAToken {
|
|||
uint256 amount,
|
||||
uint256 index
|
||||
) external override onlyLendingPool {
|
||||
uint256 scaledAmount = amount.rayDiv(index);
|
||||
|
||||
//mint an equivalent amount of tokens to cover the new deposit
|
||||
_mint(user, scaledAmount);
|
||||
_mint(user, amount.rayDiv(index));
|
||||
|
||||
//transfer event to track balances
|
||||
emit Transfer(address(0), user, amount);
|
||||
emit Mint(user, amount, index);
|
||||
}
|
||||
|
||||
function mintToTreasury(uint256 amount, uint256 index) external override onlyLendingPool {
|
||||
_mint(RESERVE_TREASURY_ADDRESS, amount.div(index));
|
||||
|
||||
//transfer event to track balances
|
||||
emit Transfer(address(0), RESERVE_TREASURY_ADDRESS, amount);
|
||||
emit Mint(RESERVE_TREASURY_ADDRESS, amount, 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
|
||||
|
@ -209,6 +211,14 @@ contract AToken is VersionedInitializable, IncentivizedERC20, IAToken {
|
|||
return currentSupplyScaled.rayMul(POOL.getReserveNormalizedIncome(UNDERLYING_ASSET_ADDRESS));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the scaled total supply of the variable debt token. Represents sum(borrows/index)
|
||||
* @return the scaled total supply
|
||||
**/
|
||||
function scaledTotalSupply() public virtual override view returns (uint256) {
|
||||
return super.totalSupply();
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Used to validate transfers before actually executing them.
|
||||
* @param user address of the user to check
|
||||
|
@ -232,7 +242,7 @@ contract AToken is VersionedInitializable, IncentivizedERC20, IAToken {
|
|||
onlyLendingPool
|
||||
returns (uint256)
|
||||
{
|
||||
IncentivizedERC20(UNDERLYING_ASSET_ADDRESS).safeTransfer(target, amount);
|
||||
IERC20(UNDERLYING_ASSET_ADDRESS).safeTransfer(target, amount);
|
||||
return amount;
|
||||
}
|
||||
|
||||
|
@ -271,6 +281,14 @@ contract AToken is VersionedInitializable, IncentivizedERC20, IAToken {
|
|||
_approve(owner, spender, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev transfers the aTokens between two users. Validates the transfer
|
||||
* (ie checks for valid HF after the transfer) if required
|
||||
* @param from the source address
|
||||
* @param to the destination address
|
||||
* @param amount the amount to transfer
|
||||
* @param validate true if the transfer needs to be validated
|
||||
**/
|
||||
function _transfer(
|
||||
address from,
|
||||
address to,
|
||||
|
@ -283,13 +301,17 @@ contract AToken is VersionedInitializable, IncentivizedERC20, IAToken {
|
|||
|
||||
uint256 index = POOL.getReserveNormalizedIncome(UNDERLYING_ASSET_ADDRESS);
|
||||
|
||||
uint256 scaledAmount = amount.rayDiv(index);
|
||||
|
||||
super._transfer(from, to, scaledAmount);
|
||||
super._transfer(from, to, amount.rayDiv(index));
|
||||
|
||||
emit BalanceTransfer(from, to, amount, index);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev overrides the parent _transfer to force validated transfer() and transferFrom()
|
||||
* @param from the source address
|
||||
* @param to the destination address
|
||||
* @param amount the amount to transfer
|
||||
**/
|
||||
function _transfer(
|
||||
address from,
|
||||
address to,
|
||||
|
|
|
@ -8,6 +8,7 @@ import {DebtTokenBase} from './base/DebtTokenBase.sol';
|
|||
import {MathUtils} from '../libraries/math/MathUtils.sol';
|
||||
import {WadRayMath} from '../libraries/math/WadRayMath.sol';
|
||||
import {IStableDebtToken} from './interfaces/IStableDebtToken.sol';
|
||||
import "@nomiclabs/buidler/console.sol";
|
||||
|
||||
/**
|
||||
* @title contract StableDebtToken
|
||||
|
@ -21,6 +22,7 @@ contract StableDebtToken is IStableDebtToken, DebtTokenBase {
|
|||
|
||||
uint256 private _avgStableRate;
|
||||
mapping(address => uint40) _timestamps;
|
||||
uint40 _totalSupplyTimestamp;
|
||||
|
||||
constructor(
|
||||
address pool,
|
||||
|
@ -68,7 +70,7 @@ contract StableDebtToken is IStableDebtToken, DebtTokenBase {
|
|||
* @return the accumulated debt of the user
|
||||
**/
|
||||
function balanceOf(address account) public virtual override view returns (uint256) {
|
||||
uint256 accountBalance = principalBalanceOf(account);
|
||||
uint256 accountBalance = super.balanceOf(account);
|
||||
uint256 stableRate = _usersData[account];
|
||||
if (accountBalance == 0) {
|
||||
return 0;
|
||||
|
@ -77,14 +79,15 @@ contract StableDebtToken is IStableDebtToken, DebtTokenBase {
|
|||
stableRate,
|
||||
_timestamps[account]
|
||||
);
|
||||
return accountBalance.wadToRay().rayMul(cumulatedInterest).rayToWad();
|
||||
return accountBalance.rayMul(cumulatedInterest);
|
||||
}
|
||||
|
||||
struct MintLocalVars {
|
||||
uint256 supplyAfterMint;
|
||||
uint256 supplyBeforeMint;
|
||||
uint256 previousSupply;
|
||||
uint256 nextSupply;
|
||||
uint256 amountInRay;
|
||||
uint256 newStableRate;
|
||||
uint256 currentAvgStableRate;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -108,8 +111,10 @@ contract StableDebtToken is IStableDebtToken, DebtTokenBase {
|
|||
uint256 balanceIncrease
|
||||
) = _calculateBalanceIncrease(user);
|
||||
|
||||
vars.supplyBeforeMint = totalSupply().add(balanceIncrease);
|
||||
vars.supplyAfterMint = vars.supplyBeforeMint.add(amount);
|
||||
//accrueing the interest accumulation to the stored total supply and caching it
|
||||
vars.previousSupply = totalSupply();
|
||||
vars.currentAvgStableRate = _avgStableRate;
|
||||
vars.nextSupply = _totalSupply = vars.previousSupply.add(amount);
|
||||
|
||||
vars.amountInRay = amount.wadToRay();
|
||||
|
||||
|
@ -122,16 +127,17 @@ contract StableDebtToken is IStableDebtToken, DebtTokenBase {
|
|||
require(vars.newStableRate < (1 << 128), 'Debt token: stable rate overflow');
|
||||
_usersData[user] = vars.newStableRate;
|
||||
|
||||
//updating the user and supply timestamp
|
||||
//solium-disable-next-line
|
||||
_timestamps[user] = uint40(block.timestamp);
|
||||
_totalSupplyTimestamp = _timestamps[user] = uint40(block.timestamp);
|
||||
|
||||
//calculates the updated average stable rate
|
||||
_avgStableRate = _avgStableRate
|
||||
.rayMul(vars.supplyBeforeMint.wadToRay())
|
||||
_avgStableRate = vars.currentAvgStableRate
|
||||
.rayMul(vars.previousSupply.wadToRay())
|
||||
.add(rate.rayMul(vars.amountInRay))
|
||||
.rayDiv(vars.supplyAfterMint.wadToRay());
|
||||
.rayDiv(vars.nextSupply.wadToRay());
|
||||
|
||||
_mint(user, amount.add(balanceIncrease));
|
||||
_mint(user, amount.add(balanceIncrease), vars.previousSupply);
|
||||
|
||||
// transfer event to track balances
|
||||
emit Transfer(address(0), user, amount);
|
||||
|
@ -158,30 +164,39 @@ contract StableDebtToken is IStableDebtToken, DebtTokenBase {
|
|||
uint256 balanceIncrease
|
||||
) = _calculateBalanceIncrease(user);
|
||||
|
||||
uint256 supplyBeforeBurn = totalSupply().add(balanceIncrease);
|
||||
uint256 supplyAfterBurn = supplyBeforeBurn.sub(amount);
|
||||
|
||||
uint256 previousSupply = totalSupply();
|
||||
|
||||
if (supplyAfterBurn == 0) {
|
||||
//since the total supply and each single user debt accrue separately,
|
||||
//there might be accumulation errors so that the last borrower repaying
|
||||
//might actually try to repay more than the available debt supply.
|
||||
//in this case we simply set the total supply and the avg stable rate to 0
|
||||
if (previousSupply <= amount) {
|
||||
_avgStableRate = 0;
|
||||
_totalSupply = 0;
|
||||
} else {
|
||||
uint256 nextSupply = _totalSupply = previousSupply.sub(amount);
|
||||
_avgStableRate = _avgStableRate
|
||||
.rayMul(supplyBeforeBurn.wadToRay())
|
||||
.rayMul(previousSupply.wadToRay())
|
||||
.sub(_usersData[user].rayMul(amount.wadToRay()))
|
||||
.rayDiv(supplyAfterBurn.wadToRay());
|
||||
.rayDiv(nextSupply.wadToRay());
|
||||
}
|
||||
|
||||
if (amount == currentBalance) {
|
||||
_usersData[user] = 0;
|
||||
_timestamps[user] = 0;
|
||||
|
||||
} else {
|
||||
//solium-disable-next-line
|
||||
_timestamps[user] = uint40(block.timestamp);
|
||||
}
|
||||
//solium-disable-next-line
|
||||
_totalSupplyTimestamp = uint40(block.timestamp);
|
||||
|
||||
if (balanceIncrease > amount) {
|
||||
_mint(user, balanceIncrease.sub(amount));
|
||||
_mint(user, balanceIncrease.sub(amount), previousSupply);
|
||||
} else {
|
||||
_burn(user, amount.sub(balanceIncrease));
|
||||
_burn(user, amount.sub(balanceIncrease), previousSupply);
|
||||
}
|
||||
|
||||
// transfer event to track balances
|
||||
|
@ -189,4 +204,127 @@ contract StableDebtToken is IStableDebtToken, DebtTokenBase {
|
|||
|
||||
emit BurnDebt(user, amount, previousBalance, currentBalance, balanceIncrease);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Calculates the increase in balance since the last user interaction
|
||||
* @param user The address of the user for which the interest is being accumulated
|
||||
* @return The previous principal balance, the new principal balance, the balance increase
|
||||
* and the new user index
|
||||
**/
|
||||
function _calculateBalanceIncrease(address user)
|
||||
internal
|
||||
view
|
||||
returns (
|
||||
uint256,
|
||||
uint256,
|
||||
uint256
|
||||
)
|
||||
{
|
||||
uint256 previousPrincipalBalance = super.balanceOf(user);
|
||||
|
||||
if (previousPrincipalBalance == 0) {
|
||||
return (0, 0, 0);
|
||||
}
|
||||
|
||||
// Calculation of the accrued interest since the last accumulation
|
||||
uint256 balanceIncrease = balanceOf(user).sub(previousPrincipalBalance);
|
||||
|
||||
return (
|
||||
previousPrincipalBalance,
|
||||
previousPrincipalBalance.add(balanceIncrease),
|
||||
balanceIncrease
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev returns the principal and total supply, the average borrow rate and the last supply update timestamp
|
||||
**/
|
||||
function getSupplyData() public override view returns (uint256, uint256, uint256,uint40) {
|
||||
uint256 avgRate = _avgStableRate;
|
||||
return (super.totalSupply(), _calcTotalSupply(avgRate), avgRate, _totalSupplyTimestamp);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev returns the the total supply and the average stable rate
|
||||
**/
|
||||
function getTotalSupplyAndAvgRate() public override view returns (uint256, uint256) {
|
||||
uint256 avgRate = _avgStableRate;
|
||||
return (_calcTotalSupply(avgRate), avgRate);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev returns the total supply
|
||||
**/
|
||||
function totalSupply() public override view returns (uint256) {
|
||||
return _calcTotalSupply(_avgStableRate);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev returns the timestamp at which the total supply was updated
|
||||
**/
|
||||
function getTotalSupplyLastUpdated() public override view returns(uint40) {
|
||||
return _totalSupplyTimestamp;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the principal debt balance of the user from
|
||||
* @param user the user
|
||||
* @return The debt balance of the user since the last burn/mint action
|
||||
**/
|
||||
function principalBalanceOf(address user) external virtual override view returns (uint256) {
|
||||
return super.balanceOf(user);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @dev calculates the total supply
|
||||
* @param avgRate the average rate at which calculate the total supply
|
||||
* @return The debt balance of the user since the last burn/mint action
|
||||
**/
|
||||
function _calcTotalSupply(uint256 avgRate) internal view returns(uint256) {
|
||||
uint256 principalSupply = super.totalSupply();
|
||||
|
||||
if (principalSupply == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint256 cumulatedInterest = MathUtils.calculateCompoundedInterest(
|
||||
avgRate,
|
||||
_totalSupplyTimestamp
|
||||
);
|
||||
|
||||
return principalSupply.rayMul(cumulatedInterest);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev mints stable debt tokens to an user
|
||||
* @param account the account receiving the debt tokens
|
||||
* @param amount the amount being minted
|
||||
* @param oldTotalSupply the total supply before the minting event
|
||||
**/
|
||||
function _mint(address account, uint256 amount, uint256 oldTotalSupply) internal {
|
||||
|
||||
uint256 oldAccountBalance = _balances[account];
|
||||
_balances[account] = oldAccountBalance.add(amount);
|
||||
|
||||
if (address(_incentivesController) != address(0)) {
|
||||
_incentivesController.handleAction(account, oldTotalSupply, oldAccountBalance);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev burns stable debt tokens of an user
|
||||
* @param account the user getting his debt burned
|
||||
* @param amount the amount being burned
|
||||
* @param oldTotalSupply the total supply before the burning event
|
||||
**/
|
||||
function _burn(address account, uint256 amount, uint256 oldTotalSupply) internal {
|
||||
|
||||
uint256 oldAccountBalance = _balances[account];
|
||||
_balances[account] = oldAccountBalance.sub(amount, 'ERC20: burn amount exceeds balance');
|
||||
|
||||
if (address(_incentivesController) != address(0)) {
|
||||
_incentivesController.handleAction(account, oldTotalSupply, oldAccountBalance);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,79 +39,81 @@ contract VariableDebtToken is DebtTokenBase, IVariableDebtToken {
|
|||
* @return the debt balance of the user
|
||||
**/
|
||||
function balanceOf(address user) public virtual override view returns (uint256) {
|
||||
uint256 userBalance = principalBalanceOf(user);
|
||||
uint256 index = _usersData[user];
|
||||
if (userBalance == 0) {
|
||||
uint256 scaledBalance = super.balanceOf(user);
|
||||
|
||||
if (scaledBalance == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return
|
||||
userBalance
|
||||
.wadToRay()
|
||||
.rayMul(POOL.getReserveNormalizedVariableDebt(UNDERLYING_ASSET))
|
||||
.rayDiv(index)
|
||||
.rayToWad();
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev returns the index of the last user action
|
||||
* @return the user index
|
||||
**/
|
||||
|
||||
function getUserIndex(address user) external virtual override view returns (uint256) {
|
||||
return _usersData[user];
|
||||
return scaledBalance.rayMul(POOL.getReserveNormalizedVariableDebt(UNDERLYING_ASSET));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev mints new variable debt
|
||||
* @param user the user receiving the debt
|
||||
* @param amount the amount of debt being minted
|
||||
* @param index the variable debt index of the reserve
|
||||
**/
|
||||
function mint(address user, uint256 amount) external override onlyLendingPool {
|
||||
(
|
||||
uint256 previousBalance,
|
||||
uint256 currentBalance,
|
||||
uint256 balanceIncrease
|
||||
) = _calculateBalanceIncrease(user);
|
||||
|
||||
_mint(user, amount.add(balanceIncrease));
|
||||
|
||||
uint256 newUserIndex = POOL.getReserveNormalizedVariableDebt(UNDERLYING_ASSET);
|
||||
require(newUserIndex < (1 << 128), 'Debt token: Index overflow');
|
||||
_usersData[user] = newUserIndex;
|
||||
function mint(
|
||||
address user,
|
||||
uint256 amount,
|
||||
uint256 index
|
||||
) external override onlyLendingPool {
|
||||
|
||||
_mint(user, amount.rayDiv(index));
|
||||
|
||||
emit Transfer(address(0), user, amount);
|
||||
emit MintDebt(user, amount, previousBalance, currentBalance, balanceIncrease, newUserIndex);
|
||||
emit Mint(user, amount, index);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev burns user variable debt
|
||||
* @param user the user which debt is burnt
|
||||
* @param amount the amount of debt being burned
|
||||
* @param index the variable debt index of the reserve
|
||||
**/
|
||||
function burn(address user, uint256 amount) external override onlyLendingPool {
|
||||
(
|
||||
uint256 previousBalance,
|
||||
uint256 currentBalance,
|
||||
uint256 balanceIncrease
|
||||
) = _calculateBalanceIncrease(user);
|
||||
function burn(
|
||||
address user,
|
||||
uint256 amount,
|
||||
uint256 index
|
||||
) external override onlyLendingPool {
|
||||
_burn(user, amount.rayDiv(index));
|
||||
|
||||
if (balanceIncrease > amount) {
|
||||
_mint(user, balanceIncrease.sub(amount));
|
||||
} else {
|
||||
_burn(user, amount.sub(balanceIncrease));
|
||||
}
|
||||
|
||||
uint256 newUserIndex = 0;
|
||||
//if user not repaid everything
|
||||
if (currentBalance != amount) {
|
||||
newUserIndex = POOL.getReserveNormalizedVariableDebt(UNDERLYING_ASSET);
|
||||
require(newUserIndex < (1 << 128), 'Debt token: Index overflow');
|
||||
}
|
||||
_usersData[user] = newUserIndex;
|
||||
|
||||
// transfer event to track the balances
|
||||
emit Transfer(user, address(0), amount);
|
||||
emit BurnDebt(user, amount, previousBalance, currentBalance, balanceIncrease, newUserIndex);
|
||||
emit Burn(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 scaledBalanceOf(address user) public virtual override view returns (uint256) {
|
||||
return super.balanceOf(user);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the total supply of the variable debt token. Represents the total debt accrued by the users
|
||||
* @return the total supply
|
||||
**/
|
||||
function totalSupply() public virtual override view returns (uint256) {
|
||||
return super.totalSupply().rayMul(POOL.getReserveNormalizedVariableDebt(UNDERLYING_ASSET));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the scaled total supply of the variable debt token. Represents sum(borrows/index)
|
||||
* @return the scaled total supply
|
||||
**/
|
||||
function scaledTotalSupply() public virtual override view returns (uint256) {
|
||||
return super.totalSupply();
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev returns the principal balance of the user and principal total supply.
|
||||
* @param user the address of the user
|
||||
* @return the principal balance of the user
|
||||
* @return the principal total supply
|
||||
**/
|
||||
function getScaledUserBalanceAndSupply(address user) external override view returns (uint256, uint256){
|
||||
return (super.balanceOf(user), super.totalSupply());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -65,14 +65,6 @@ abstract contract DebtTokenBase is IncentivizedERC20, VersionedInitializable {
|
|||
return UNDERLYING_ASSET;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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) {
|
||||
return super.balanceOf(user);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Being non transferrable, the debt token does not implement any of the
|
||||
* standard ERC20 functions for transfer and allowance.
|
||||
|
@ -133,35 +125,4 @@ abstract contract DebtTokenBase is IncentivizedERC20, VersionedInitializable {
|
|||
subtractedValue;
|
||||
revert('ALLOWANCE_NOT_SUPPORTED');
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Calculates the increase in balance since the last user interaction
|
||||
* @param user The address of the user for which the interest is being accumulated
|
||||
* @return The previous principal balance, the new principal balance, the balance increase
|
||||
* and the new user index
|
||||
**/
|
||||
function _calculateBalanceIncrease(address user)
|
||||
internal
|
||||
view
|
||||
returns (
|
||||
uint256,
|
||||
uint256,
|
||||
uint256
|
||||
)
|
||||
{
|
||||
uint256 previousPrincipalBalance = principalBalanceOf(user);
|
||||
|
||||
if (previousPrincipalBalance == 0) {
|
||||
return (0, 0, 0);
|
||||
}
|
||||
|
||||
// Calculation of the accrued interest since the last accumulation
|
||||
uint256 balanceIncrease = balanceOf(user).sub(previousPrincipalBalance);
|
||||
|
||||
return (
|
||||
previousPrincipalBalance,
|
||||
previousPrincipalBalance.add(balanceIncrease),
|
||||
balanceIncrease
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,8 +2,9 @@
|
|||
pragma solidity ^0.6.8;
|
||||
|
||||
import {IERC20} from '../../interfaces/IERC20.sol';
|
||||
import {IScaledBalanceToken} from './IScaledBalanceToken.sol';
|
||||
|
||||
interface IAToken is IERC20 {
|
||||
interface IAToken is IERC20, IScaledBalanceToken {
|
||||
/**
|
||||
* @dev emitted after aTokens are burned
|
||||
* @param from the address performing the redeem
|
||||
|
@ -16,15 +17,6 @@ interface IAToken is IERC20 {
|
|||
uint256 value,
|
||||
uint256 index
|
||||
);
|
||||
|
||||
/**
|
||||
* @dev emitted after the mint action
|
||||
* @param from the address performing the mint
|
||||
* @param value the amount to be minted
|
||||
* @param index the last index of the reserve
|
||||
**/
|
||||
event Mint(address indexed from, uint256 value, uint256 index);
|
||||
|
||||
/**
|
||||
* @dev emitted during the transfer action
|
||||
* @param from the address from which the tokens are being transferred
|
||||
|
@ -38,7 +30,6 @@ interface IAToken is IERC20 {
|
|||
uint256 value,
|
||||
uint256 index
|
||||
);
|
||||
|
||||
/**
|
||||
* @dev burns the aTokens and sends the equivalent amount of underlying to the target.
|
||||
* only lending pools can call this function
|
||||
|
@ -53,13 +44,11 @@ interface IAToken is IERC20 {
|
|||
) external;
|
||||
|
||||
/**
|
||||
* @dev mints aTokens to user
|
||||
* only lending pools can call this function
|
||||
* @param user the address receiving the minted tokens
|
||||
* @param amount the amount of tokens to mint
|
||||
* @param index the liquidity index
|
||||
*/
|
||||
function mint(address user, uint256 amount, uint256 index) external;
|
||||
* @dev mints aTokens to the reserve treasury
|
||||
* @param amount the amount to mint
|
||||
* @param index the liquidity index of the reserve
|
||||
**/
|
||||
function mintToTreasury(uint256 amount, uint256 index) external;
|
||||
|
||||
/**
|
||||
* @dev transfers tokens in the event of a borrow being liquidated, in case the liquidators reclaims the aToken
|
||||
|
@ -74,28 +63,7 @@ interface IAToken is IERC20 {
|
|||
uint256 value
|
||||
) external;
|
||||
|
||||
/**
|
||||
* @dev returns the principal balance of the user. The principal balance is the last
|
||||
* updated stored balance, which does not consider the perpetually accruing interest.
|
||||
* @param user the address of the user
|
||||
* @return the principal balance of the user
|
||||
**/
|
||||
function scaledBalanceOf(address user) external view returns (uint256);
|
||||
|
||||
/**
|
||||
* @dev returns the principal balance of the user and principal total supply.
|
||||
* @param user the address of the user
|
||||
* @return the principal balance of the user
|
||||
* @return the principal total supply
|
||||
**/
|
||||
function getScaledUserBalanceAndSupply(address user) external view returns (uint256, uint256);
|
||||
|
||||
/**
|
||||
* @dev Used to validate transfers before actually executing them.
|
||||
* @param user address of the user to check
|
||||
* @param amount the amount to check
|
||||
* @return true if the user can transfer amount, false otherwise
|
||||
**/
|
||||
|
||||
function isTransferAllowed(address user, uint256 amount) external view returns (bool);
|
||||
|
||||
/**
|
||||
|
@ -104,6 +72,7 @@ interface IAToken is IERC20 {
|
|||
* @param amount the amount to transfer
|
||||
* @return the amount transferred
|
||||
**/
|
||||
|
||||
function transferUnderlyingTo(address user, uint256 amount) external returns (uint256);
|
||||
|
||||
|
||||
}
|
||||
|
|
49
contracts/tokenization/interfaces/IScaledBalanceToken.sol
Normal file
49
contracts/tokenization/interfaces/IScaledBalanceToken.sol
Normal file
|
@ -0,0 +1,49 @@
|
|||
|
||||
// SPDX-License-Identifier: agpl-3.0
|
||||
pragma solidity ^0.6.8;
|
||||
|
||||
interface IScaledBalanceToken {
|
||||
|
||||
/**
|
||||
* @dev emitted after the mint action
|
||||
* @param from the address performing the mint
|
||||
* @param value the amount to be minted
|
||||
* @param index the last index of the reserve
|
||||
**/
|
||||
event Mint(address indexed from, uint256 value, uint256 index);
|
||||
|
||||
/**
|
||||
* @dev mints aTokens to user
|
||||
* only lending pools can call this function
|
||||
* @param user the address receiving the minted tokens
|
||||
* @param amount the amount of tokens to mint
|
||||
* @param index the liquidity index
|
||||
*/
|
||||
function mint(
|
||||
address user,
|
||||
uint256 amount,
|
||||
uint256 index
|
||||
) external;
|
||||
|
||||
/**
|
||||
* @dev returns the principal balance of the user. The principal balance is the last
|
||||
* updated stored balance, which does not consider the perpetually accruing interest.
|
||||
* @param user the address of the user
|
||||
* @return the principal balance of the user
|
||||
**/
|
||||
function scaledBalanceOf(address user) external view returns (uint256);
|
||||
|
||||
/**
|
||||
* @dev returns the principal balance of the user and principal total supply.
|
||||
* @param user the address of the user
|
||||
* @return the principal balance of the user
|
||||
* @return the principal total supply
|
||||
**/
|
||||
function getScaledUserBalanceAndSupply(address user) external view returns (uint256, uint256);
|
||||
|
||||
/**
|
||||
* @dev Returns the scaled total supply of the variable debt token. Represents sum(borrows/index)
|
||||
* @return the scaled total supply
|
||||
**/
|
||||
function scaledTotalSupply() external view returns (uint256);
|
||||
}
|
|
@ -84,4 +84,26 @@ interface IStableDebtToken {
|
|||
* @return the timestamp
|
||||
**/
|
||||
function getUserLastUpdated(address user) external view returns (uint40);
|
||||
|
||||
/**
|
||||
* @dev returns the principal, the total supply and the average stable rate
|
||||
**/
|
||||
function getSupplyData() external view returns (uint256, uint256, uint256, uint40);
|
||||
|
||||
/**
|
||||
* @dev returns the timestamp of the last update of the total supply
|
||||
* @return the timestamp
|
||||
**/
|
||||
function getTotalSupplyLastUpdated() external view returns (uint40);
|
||||
|
||||
/**
|
||||
* @dev returns the total supply and the average stable rate
|
||||
**/
|
||||
function getTotalSupplyAndAvgRate() external view returns (uint256, uint256);
|
||||
|
||||
/**
|
||||
* @dev Returns the principal debt balance of the user
|
||||
* @return The debt balance of the user since the last burn/mint action
|
||||
**/
|
||||
function principalBalanceOf(address user) external view returns (uint256);
|
||||
}
|
||||
|
|
|
@ -1,66 +1,36 @@
|
|||
// SPDX-License-Identifier: agpl-3.0
|
||||
pragma solidity ^0.6.8;
|
||||
|
||||
import {IScaledBalanceToken} from './IScaledBalanceToken.sol';
|
||||
|
||||
/**
|
||||
* @title interface IVariableDebtToken
|
||||
* @author Aave
|
||||
* @notice defines the basic interface for a variable debt token.
|
||||
* @dev does not inherit from IERC20 to save in contract size
|
||||
**/
|
||||
interface IVariableDebtToken {
|
||||
/**
|
||||
* @dev emitted when new variable debt is minted
|
||||
* @param user the user receiving the debt
|
||||
* @param amount the amount of debt being minted
|
||||
* @param previousBalance the previous balance of the user
|
||||
* @param currentBalance the current balance of the user
|
||||
* @param balanceIncrease the debt accumulated since the last action
|
||||
* @param index the index of the user
|
||||
**/
|
||||
event MintDebt(
|
||||
address user,
|
||||
uint256 amount,
|
||||
uint256 previousBalance,
|
||||
uint256 currentBalance,
|
||||
uint256 balanceIncrease,
|
||||
uint256 index
|
||||
);
|
||||
|
||||
interface IVariableDebtToken is IScaledBalanceToken {
|
||||
|
||||
/**
|
||||
* @dev emitted when variable debt is burnt
|
||||
* @param user the user which debt has been burned
|
||||
* @param amount the amount of debt being burned
|
||||
* @param previousBalance the previous balance of the user
|
||||
* @param currentBalance the current balance of the user
|
||||
* @param balanceIncrease the debt accumulated since the last action
|
||||
* @param index the index of the user
|
||||
**/
|
||||
event BurnDebt(
|
||||
address user,
|
||||
event Burn(
|
||||
address indexed user,
|
||||
uint256 amount,
|
||||
uint256 previousBalance,
|
||||
uint256 currentBalance,
|
||||
uint256 balanceIncrease,
|
||||
uint256 index
|
||||
);
|
||||
|
||||
/**
|
||||
* @dev mints new variable debt
|
||||
* @param user the user receiving the debt
|
||||
* @param amount the amount of debt being minted
|
||||
**/
|
||||
function mint(address user, uint256 amount) external;
|
||||
|
||||
/**
|
||||
/**
|
||||
* @dev burns user variable debt
|
||||
* @param user the user which debt is burnt
|
||||
* @param amount the amount of debt being burned
|
||||
* @param index the variable debt index of the reserve
|
||||
**/
|
||||
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);
|
||||
function burn(
|
||||
address user,
|
||||
uint256 amount,
|
||||
uint256 index
|
||||
) external;
|
||||
|
||||
}
|
||||
|
|
|
@ -5,7 +5,11 @@
|
|||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
},
|
||||
"localhost": {
|
||||
"address": "0x9Dc554694756dC303a087e04bA6918C333Bc26a7",
|
||||
"address": "0x58F132FBB86E21545A4Bace3C19f1C05d86d7A22",
|
||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
},
|
||||
"coverage": {
|
||||
"address": "0x58F132FBB86E21545A4Bace3C19f1C05d86d7A22",
|
||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
}
|
||||
},
|
||||
|
@ -15,7 +19,11 @@
|
|||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
},
|
||||
"localhost": {
|
||||
"address": "0xAfC307938C1c0035942c141c31524504c89Aaa8B",
|
||||
"address": "0xa4bcDF64Cdd5451b6ac3743B414124A6299B65FF",
|
||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
},
|
||||
"coverage": {
|
||||
"address": "0xa4bcDF64Cdd5451b6ac3743B414124A6299B65FF",
|
||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
}
|
||||
},
|
||||
|
@ -25,7 +33,11 @@
|
|||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
},
|
||||
"localhost": {
|
||||
"address": "0x73DE1e0ab6A5C221258703bc546E0CAAcCc6EC87",
|
||||
"address": "0x5A0773Ff307Bf7C71a832dBB5312237fD3437f9F",
|
||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
},
|
||||
"coverage": {
|
||||
"address": "0x5A0773Ff307Bf7C71a832dBB5312237fD3437f9F",
|
||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
}
|
||||
},
|
||||
|
@ -53,7 +65,10 @@
|
|||
"address": "0x6642B57e4265BAD868C17Fc1d1F4F88DBBA04Aa8"
|
||||
},
|
||||
"localhost": {
|
||||
"address": "0x65e0Cd5B8904A02f2e00BC6f58bf881998D54BDe"
|
||||
"address": "0x6642B57e4265BAD868C17Fc1d1F4F88DBBA04Aa8"
|
||||
},
|
||||
"coverage": {
|
||||
"address": "0x6642B57e4265BAD868C17Fc1d1F4F88DBBA04Aa8"
|
||||
}
|
||||
},
|
||||
"LendingPoolDataProvider": {
|
||||
|
@ -66,7 +81,10 @@
|
|||
"address": "0xD9273d497eDBC967F39d419461CfcF382a0A822e"
|
||||
},
|
||||
"localhost": {
|
||||
"address": "0x5d12dDe3286D94E0d85F9D3B01B7099cfA0aBCf1"
|
||||
"address": "0xD9273d497eDBC967F39d419461CfcF382a0A822e"
|
||||
},
|
||||
"coverage": {
|
||||
"address": "0xD9273d497eDBC967F39d419461CfcF382a0A822e"
|
||||
}
|
||||
},
|
||||
"PriceOracle": {
|
||||
|
@ -75,7 +93,11 @@
|
|||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
},
|
||||
"localhost": {
|
||||
"address": "0xbeA90474c2F3C7c43bC7c36CaAf5272c927Af5a1",
|
||||
"address": "0x1750499D05Ed1674d822430FB960d5F6731fDf64",
|
||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
},
|
||||
"coverage": {
|
||||
"address": "0x1750499D05Ed1674d822430FB960d5F6731fDf64",
|
||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
}
|
||||
},
|
||||
|
@ -85,7 +107,11 @@
|
|||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
},
|
||||
"localhost": {
|
||||
"address": "0x19E42cA990cF697D3dda0e59131215C43bB6989F",
|
||||
"address": "0xEC1C93A9f6a9e18E97784c76aC52053587FcDB89",
|
||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
},
|
||||
"coverage": {
|
||||
"address": "0xEC1C93A9f6a9e18E97784c76aC52053587FcDB89",
|
||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
}
|
||||
},
|
||||
|
@ -95,7 +121,11 @@
|
|||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
},
|
||||
"localhost": {
|
||||
"address": "0xE30c3983E51bC9d6baE3E9437710a1459e21e81F",
|
||||
"address": "0x7B6C3e5486D9e6959441ab554A889099eed76290",
|
||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
},
|
||||
"coverage": {
|
||||
"address": "0x7B6C3e5486D9e6959441ab554A889099eed76290",
|
||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
}
|
||||
},
|
||||
|
@ -105,7 +135,11 @@
|
|||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
},
|
||||
"localhost": {
|
||||
"address": "0xDf69898e844197a24C658CcF9fD53dF15948dc8b",
|
||||
"address": "0xD83D2773a7873ae2b5f8Fb92097e20a8C64F691E",
|
||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
},
|
||||
"coverage": {
|
||||
"address": "0xD83D2773a7873ae2b5f8Fb92097e20a8C64F691E",
|
||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
}
|
||||
},
|
||||
|
@ -115,7 +149,11 @@
|
|||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
},
|
||||
"localhost": {
|
||||
"address": "0xBe6d8642382C241c9B4B50c89574DbF3f4181E7D",
|
||||
"address": "0x626FdE749F9d499d3777320CAf29484B624ab84a",
|
||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
},
|
||||
"coverage": {
|
||||
"address": "0x626FdE749F9d499d3777320CAf29484B624ab84a",
|
||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
}
|
||||
},
|
||||
|
@ -169,7 +207,10 @@
|
|||
"address": "0x2B681757d757fbB80cc51c6094cEF5eE75bF55aA"
|
||||
},
|
||||
"localhost": {
|
||||
"address": "0xAd49512dFBaD6fc13D67d3935283c0606812E962"
|
||||
"address": "0x2B681757d757fbB80cc51c6094cEF5eE75bF55aA"
|
||||
},
|
||||
"coverage": {
|
||||
"address": "0x2B681757d757fbB80cc51c6094cEF5eE75bF55aA"
|
||||
}
|
||||
},
|
||||
"WalletBalanceProvider": {
|
||||
|
@ -178,7 +219,11 @@
|
|||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
},
|
||||
"localhost": {
|
||||
"address": "0xA29C2A7e59aa49C71aF084695337E3AA5e820758",
|
||||
"address": "0xDf73fC454FA018051D4a1509e63D11530A59DE10",
|
||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
},
|
||||
"coverage": {
|
||||
"address": "0xDf73fC454FA018051D4a1509e63D11530A59DE10",
|
||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
}
|
||||
},
|
||||
|
@ -188,7 +233,11 @@
|
|||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
},
|
||||
"localhost": {
|
||||
"address": "0xbe66dC9DFEe580ED968403e35dF7b5159f873df8",
|
||||
"address": "0x7c2C195CD6D34B8F845992d380aADB2730bB9C6F",
|
||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
},
|
||||
"coverage": {
|
||||
"address": "0x7c2C195CD6D34B8F845992d380aADB2730bB9C6F",
|
||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
}
|
||||
},
|
||||
|
@ -198,7 +247,11 @@
|
|||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
},
|
||||
"localhost": {
|
||||
"address": "0x93AfC6Df4bB8F62F2493B19e577f8382c0BA9EBC",
|
||||
"address": "0x8858eeB3DfffA017D4BCE9801D340D36Cf895CCf",
|
||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
},
|
||||
"coverage": {
|
||||
"address": "0x8858eeB3DfffA017D4BCE9801D340D36Cf895CCf",
|
||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
}
|
||||
},
|
||||
|
@ -208,7 +261,11 @@
|
|||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
},
|
||||
"localhost": {
|
||||
"address": "0x75Ded61646B5945BdDd0CD9a9Db7c8288DA6F810",
|
||||
"address": "0x0078371BDeDE8aAc7DeBfFf451B74c5EDB385Af7",
|
||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
},
|
||||
"coverage": {
|
||||
"address": "0x0078371BDeDE8aAc7DeBfFf451B74c5EDB385Af7",
|
||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
}
|
||||
},
|
||||
|
@ -218,7 +275,11 @@
|
|||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
},
|
||||
"localhost": {
|
||||
"address": "0xdE7c40e675bF1aA45c18cCbaEb9662B16b0Ddf7E",
|
||||
"address": "0xf4e77E5Da47AC3125140c470c71cBca77B5c638c",
|
||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
},
|
||||
"coverage": {
|
||||
"address": "0xf4e77E5Da47AC3125140c470c71cBca77B5c638c",
|
||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
}
|
||||
},
|
||||
|
@ -228,7 +289,11 @@
|
|||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
},
|
||||
"localhost": {
|
||||
"address": "0xDFbeeed692AA81E7f86E72F7ACbEA2A1C4d63544",
|
||||
"address": "0x3619DbE27d7c1e7E91aA738697Ae7Bc5FC3eACA5",
|
||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
},
|
||||
"coverage": {
|
||||
"address": "0x3619DbE27d7c1e7E91aA738697Ae7Bc5FC3eACA5",
|
||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
}
|
||||
},
|
||||
|
@ -238,7 +303,11 @@
|
|||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
},
|
||||
"localhost": {
|
||||
"address": "0x5191aA68c7dB195181Dd2441dBE23A48EA24b040",
|
||||
"address": "0x038B86d9d8FAFdd0a02ebd1A476432877b0107C8",
|
||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
},
|
||||
"coverage": {
|
||||
"address": "0x038B86d9d8FAFdd0a02ebd1A476432877b0107C8",
|
||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
}
|
||||
},
|
||||
|
@ -248,7 +317,11 @@
|
|||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
},
|
||||
"localhost": {
|
||||
"address": "0x8F9422aa37215c8b3D1Ea1674138107F84D68F26",
|
||||
"address": "0x1A1FEe7EeD918BD762173e4dc5EfDB8a78C924A8",
|
||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
},
|
||||
"coverage": {
|
||||
"address": "0x1A1FEe7EeD918BD762173e4dc5EfDB8a78C924A8",
|
||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
}
|
||||
},
|
||||
|
@ -258,7 +331,11 @@
|
|||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
},
|
||||
"localhost": {
|
||||
"address": "0xa89E20284Bd638F31b0011D0fC754Fc9d2fa73e3",
|
||||
"address": "0x500D1d6A4c7D8Ae28240b47c8FCde034D827fD5e",
|
||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
},
|
||||
"coverage": {
|
||||
"address": "0x500D1d6A4c7D8Ae28240b47c8FCde034D827fD5e",
|
||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
}
|
||||
},
|
||||
|
@ -268,7 +345,11 @@
|
|||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
},
|
||||
"localhost": {
|
||||
"address": "0xaA935993065F2dDB1d13623B1941C7AEE3A60F23",
|
||||
"address": "0xc4905364b78a742ccce7B890A89514061E47068D",
|
||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
},
|
||||
"coverage": {
|
||||
"address": "0xc4905364b78a742ccce7B890A89514061E47068D",
|
||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
}
|
||||
},
|
||||
|
@ -278,7 +359,11 @@
|
|||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
},
|
||||
"localhost": {
|
||||
"address": "0x35A2624888e207e4B3434E9a9E250bF6Ee68FeA3",
|
||||
"address": "0xD6C850aeBFDC46D7F4c207e445cC0d6B0919BDBe",
|
||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
},
|
||||
"coverage": {
|
||||
"address": "0xD6C850aeBFDC46D7F4c207e445cC0d6B0919BDBe",
|
||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
}
|
||||
},
|
||||
|
@ -288,7 +373,11 @@
|
|||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
},
|
||||
"localhost": {
|
||||
"address": "0x1f569c307949a908A4b8Ff7453a88Ca0b8D8df13",
|
||||
"address": "0x8B5B7a6055E54a36fF574bbE40cf2eA68d5554b3",
|
||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
},
|
||||
"coverage": {
|
||||
"address": "0x8B5B7a6055E54a36fF574bbE40cf2eA68d5554b3",
|
||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
}
|
||||
},
|
||||
|
@ -298,7 +387,11 @@
|
|||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
},
|
||||
"localhost": {
|
||||
"address": "0x4301cb254CCc126B9eb9cbBE030C6FDA2FA16D4a",
|
||||
"address": "0xEcc0a6dbC0bb4D51E4F84A315a9e5B0438cAD4f0",
|
||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
},
|
||||
"coverage": {
|
||||
"address": "0xEcc0a6dbC0bb4D51E4F84A315a9e5B0438cAD4f0",
|
||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
}
|
||||
},
|
||||
|
@ -308,7 +401,11 @@
|
|||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
},
|
||||
"localhost": {
|
||||
"address": "0x0766c9592a8686CAB0081b4f35449462c6e82F11",
|
||||
"address": "0x20Ce94F404343aD2752A2D01b43fa407db9E0D00",
|
||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
},
|
||||
"coverage": {
|
||||
"address": "0x20Ce94F404343aD2752A2D01b43fa407db9E0D00",
|
||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
}
|
||||
},
|
||||
|
@ -318,7 +415,11 @@
|
|||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
},
|
||||
"localhost": {
|
||||
"address": "0xaF6D34adD35E1A565be4539E4d1069c48A49C953",
|
||||
"address": "0x1d80315fac6aBd3EfeEbE97dEc44461ba7556160",
|
||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
},
|
||||
"coverage": {
|
||||
"address": "0x1d80315fac6aBd3EfeEbE97dEc44461ba7556160",
|
||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
}
|
||||
},
|
||||
|
@ -328,7 +429,11 @@
|
|||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
},
|
||||
"localhost": {
|
||||
"address": "0x48bb3E35D2D6994374db457a6Bf61de2d9cC8E49",
|
||||
"address": "0x2D8553F9ddA85A9B3259F6Bf26911364B85556F5",
|
||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
},
|
||||
"coverage": {
|
||||
"address": "0x2D8553F9ddA85A9B3259F6Bf26911364B85556F5",
|
||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
}
|
||||
},
|
||||
|
@ -338,7 +443,11 @@
|
|||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
},
|
||||
"localhost": {
|
||||
"address": "0x1E59BA56B1F61c3Ee946D8c7e2994B4A9b0cA45C",
|
||||
"address": "0x52d3b94181f8654db2530b0fEe1B19173f519C52",
|
||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
},
|
||||
"coverage": {
|
||||
"address": "0x52d3b94181f8654db2530b0fEe1B19173f519C52",
|
||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
}
|
||||
},
|
||||
|
@ -348,7 +457,11 @@
|
|||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
},
|
||||
"localhost": {
|
||||
"address": "0x53813198c75959DDB604462831d8989C29152164",
|
||||
"address": "0xd15468525c35BDBC1eD8F2e09A00F8a173437f2f",
|
||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
},
|
||||
"coverage": {
|
||||
"address": "0xd15468525c35BDBC1eD8F2e09A00F8a173437f2f",
|
||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
}
|
||||
},
|
||||
|
@ -358,7 +471,11 @@
|
|||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
},
|
||||
"localhost": {
|
||||
"address": "0x0eD6115873ce6B807a03FE0df1f940387779b729",
|
||||
"address": "0x7e35Eaf7e8FBd7887ad538D4A38Df5BbD073814a",
|
||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
},
|
||||
"coverage": {
|
||||
"address": "0x7e35Eaf7e8FBd7887ad538D4A38Df5BbD073814a",
|
||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
}
|
||||
},
|
||||
|
@ -368,7 +485,11 @@
|
|||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
},
|
||||
"localhost": {
|
||||
"address": "0xFFfDa24e7E3d5F89a24278f53d6f0F81B3bE0d6B",
|
||||
"address": "0x5bcb88A0d20426e451332eE6C4324b0e663c50E0",
|
||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
},
|
||||
"coverage": {
|
||||
"address": "0x5bcb88A0d20426e451332eE6C4324b0e663c50E0",
|
||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
}
|
||||
},
|
||||
|
@ -378,7 +499,11 @@
|
|||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
},
|
||||
"localhost": {
|
||||
"address": "0x5889354f21A1C8D8D2f82669d778f6Dab778B519",
|
||||
"address": "0x3521eF8AaB0323004A6dD8b03CE890F4Ea3A13f5",
|
||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
},
|
||||
"coverage": {
|
||||
"address": "0x3521eF8AaB0323004A6dD8b03CE890F4Ea3A13f5",
|
||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
}
|
||||
},
|
||||
|
@ -388,7 +513,11 @@
|
|||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
},
|
||||
"localhost": {
|
||||
"address": "0x09F7bF33B3F8922268B34103af3a8AF83148C9B1",
|
||||
"address": "0x53369fd4680FfE3DfF39Fc6DDa9CfbfD43daeA2E",
|
||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
},
|
||||
"coverage": {
|
||||
"address": "0x53369fd4680FfE3DfF39Fc6DDa9CfbfD43daeA2E",
|
||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
}
|
||||
},
|
||||
|
@ -398,7 +527,11 @@
|
|||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
},
|
||||
"localhost": {
|
||||
"address": "0x8f3966F7d53Fd5f12b701C8835e1e32541613869",
|
||||
"address": "0xB00cC45B4a7d3e1FEE684cFc4417998A1c183e6d",
|
||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
},
|
||||
"coverage": {
|
||||
"address": "0xB00cC45B4a7d3e1FEE684cFc4417998A1c183e6d",
|
||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
}
|
||||
},
|
||||
|
@ -408,7 +541,11 @@
|
|||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
},
|
||||
"localhost": {
|
||||
"address": "0x9Dc554694756dC303a087e04bA6918C333Bc26a7",
|
||||
"address": "0x58F132FBB86E21545A4Bace3C19f1C05d86d7A22",
|
||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
},
|
||||
"coverage": {
|
||||
"address": "0x58F132FBB86E21545A4Bace3C19f1C05d86d7A22",
|
||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
}
|
||||
},
|
||||
|
@ -417,7 +554,10 @@
|
|||
"address": "0x2cfcA5785261fbC88EFFDd46fCFc04c22525F9e4"
|
||||
},
|
||||
"localhost": {
|
||||
"address": "0x9305d862ee95a899b83906Cd9CB666aC269E5f66"
|
||||
"address": "0x2cfcA5785261fbC88EFFDd46fCFc04c22525F9e4"
|
||||
},
|
||||
"coverage": {
|
||||
"address": "0x2cfcA5785261fbC88EFFDd46fCFc04c22525F9e4"
|
||||
}
|
||||
},
|
||||
"StableDebtToken": {
|
||||
|
@ -426,7 +566,11 @@
|
|||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
},
|
||||
"localhost": {
|
||||
"address": "0x02BB514187B830d6A2111197cd7D8cb60650B970",
|
||||
"address": "0xB660Fdd109a95718cB9d20E3A89EE6cE342aDcB6",
|
||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
},
|
||||
"coverage": {
|
||||
"address": "0xB660Fdd109a95718cB9d20E3A89EE6cE342aDcB6",
|
||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
}
|
||||
},
|
||||
|
@ -436,18 +580,26 @@
|
|||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
},
|
||||
"localhost": {
|
||||
"address": "0x6774Ce86Abf5EBB22E9F45b5f55daCbB4170aD7f",
|
||||
"address": "0x830bceA96E56DBC1F8578f75fBaC0AF16B32A07d",
|
||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
},
|
||||
"coverage": {
|
||||
"address": "0x830bceA96E56DBC1F8578f75fBaC0AF16B32A07d",
|
||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
}
|
||||
},
|
||||
"AToken": {
|
||||
"localhost": {
|
||||
"address": "0x007C1a44e85bDa8F562F916685A9DC8BdC6542bF",
|
||||
"address": "0xA0AB1cB92A4AF81f84dCd258155B5c25D247b54E",
|
||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
},
|
||||
"buidlerevm": {
|
||||
"address": "0xA0AB1cB92A4AF81f84dCd258155B5c25D247b54E",
|
||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
},
|
||||
"coverage": {
|
||||
"address": "0xA0AB1cB92A4AF81f84dCd258155B5c25D247b54E",
|
||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
}
|
||||
},
|
||||
"MockAToken": {
|
||||
|
@ -456,7 +608,11 @@
|
|||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
},
|
||||
"localhost": {
|
||||
"address": "0xFBdF1E93D0D88145e3CcA63bf8d513F83FB0903b",
|
||||
"address": "0xEcb928A3c079a1696Aa5244779eEc3dE1717fACd",
|
||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
},
|
||||
"coverage": {
|
||||
"address": "0x392E5355a0e88Bd394F717227c752670fb3a8020",
|
||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
}
|
||||
},
|
||||
|
@ -466,7 +622,11 @@
|
|||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
},
|
||||
"localhost": {
|
||||
"address": "0xEcb928A3c079a1696Aa5244779eEc3dE1717fACd",
|
||||
"address": "0xf784709d2317D872237C4bC22f867d1BAe2913AB",
|
||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
},
|
||||
"coverage": {
|
||||
"address": "0xf784709d2317D872237C4bC22f867d1BAe2913AB",
|
||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
}
|
||||
},
|
||||
|
@ -476,7 +636,11 @@
|
|||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
},
|
||||
"localhost": {
|
||||
"address": "0xE45fF4A0A8D0E9734C73874c034E03594E15ba28",
|
||||
"address": "0xDFbeeed692AA81E7f86E72F7ACbEA2A1C4d63544",
|
||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
},
|
||||
"coverage": {
|
||||
"address": "0x3b050AFb4ac4ACE646b31fF3639C1CD43aC31460",
|
||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
}
|
||||
},
|
||||
|
@ -486,13 +650,23 @@
|
|||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
},
|
||||
"localhost": {
|
||||
"address": "0x5cCC6Abc4c9F7262B9485797a848Ec6CC28A11dF",
|
||||
"address": "0x5191aA68c7dB195181Dd2441dBE23A48EA24b040",
|
||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
},
|
||||
"coverage": {
|
||||
"address": "0xEBAB67ee3ef604D5c250A53b4b8fcbBC6ec3007C",
|
||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||
}
|
||||
},
|
||||
"MockSwapAdapter": {
|
||||
"buidlerevm": {
|
||||
"address": "0xBEF0d4b9c089a5883741fC14cbA352055f35DDA2"
|
||||
},
|
||||
"coverage": {
|
||||
"address": "0xBEF0d4b9c089a5883741fC14cbA352055f35DDA2"
|
||||
},
|
||||
"localhost": {
|
||||
"address": "0xBEF0d4b9c089a5883741fC14cbA352055f35DDA2"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -31,6 +31,7 @@ import BigNumber from 'bignumber.js';
|
|||
import {Ierc20Detailed} from '../types/Ierc20Detailed';
|
||||
import {StableDebtToken} from '../types/StableDebtToken';
|
||||
import {VariableDebtToken} from '../types/VariableDebtToken';
|
||||
import { ZERO_ADDRESS } from './constants';
|
||||
import {MockSwapAdapter} from '../types/MockSwapAdapter';
|
||||
import {signTypedData_v4, TypedData} from 'eth-sig-util';
|
||||
import {fromRpcSig, ECDSASignature} from 'ethereumjs-util';
|
||||
|
@ -290,13 +291,15 @@ export const deployVariableDebtToken = async ([
|
|||
export const deployGenericAToken = async ([
|
||||
poolAddress,
|
||||
underlyingAssetAddress,
|
||||
reserveTreasuryAddress,
|
||||
name,
|
||||
symbol,
|
||||
incentivesController,
|
||||
]: [tEthereumAddress, tEthereumAddress, string, string, tEthereumAddress]) => {
|
||||
]: [tEthereumAddress, tEthereumAddress, tEthereumAddress, string, string, tEthereumAddress]) => {
|
||||
const token = await deployContract<AToken>(eContractid.AToken, [
|
||||
poolAddress,
|
||||
underlyingAssetAddress,
|
||||
reserveTreasuryAddress,
|
||||
name,
|
||||
symbol,
|
||||
incentivesController,
|
||||
|
@ -353,6 +356,21 @@ export const getAToken = async (address?: tEthereumAddress) => {
|
|||
);
|
||||
};
|
||||
|
||||
export const getStableDebtToken = async (address?: tEthereumAddress) => {
|
||||
return await getContract<AToken>(
|
||||
eContractid.StableDebtToken,
|
||||
address || (await getDb().get(`${eContractid.StableDebtToken}.${BRE.network.name}`).value()).address
|
||||
);
|
||||
};
|
||||
|
||||
export const getVariableDebtToken = async (address?: tEthereumAddress) => {
|
||||
return await getContract<AToken>(
|
||||
eContractid.VariableDebtToken,
|
||||
address || (await getDb().get(`${eContractid.VariableDebtToken}.${BRE.network.name}`).value()).address
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
export const getMintableErc20 = async (address: tEthereumAddress) => {
|
||||
return await getContract<MintableErc20>(
|
||||
eContractid.MintableERC20,
|
||||
|
|
|
@ -245,6 +245,7 @@ const initReserves = async (
|
|||
const aToken = await deployGenericAToken([
|
||||
lendingPool.address,
|
||||
tokenAddress,
|
||||
ZERO_ADDRESS,
|
||||
`Aave interest bearing ${assetSymbol === 'WETH' ? 'ETH' : assetSymbol}`,
|
||||
`a${assetSymbol === 'WETH' ? 'ETH' : assetSymbol}`,
|
||||
incentivesController,
|
||||
|
|
|
@ -180,6 +180,23 @@ makeSuite('LendingPoolConfigurator', (testEnv: TestEnv) => {
|
|||
).to.be.revertedWith(CALLER_NOT_AAVE_ADMIN);
|
||||
});
|
||||
|
||||
|
||||
it('Changes the reserve factor of the reserve', async () => {
|
||||
const {configurator, pool, weth} = testEnv;
|
||||
await configurator.setReserveFactor(weth.address, '1000');
|
||||
const {reserveFactor} = await pool.getReserveConfigurationData(weth.address);
|
||||
expect(reserveFactor.toString()).to.be.bignumber.equal('1000', 'Invalid reserve factor');
|
||||
});
|
||||
|
||||
it('Check the onlyLendingPoolManager on setReserveFactor', async () => {
|
||||
const {configurator, users, weth} = testEnv;
|
||||
await expect(
|
||||
configurator.connect(users[2].signer).setReserveFactor(weth.address, '2000'),
|
||||
CALLER_NOT_AAVE_ADMIN
|
||||
).to.be.revertedWith(CALLER_NOT_AAVE_ADMIN);
|
||||
});
|
||||
|
||||
|
||||
it('Changes liquidation threshold of the reserve', async () => {
|
||||
const {configurator, pool, weth} = testEnv;
|
||||
await configurator.setLiquidationThreshold(weth.address, '75');
|
||||
|
|
|
@ -125,7 +125,9 @@ makeSuite('LendingPool. repayWithCollateral() with liquidator', (testEnv: TestEn
|
|||
).minus(usdcUserDataBefore.currentVariableDebt);
|
||||
|
||||
const expectedStableDebtIncrease = calcExpectedStableDebtTokenBalance(
|
||||
usdcUserDataBefore,
|
||||
usdcUserDataBefore.principalStableDebt,
|
||||
usdcUserDataBefore.stableBorrowRate,
|
||||
usdcUserDataBefore.stableRateLastUpdated,
|
||||
new BigNumber(repayWithCollateralTimestamp)
|
||||
).minus(usdcUserDataBefore.currentStableDebt);
|
||||
|
||||
|
@ -233,7 +235,7 @@ makeSuite('LendingPool. repayWithCollateral() with liquidator', (testEnv: TestEn
|
|||
userData: usdcUserDataBefore,
|
||||
} = await getContractsData(usdc.address, user.address, testEnv);
|
||||
|
||||
const amountToRepay = usdcReserveDataBefore.totalBorrowsVariable.dividedBy(2).toFixed(0);
|
||||
const amountToRepay = usdcReserveDataBefore.totalVariableDebt.dividedBy(2).toFixed(0);
|
||||
|
||||
await mockSwapAdapter.setAmountToReturn(amountToRepay);
|
||||
await waitForTx(
|
||||
|
@ -295,7 +297,7 @@ makeSuite('LendingPool. repayWithCollateral() with liquidator', (testEnv: TestEn
|
|||
'INVALID_DEBT_POSITION'
|
||||
);
|
||||
|
||||
expect(wethUserDataAfter.currentATokenBalance).to.be.bignumber.equal(
|
||||
expect(wethUserDataAfter.currentATokenBalance).to.be.bignumber.almostEqual(
|
||||
new BigNumber(wethUserDataBefore.currentATokenBalance).minus(
|
||||
expectedCollateralLiquidated.toString()
|
||||
),
|
||||
|
@ -368,7 +370,7 @@ makeSuite('LendingPool. repayWithCollateral() with liquidator', (testEnv: TestEn
|
|||
userData: usdcUserDataBefore,
|
||||
} = await getContractsData(usdc.address, user.address, testEnv);
|
||||
|
||||
const amountToRepay = usdcReserveDataBefore.totalBorrowsVariable.toFixed(0);
|
||||
const amountToRepay = usdcReserveDataBefore.totalVariableDebt.toFixed(0);
|
||||
|
||||
await mockSwapAdapter.setAmountToReturn(amountToRepay);
|
||||
await waitForTx(
|
||||
|
@ -486,7 +488,7 @@ makeSuite('LendingPool. repayWithCollateral() with liquidator', (testEnv: TestEn
|
|||
testEnv
|
||||
);
|
||||
|
||||
const amountToRepay = daiReserveDataBefore.totalBorrowsVariable.toString();
|
||||
const amountToRepay = daiReserveDataBefore.totalVariableDebt.toString();
|
||||
|
||||
await waitForTx(await mockSwapAdapter.setTryReentrancy(true));
|
||||
|
||||
|
@ -522,7 +524,7 @@ makeSuite('LendingPool. repayWithCollateral() with liquidator', (testEnv: TestEn
|
|||
);
|
||||
|
||||
// First half
|
||||
const amountToRepay = daiReserveDataBefore.totalBorrowsVariable.dividedBy(2).toString();
|
||||
const amountToRepay = daiReserveDataBefore.totalVariableDebt.dividedBy(2).toString();
|
||||
|
||||
await mockSwapAdapter.setAmountToReturn(amountToRepay);
|
||||
await expect(
|
||||
|
@ -568,7 +570,7 @@ makeSuite('LendingPool. repayWithCollateral() with liquidator', (testEnv: TestEn
|
|||
);
|
||||
|
||||
// First half
|
||||
const amountToRepay = daiReserveDataBefore.totalBorrowsVariable.multipliedBy(0.6).toString();
|
||||
const amountToRepay = daiReserveDataBefore.totalVariableDebt.multipliedBy(0.6).toFixed(0).toString();
|
||||
|
||||
await mockSwapAdapter.setAmountToReturn(amountToRepay);
|
||||
await waitForTx(
|
||||
|
@ -654,7 +656,7 @@ makeSuite('LendingPool. repayWithCollateral() with liquidator', (testEnv: TestEn
|
|||
|
||||
await increaseTime(1000);
|
||||
// Repay the remaining DAI
|
||||
const amountToRepay = daiReserveDataBefore.totalBorrowsVariable.toString();
|
||||
const amountToRepay = daiReserveDataBefore.totalVariableDebt.toString();
|
||||
|
||||
await mockSwapAdapter.setAmountToReturn(amountToRepay);
|
||||
const receipt = await waitForTx(
|
||||
|
@ -816,7 +818,7 @@ makeSuite('LendingPool. repayWithCollateral() with liquidator', (testEnv: TestEn
|
|||
new BigNumber(repayWithCollateralTimestamp)
|
||||
).minus(usdcUserDataBefore.currentVariableDebt);
|
||||
|
||||
expect(usdcUserDataAfter.currentVariableDebt).to.be.bignumber.equal(
|
||||
expect(usdcUserDataAfter.currentVariableDebt).to.be.bignumber.almostEqual(
|
||||
new BigNumber(usdcUserDataBefore.currentVariableDebt)
|
||||
.minus(expectedDebtCovered.toString())
|
||||
.plus(expectedVariableDebtIncrease),
|
||||
|
|
|
@ -62,8 +62,8 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => {
|
|||
const currentLiquidityIndex = reserveData.liquidityIndex;
|
||||
|
||||
const totalLiquidity = new BigNumber(reserveData.availableLiquidity.toString())
|
||||
.plus(reserveData.totalBorrowsStable.toString())
|
||||
.plus(reserveData.totalBorrowsVariable.toString());
|
||||
.plus(reserveData.totalStableDebt.toString())
|
||||
.plus(reserveData.totalVariableDebt.toString());
|
||||
|
||||
expect(totalLiquidity.toString()).to.be.equal('1000720000000000000');
|
||||
expect(currentLiquidityRate.toString()).to.be.equal('0');
|
||||
|
@ -89,8 +89,8 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => {
|
|||
const currentLiquidityIndex = reserveData.liquidityIndex;
|
||||
|
||||
const totalLiquidity = new BigNumber(reserveData.availableLiquidity.toString())
|
||||
.plus(reserveData.totalBorrowsStable.toString())
|
||||
.plus(reserveData.totalBorrowsVariable.toString());
|
||||
.plus(reserveData.totalStableDebt.toString())
|
||||
.plus(reserveData.totalVariableDebt.toString());
|
||||
|
||||
expect(totalLiquidity.toString()).to.be.equal('1001620648000000000');
|
||||
expect(currentLiqudityRate.toString()).to.be.equal('0');
|
||||
|
@ -244,8 +244,8 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => {
|
|||
const userData = await pool.getUserReserveData(usdc.address, depositor.address);
|
||||
|
||||
const totalLiquidity = reserveData.availableLiquidity
|
||||
.add(reserveData.totalBorrowsStable)
|
||||
.add(reserveData.totalBorrowsVariable)
|
||||
.add(reserveData.totalStableDebt)
|
||||
.add(reserveData.totalVariableDebt)
|
||||
.toString();
|
||||
const currentLiqudityRate = reserveData.liquidityRate.toString();
|
||||
const currentLiquidityIndex = reserveData.liquidityIndex.toString();
|
||||
|
|
|
@ -32,6 +32,7 @@ import {waitForTx} from '../__setup.spec';
|
|||
import {ContractReceipt} from 'ethers';
|
||||
import {AToken} from '../../types/AToken';
|
||||
import {RateMode, tEthereumAddress} from '../../helpers/types';
|
||||
import { time } from 'console';
|
||||
|
||||
const {expect} = chai;
|
||||
|
||||
|
@ -48,7 +49,8 @@ const almostEqualOrEqual = function (
|
|||
key === 'marketStableRate' ||
|
||||
key === 'symbol' ||
|
||||
key === 'aTokenAddress' ||
|
||||
key === 'decimals'
|
||||
key === 'decimals' ||
|
||||
key === 'totalStableDebtLastUpdated'
|
||||
) {
|
||||
// skipping consistency check on accessory data
|
||||
return;
|
||||
|
@ -262,10 +264,6 @@ export const withdraw = async (
|
|||
txCost
|
||||
);
|
||||
|
||||
const actualAmountWithdrawn = userDataBefore.currentATokenBalance.minus(
|
||||
expectedUserData.currentATokenBalance
|
||||
);
|
||||
|
||||
expectEqual(reserveDataAfter, expectedReserveData);
|
||||
expectEqual(userDataAfter, expectedUserData);
|
||||
|
||||
|
@ -371,8 +369,7 @@ export const borrow = async (
|
|||
expectedReserveData,
|
||||
userDataBefore,
|
||||
txTimestamp,
|
||||
timestamp,
|
||||
txCost
|
||||
timestamp
|
||||
);
|
||||
|
||||
expectEqual(reserveDataAfter, expectedReserveData);
|
||||
|
@ -475,8 +472,7 @@ export const repay = async (
|
|||
user.address,
|
||||
onBehalfOf.address,
|
||||
txTimestamp,
|
||||
timestamp,
|
||||
txCost
|
||||
timestamp
|
||||
);
|
||||
|
||||
expectEqual(reserveDataAfter, expectedReserveData);
|
||||
|
@ -741,9 +737,12 @@ export const getContractsData = async (
|
|||
sender?: string
|
||||
) => {
|
||||
const {pool} = testEnv;
|
||||
const reserveData = await getReserveData(pool, reserve);
|
||||
const userData = await getUserData(pool, reserve, user, sender || user);
|
||||
const timestamp = await timeLatest();
|
||||
|
||||
const [userData, reserveData, timestamp] = await Promise.all([
|
||||
getUserData(pool, reserve, user, sender || user),
|
||||
getReserveData(pool, reserve),
|
||||
timeLatest(),
|
||||
]);
|
||||
|
||||
return {
|
||||
reserveData,
|
||||
|
|
|
@ -626,6 +626,17 @@
|
|||
},
|
||||
"expected": "success"
|
||||
},
|
||||
{
|
||||
"name": "repay",
|
||||
"args": {
|
||||
"reserve": "DAI",
|
||||
"amount": "-1",
|
||||
"user": "1",
|
||||
"onBehalfOf": "1",
|
||||
"borrowRateMode": "variable"
|
||||
},
|
||||
"expected": "success"
|
||||
},
|
||||
{
|
||||
"name": "withdraw",
|
||||
"args": {
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -4,9 +4,8 @@ import {
|
|||
getLendingRateOracle,
|
||||
getIErc20Detailed,
|
||||
getMintableErc20,
|
||||
getAToken,
|
||||
getAToken, getStableDebtToken, getVariableDebtToken
|
||||
} from '../../../helpers/contracts-helpers';
|
||||
import {ZERO_ADDRESS} from '../../../helpers/constants';
|
||||
import {tEthereumAddress} from '../../../helpers/types';
|
||||
import BigNumber from 'bignumber.js';
|
||||
import {getDb, BRE} from '../../../helpers/misc-utils';
|
||||
|
@ -15,41 +14,54 @@ export const getReserveData = async (
|
|||
pool: LendingPool,
|
||||
reserve: tEthereumAddress
|
||||
): Promise<ReserveData> => {
|
||||
const data = await pool.getReserveData(reserve);
|
||||
const tokenAddresses = await pool.getReserveTokensAddresses(reserve);
|
||||
const rateOracle = await getLendingRateOracle();
|
||||
const [reserveData, tokenAddresses, rateOracle, token] = await Promise.all([
|
||||
pool.getReserveData(reserve),
|
||||
pool.getReserveTokensAddresses(reserve),
|
||||
getLendingRateOracle(),
|
||||
getIErc20Detailed(reserve),
|
||||
]);
|
||||
|
||||
const stableDebtToken = await getStableDebtToken(tokenAddresses.stableDebtTokenAddress);
|
||||
const variableDebtToken = await getVariableDebtToken(tokenAddresses.variableDebtTokenAddress);
|
||||
|
||||
const [principalStableDebt] = await stableDebtToken.getSupplyData();
|
||||
const totalStableDebtLastUpdated = await stableDebtToken.getTotalSupplyLastUpdated();
|
||||
|
||||
|
||||
const scaledVariableDebt = await variableDebtToken.scaledTotalSupply();
|
||||
|
||||
const rate = (await rateOracle.getMarketBorrowRate(reserve)).toString();
|
||||
|
||||
const token = await getIErc20Detailed(reserve);
|
||||
const symbol = await token.symbol();
|
||||
const decimals = new BigNumber(await token.decimals());
|
||||
|
||||
const totalLiquidity = new BigNumber(data.availableLiquidity.toString())
|
||||
.plus(data.totalBorrowsStable.toString())
|
||||
.plus(data.totalBorrowsVariable.toString());
|
||||
const totalLiquidity = new BigNumber(reserveData.availableLiquidity.toString())
|
||||
.plus(reserveData.totalStableDebt.toString())
|
||||
.plus(reserveData.totalVariableDebt.toString());
|
||||
|
||||
const utilizationRate = new BigNumber(
|
||||
totalLiquidity.eq(0)
|
||||
? 0
|
||||
: new BigNumber(data.totalBorrowsStable.toString())
|
||||
.plus(data.totalBorrowsVariable.toString())
|
||||
: new BigNumber(reserveData.totalStableDebt.toString())
|
||||
.plus(reserveData.totalVariableDebt.toString())
|
||||
.rayDiv(totalLiquidity)
|
||||
);
|
||||
|
||||
return {
|
||||
totalLiquidity,
|
||||
utilizationRate,
|
||||
availableLiquidity: new BigNumber(data.availableLiquidity.toString()),
|
||||
totalBorrowsStable: new BigNumber(data.totalBorrowsStable.toString()),
|
||||
totalBorrowsVariable: new BigNumber(data.totalBorrowsVariable.toString()),
|
||||
liquidityRate: new BigNumber(data.liquidityRate.toString()),
|
||||
variableBorrowRate: new BigNumber(data.variableBorrowRate.toString()),
|
||||
stableBorrowRate: new BigNumber(data.stableBorrowRate.toString()),
|
||||
averageStableBorrowRate: new BigNumber(data.averageStableBorrowRate.toString()),
|
||||
liquidityIndex: new BigNumber(data.liquidityIndex.toString()),
|
||||
variableBorrowIndex: new BigNumber(data.variableBorrowIndex.toString()),
|
||||
lastUpdateTimestamp: new BigNumber(data.lastUpdateTimestamp),
|
||||
availableLiquidity: new BigNumber(reserveData.availableLiquidity.toString()),
|
||||
totalStableDebt: new BigNumber(reserveData.totalStableDebt.toString()),
|
||||
totalVariableDebt: new BigNumber(reserveData.totalVariableDebt.toString()),
|
||||
liquidityRate: new BigNumber(reserveData.liquidityRate.toString()),
|
||||
variableBorrowRate: new BigNumber(reserveData.variableBorrowRate.toString()),
|
||||
stableBorrowRate: new BigNumber(reserveData.stableBorrowRate.toString()),
|
||||
averageStableBorrowRate: new BigNumber(reserveData.averageStableBorrowRate.toString()),
|
||||
liquidityIndex: new BigNumber(reserveData.liquidityIndex.toString()),
|
||||
variableBorrowIndex: new BigNumber(reserveData.variableBorrowIndex.toString()),
|
||||
lastUpdateTimestamp: new BigNumber(reserveData.lastUpdateTimestamp),
|
||||
totalStableDebtLastUpdated: new BigNumber(totalStableDebtLastUpdated),
|
||||
principalStableDebt: new BigNumber(principalStableDebt.toString()),
|
||||
scaledVariableDebt: new BigNumber(scaledVariableDebt.toString()),
|
||||
address: reserve,
|
||||
aTokenAddress: tokenAddresses.aTokenAddress,
|
||||
symbol,
|
||||
|
@ -69,7 +81,6 @@ export const getUserData = async (
|
|||
getATokenUserData(reserve, user, pool),
|
||||
]);
|
||||
|
||||
|
||||
const token = await getMintableErc20(reserve);
|
||||
const walletBalance = new BigNumber((await token.balanceOf(sender || user)).toString());
|
||||
|
||||
|
@ -79,8 +90,7 @@ export const getUserData = async (
|
|||
currentStableDebt: new BigNumber(userData.currentStableDebt.toString()),
|
||||
currentVariableDebt: new BigNumber(userData.currentVariableDebt.toString()),
|
||||
principalStableDebt: new BigNumber(userData.principalStableDebt.toString()),
|
||||
principalVariableDebt: new BigNumber(userData.principalVariableDebt.toString()),
|
||||
variableBorrowIndex: new BigNumber(userData.variableBorrowIndex.toString()),
|
||||
scaledVariableDebt: new BigNumber(userData.scaledVariableDebt.toString()),
|
||||
stableBorrowRate: new BigNumber(userData.stableBorrowRate.toString()),
|
||||
liquidityRate: new BigNumber(userData.liquidityRate.toString()),
|
||||
usageAsCollateralEnabled: userData.usageAsCollateralEnabled,
|
||||
|
@ -107,5 +117,4 @@ const getATokenUserData = async (reserve: string, user: string, pool: LendingPoo
|
|||
|
||||
const scaledBalance = await aToken.scaledBalanceOf(user);
|
||||
return scaledBalance.toString();
|
||||
|
||||
};
|
||||
|
|
|
@ -6,8 +6,7 @@ export interface UserReserveData {
|
|||
currentStableDebt: BigNumber;
|
||||
currentVariableDebt: BigNumber;
|
||||
principalStableDebt: BigNumber;
|
||||
principalVariableDebt: BigNumber;
|
||||
variableBorrowIndex: BigNumber;
|
||||
scaledVariableDebt: BigNumber;
|
||||
liquidityRate: BigNumber;
|
||||
stableBorrowRate: BigNumber;
|
||||
stableRateLastUpdated: BigNumber;
|
||||
|
@ -22,8 +21,10 @@ export interface ReserveData {
|
|||
decimals: BigNumber;
|
||||
totalLiquidity: BigNumber;
|
||||
availableLiquidity: BigNumber;
|
||||
totalBorrowsStable: BigNumber;
|
||||
totalBorrowsVariable: BigNumber;
|
||||
totalStableDebt: BigNumber;
|
||||
totalVariableDebt: BigNumber;
|
||||
principalStableDebt: BigNumber,
|
||||
scaledVariableDebt: BigNumber,
|
||||
averageStableBorrowRate: BigNumber;
|
||||
variableBorrowRate: BigNumber;
|
||||
stableBorrowRate: BigNumber;
|
||||
|
@ -33,6 +34,7 @@ export interface ReserveData {
|
|||
aTokenAddress: string;
|
||||
marketStableRate: BigNumber;
|
||||
lastUpdateTimestamp: BigNumber;
|
||||
totalStableDebtLastUpdated: BigNumber;
|
||||
liquidityRate: BigNumber;
|
||||
[key: string]: BigNumber | string;
|
||||
}
|
||||
|
|
|
@ -175,7 +175,9 @@ makeSuite('LendingPool liquidation - liquidator receiving the underlying asset',
|
|||
);
|
||||
|
||||
const stableDebtBeforeTx = calcExpectedStableDebtTokenBalance(
|
||||
userReserveDataBefore,
|
||||
userReserveDataBefore.principalStableDebt,
|
||||
userReserveDataBefore.stableBorrowRate,
|
||||
userReserveDataBefore.stableRateLastUpdated,
|
||||
txTimestamp
|
||||
);
|
||||
|
||||
|
|
|
@ -420,7 +420,9 @@ makeSuite('LendingPool. repayWithCollateral()', (testEnv: TestEnv) => {
|
|||
).minus(usdcUserDataBefore.currentVariableDebt);
|
||||
|
||||
const expectedStableDebtIncrease = calcExpectedStableDebtTokenBalance(
|
||||
usdcUserDataBefore,
|
||||
usdcUserDataBefore.principalStableDebt,
|
||||
usdcUserDataBefore.stableBorrowRate,
|
||||
usdcUserDataBefore.stableRateLastUpdated,
|
||||
new BigNumber(repayWithCollateralTimestamp)
|
||||
).minus(usdcUserDataBefore.currentStableDebt);
|
||||
|
||||
|
@ -556,14 +558,14 @@ makeSuite('LendingPool. repayWithCollateral()', (testEnv: TestEnv) => {
|
|||
new BigNumber(repayWithCollateralTimestamp)
|
||||
).minus(daiUserDataBefore.currentVariableDebt);
|
||||
|
||||
expect(daiUserDataAfter.currentVariableDebt).to.be.bignumber.equal(
|
||||
expect(daiUserDataAfter.currentVariableDebt).to.be.bignumber.almostEqual(
|
||||
new BigNumber(daiUserDataBefore.currentVariableDebt)
|
||||
.minus(expectedDebtCovered.toString())
|
||||
.plus(expectedVariableDebtIncrease),
|
||||
'INVALID_VARIABLE_DEBT_POSITION'
|
||||
);
|
||||
|
||||
expect(wethUserDataAfter.currentATokenBalance).to.be.bignumber.equal(0);
|
||||
expect(wethUserDataAfter.currentATokenBalance).to.be.bignumber.almostEqual(0);
|
||||
|
||||
expect(wethUserDataAfter.usageAsCollateralEnabled).to.be.false;
|
||||
});
|
||||
|
|
|
@ -23,9 +23,10 @@ makeSuite('Upgradeability', (testEnv: TestEnv) => {
|
|||
const aTokenInstance = await deployContract<MockAToken>(eContractid.MockAToken, [
|
||||
pool.address,
|
||||
dai.address,
|
||||
ZERO_ADDRESS,
|
||||
'Aave Interest bearing DAI updated',
|
||||
'aDAI',
|
||||
ZERO_ADDRESS,
|
||||
ZERO_ADDRESS
|
||||
]);
|
||||
|
||||
const stableDebtTokenInstance = await deployContract<MockStableDebtToken>(
|
||||
|
|
|
@ -18,7 +18,7 @@ makeSuite('Variable debt token tests', (testEnv: TestEnv) => {
|
|||
daiVariableDebtTokenAddress
|
||||
);
|
||||
|
||||
await expect(variableDebtContract.mint(deployer.address, '1')).to.be.revertedWith(
|
||||
await expect(variableDebtContract.mint(deployer.address, '1', '1')).to.be.revertedWith(
|
||||
CALLER_MUST_BE_LENDING_POOL
|
||||
);
|
||||
});
|
||||
|
@ -34,7 +34,7 @@ makeSuite('Variable debt token tests', (testEnv: TestEnv) => {
|
|||
daiVariableDebtTokenAddress
|
||||
);
|
||||
|
||||
await expect(variableDebtContract.burn(deployer.address, '1')).to.be.revertedWith(
|
||||
await expect(variableDebtContract.burn(deployer.address, '1', '1')).to.be.revertedWith(
|
||||
CALLER_MUST_BE_LENDING_POOL
|
||||
);
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue
Block a user