Merge branch 'master' into fix/45

This commit is contained in:
The3D 2020-09-21 20:19:28 +02:00
commit 75579e5d28
37 changed files with 1425 additions and 899 deletions

View File

@ -10,6 +10,7 @@ usePlugin('solidity-coverage');
usePlugin('@nomiclabs/buidler-waffle'); usePlugin('@nomiclabs/buidler-waffle');
usePlugin('@nomiclabs/buidler-etherscan'); usePlugin('@nomiclabs/buidler-etherscan');
//usePlugin('buidler-gas-reporter'); //usePlugin('buidler-gas-reporter');
const DEFAULT_BLOCK_GAS_LIMIT = 10000000; const DEFAULT_BLOCK_GAS_LIMIT = 10000000;
const DEFAULT_GAS_PRICE = 10; const DEFAULT_GAS_PRICE = 10;
const HARDFORK = 'istanbul'; const HARDFORK = 'istanbul';

View File

@ -327,6 +327,7 @@ interface ILendingPool {
uint256 ltv, uint256 ltv,
uint256 liquidationThreshold, uint256 liquidationThreshold,
uint256 liquidationBonus, uint256 liquidationBonus,
uint256 reserveFactor,
address interestRateStrategyAddress, address interestRateStrategyAddress,
bool usageAsCollateralEnabled, bool usageAsCollateralEnabled,
bool borrowingEnabled, bool borrowingEnabled,
@ -349,8 +350,8 @@ interface ILendingPool {
view view
returns ( returns (
uint256 availableLiquidity, uint256 availableLiquidity,
uint256 totalBorrowsStable, uint256 totalStableDebt,
uint256 totalBorrowsVariable, uint256 totalVariableDebt,
uint256 liquidityRate, uint256 liquidityRate,
uint256 variableBorrowRate, uint256 variableBorrowRate,
uint256 stableBorrowRate, uint256 stableBorrowRate,
@ -366,7 +367,6 @@ interface ILendingPool {
returns ( returns (
uint256 totalCollateralETH, uint256 totalCollateralETH,
uint256 totalBorrowsETH, uint256 totalBorrowsETH,
uint256 availableBorrowsETH,
uint256 currentLiquidationThreshold, uint256 currentLiquidationThreshold,
uint256 ltv, uint256 ltv,
uint256 healthFactor uint256 healthFactor
@ -380,10 +380,9 @@ interface ILendingPool {
uint256 currentStableDebt, uint256 currentStableDebt,
uint256 currentVariableDebt, uint256 currentVariableDebt,
uint256 principalStableDebt, uint256 principalStableDebt,
uint256 principalVariableDebt, uint256 scaledVariableDebt,
uint256 stableBorrowRate, uint256 stableBorrowRate,
uint256 liquidityRate, uint256 liquidityRate,
uint256 variableBorrowIndex,
uint40 stableRateLastUpdated, uint40 stableRateLastUpdated,
bool usageAsCollateralEnabled bool usageAsCollateralEnabled
); );

View File

@ -25,9 +25,10 @@ interface IReserveInterestRateStrategy {
function calculateInterestRates( function calculateInterestRates(
address reserve, address reserve,
uint256 utilizationRate, uint256 utilizationRate,
uint256 totalBorrowsStable, uint256 totalStableDebt,
uint256 totalBorrowsVariable, uint256 totalVariableDebt,
uint256 averageStableBorrowRate uint256 averageStableBorrowRate,
uint256 reserveFactor
) )
external external
view view

View File

@ -4,6 +4,7 @@ pragma solidity ^0.6.8;
import {SafeMath} from '@openzeppelin/contracts/math/SafeMath.sol'; import {SafeMath} from '@openzeppelin/contracts/math/SafeMath.sol';
import {IReserveInterestRateStrategy} from '../interfaces/IReserveInterestRateStrategy.sol'; import {IReserveInterestRateStrategy} from '../interfaces/IReserveInterestRateStrategy.sol';
import {WadRayMath} from '../libraries/math/WadRayMath.sol'; import {WadRayMath} from '../libraries/math/WadRayMath.sol';
import {PercentageMath} from '../libraries/math/PercentageMath.sol';
import {LendingPoolAddressesProvider} from '../configuration/LendingPoolAddressesProvider.sol'; import {LendingPoolAddressesProvider} from '../configuration/LendingPoolAddressesProvider.sol';
import {ILendingRateOracle} from '../interfaces/ILendingRateOracle.sol'; import {ILendingRateOracle} from '../interfaces/ILendingRateOracle.sol';
@ -17,7 +18,7 @@ import {ILendingRateOracle} from '../interfaces/ILendingRateOracle.sol';
contract DefaultReserveInterestRateStrategy is IReserveInterestRateStrategy { contract DefaultReserveInterestRateStrategy is IReserveInterestRateStrategy {
using WadRayMath for uint256; using WadRayMath for uint256;
using SafeMath 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 * @dev this constant represents the utilization rate at which the pool aims to obtain most competitive borrow rates
* expressed in ray * 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 //slope of the stable interest curve when utilization rate > OPTIMAL_UTILIZATION_RATE. Expressed in ray
uint256 internal immutable _stableRateSlope2; uint256 internal immutable _stableRateSlope2;
constructor( constructor(
LendingPoolAddressesProvider provider, LendingPoolAddressesProvider provider,
uint256 baseVariableBorrowRate, uint256 baseVariableBorrowRate,
@ -93,13 +95,23 @@ contract DefaultReserveInterestRateStrategy is IReserveInterestRateStrategy {
return _baseVariableBorrowRate.add(_variableRateSlope1).add(_variableRateSlope2); return _baseVariableBorrowRate.add(_variableRateSlope1).add(_variableRateSlope2);
} }
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. * @dev calculates the interest rates depending on the available liquidity and the total borrowed.
* @param reserve the address of the reserve * @param reserve the address of the reserve
* @param availableLiquidity the liquidity available in the reserve * @param availableLiquidity the liquidity available in the reserve
* @param totalBorrowsStable the total borrowed from the reserve a stable rate * @param totalStableDebt the total borrowed from the reserve a stable rate
* @param totalBorrowsVariable the total borrowed from the reserve at a variable 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 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 currentLiquidityRate the liquidity rate
* @return currentStableBorrowRate stable borrow rate * @return currentStableBorrowRate stable borrow rate
* @return currentVariableBorrowRate variable borrow rate * @return currentVariableBorrowRate variable borrow rate
@ -107,9 +119,10 @@ contract DefaultReserveInterestRateStrategy is IReserveInterestRateStrategy {
function calculateInterestRates( function calculateInterestRates(
address reserve, address reserve,
uint256 availableLiquidity, uint256 availableLiquidity,
uint256 totalBorrowsStable, uint256 totalStableDebt,
uint256 totalBorrowsVariable, uint256 totalVariableDebt,
uint256 averageStableBorrowRate uint256 averageStableBorrowRate,
uint256 reserveFactor
) )
external external
override override
@ -120,16 +133,19 @@ contract DefaultReserveInterestRateStrategy is IReserveInterestRateStrategy {
uint256 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 ? 0
: totalBorrows.rayDiv(availableLiquidity.add(totalBorrows)); : vars.totalBorrows.rayDiv(availableLiquidity.add(vars.totalBorrows));
currentStableBorrowRate = ILendingRateOracle(addressesProvider.getLendingRateOracle()) vars.currentStableBorrowRate = ILendingRateOracle(addressesProvider.getLendingRateOracle())
.getMarketBorrowRate(reserve); .getMarketBorrowRate(reserve);
if (utilizationRate > OPTIMAL_UTILIZATION_RATE) { if (utilizationRate > OPTIMAL_UTILIZATION_RATE) {
@ -137,56 +153,57 @@ contract DefaultReserveInterestRateStrategy is IReserveInterestRateStrategy {
EXCESS_UTILIZATION_RATE EXCESS_UTILIZATION_RATE
); );
currentStableBorrowRate = currentStableBorrowRate.add(_stableRateSlope1).add( vars.currentStableBorrowRate = vars.currentStableBorrowRate.add(_stableRateSlope1).add(
_stableRateSlope2.rayMul(excessUtilizationRateRatio) _stableRateSlope2.rayMul(excessUtilizationRateRatio)
); );
currentVariableBorrowRate = _baseVariableBorrowRate.add(_variableRateSlope1).add( vars.currentVariableBorrowRate = _baseVariableBorrowRate.add(_variableRateSlope1).add(
_variableRateSlope2.rayMul(excessUtilizationRateRatio) _variableRateSlope2.rayMul(excessUtilizationRateRatio)
); );
} else { } else {
currentStableBorrowRate = currentStableBorrowRate.add( vars.currentStableBorrowRate = vars.currentStableBorrowRate.add(
_stableRateSlope1.rayMul(utilizationRate.rayDiv(OPTIMAL_UTILIZATION_RATE)) _stableRateSlope1.rayMul(utilizationRate.rayDiv(OPTIMAL_UTILIZATION_RATE))
); );
currentVariableBorrowRate = _baseVariableBorrowRate.add( vars.currentVariableBorrowRate = _baseVariableBorrowRate.add(
utilizationRate.rayDiv(OPTIMAL_UTILIZATION_RATE).rayMul(_variableRateSlope1) utilizationRate.rayDiv(OPTIMAL_UTILIZATION_RATE).rayMul(_variableRateSlope1)
); );
} }
currentLiquidityRate = _getOverallBorrowRate( vars.currentLiquidityRate = _getOverallBorrowRate(
totalBorrowsStable, totalStableDebt,
totalBorrowsVariable, totalVariableDebt,
currentVariableBorrowRate, vars.currentVariableBorrowRate,
averageStableBorrowRate 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. * @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 totalStableDebt the total borrowed from the reserve a stable rate
* @param totalBorrowsVariable the total borrowed from the reserve at a variable rate * @param totalVariableDebt the total borrowed from the reserve at a variable rate
* @param currentVariableBorrowRate the current variable borrow rate * @param currentVariableBorrowRate the current variable borrow rate
* @param currentAverageStableBorrowRate the weighted average of all the stable rate borrows * @param currentAverageStableBorrowRate the weighted average of all the stable rate borrows
* @return the weighted averaged borrow rate * @return the weighted averaged borrow rate
**/ **/
function _getOverallBorrowRate( function _getOverallBorrowRate(
uint256 totalBorrowsStable, uint256 totalStableDebt,
uint256 totalBorrowsVariable, uint256 totalVariableDebt,
uint256 currentVariableBorrowRate, uint256 currentVariableBorrowRate,
uint256 currentAverageStableBorrowRate uint256 currentAverageStableBorrowRate
) internal pure returns (uint256) { ) internal pure returns (uint256) {
uint256 totalBorrows = totalBorrowsStable.add(totalBorrowsVariable); uint256 totalBorrows = totalStableDebt.add(totalVariableDebt);
if (totalBorrows == 0) return 0; if (totalBorrows == 0) return 0;
uint256 weightedVariableRate = totalBorrowsVariable.wadToRay().rayMul( uint256 weightedVariableRate = totalVariableDebt.wadToRay().rayMul(
currentVariableBorrowRate currentVariableBorrowRate
); );
uint256 weightedStableRate = totalBorrowsStable.wadToRay().rayMul( uint256 weightedStableRate = totalStableDebt.wadToRay().rayMul(
currentAverageStableBorrowRate currentAverageStableBorrowRate
); );

View File

@ -20,6 +20,7 @@ import {ReserveConfiguration} from '../libraries/configuration/ReserveConfigurat
import {UserConfiguration} from '../libraries/configuration/UserConfiguration.sol'; import {UserConfiguration} from '../libraries/configuration/UserConfiguration.sol';
import {IStableDebtToken} from '../tokenization/interfaces/IStableDebtToken.sol'; import {IStableDebtToken} from '../tokenization/interfaces/IStableDebtToken.sol';
import {IVariableDebtToken} from '../tokenization/interfaces/IVariableDebtToken.sol'; import {IVariableDebtToken} from '../tokenization/interfaces/IVariableDebtToken.sol';
import {DebtTokenBase} from '../tokenization/base/DebtTokenBase.sol';
import {IFlashLoanReceiver} from '../flashloan/interfaces/IFlashLoanReceiver.sol'; import {IFlashLoanReceiver} from '../flashloan/interfaces/IFlashLoanReceiver.sol';
import {ISwapAdapter} from '../interfaces/ISwapAdapter.sol'; import {ISwapAdapter} from '../interfaces/ISwapAdapter.sol';
import {LendingPoolCollateralManager} from './LendingPoolCollateralManager.sol'; import {LendingPoolCollateralManager} from './LendingPoolCollateralManager.sol';
@ -46,6 +47,8 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
uint256 public constant REBALANCE_UP_USAGE_RATIO_THRESHOLD = 0.95 * 1e27; //usage ratio of 95% uint256 public constant REBALANCE_UP_USAGE_RATIO_THRESHOLD = 0.95 * 1e27; //usage ratio of 95%
uint256 public constant MAX_STABLE_RATE_BORROW_SIZE_PERCENT = 25; uint256 public constant MAX_STABLE_RATE_BORROW_SIZE_PERCENT = 25;
uint256 public constant FLASHLOAN_PREMIUM_TOTAL = 9; uint256 public constant FLASHLOAN_PREMIUM_TOTAL = 9;
uint256 public constant UINT_MAX_VALUE = uint256(-1);
uint256 public constant LENDINGPOOL_REVISION = 0x2;
/** /**
* @dev only lending pools configurator can use functions affected by this modifier * @dev only lending pools configurator can use functions affected by this modifier
@ -68,8 +71,6 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
require(!_paused, Errors.IS_PAUSED); require(!_paused, Errors.IS_PAUSED);
} }
uint256 public constant LENDINGPOOL_REVISION = 0x2;
function getRevision() internal override pure returns (uint256) { function getRevision() internal override pure returns (uint256) {
return LENDINGPOOL_REVISION; return LENDINGPOOL_REVISION;
} }
@ -103,7 +104,7 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
address aToken = reserve.aTokenAddress; address aToken = reserve.aTokenAddress;
reserve.updateCumulativeIndexesAndTimestamp(); reserve.updateState();
reserve.updateInterestRates(asset, aToken, amount, 0); reserve.updateInterestRates(asset, aToken, amount, 0);
bool isFirstDeposit = IAToken(aToken).balanceOf(onBehalfOf) == 0; bool isFirstDeposit = IAToken(aToken).balanceOf(onBehalfOf) == 0;
@ -150,7 +151,7 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
_addressesProvider.getPriceOracle() _addressesProvider.getPriceOracle()
); );
reserve.updateCumulativeIndexesAndTimestamp(); reserve.updateState();
reserve.updateInterestRates(asset, aToken, 0, amountToWithdraw); reserve.updateInterestRates(asset, aToken, 0, amountToWithdraw);
@ -250,16 +251,7 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
address onBehalfOf address onBehalfOf
) external override { ) external override {
whenNotPaused(); 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]; ReserveLogic.ReserveData storage reserve = _reserves[asset];
(uint256 stableDebt, uint256 variableDebt) = Helpers.getUserCurrentDebt(onBehalfOf, reserve); (uint256 stableDebt, uint256 variableDebt) = Helpers.getUserCurrentDebt(onBehalfOf, reserve);
@ -284,13 +276,17 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
variableDebt variableDebt
); );
reserve.updateCumulativeIndexesAndTimestamp(); reserve.updateState();
//burns an equivalent amount of debt tokens //burns an equivalent amount of debt tokens
if (interestRateMode == ReserveLogic.InterestRateMode.STABLE) { if (interestRateMode == ReserveLogic.InterestRateMode.STABLE) {
IStableDebtToken(reserve.stableDebtTokenAddress).burn(onBehalfOf, paybackAmount); IStableDebtToken(reserve.stableDebtTokenAddress).burn(onBehalfOf, paybackAmount);
} else { } else {
IVariableDebtToken(reserve.variableDebtTokenAddress).burn(onBehalfOf, paybackAmount); IVariableDebtToken(reserve.variableDebtTokenAddress).burn(
onBehalfOf,
paybackAmount,
reserve.variableBorrowIndex
);
} }
address aToken = reserve.aTokenAddress; address aToken = reserve.aTokenAddress;
@ -300,9 +296,9 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
_usersConfig[onBehalfOf].setBorrowing(reserve.id, false); _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);
} }
/** /**
@ -326,15 +322,23 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
interestRateMode interestRateMode
); );
reserve.updateCumulativeIndexesAndTimestamp(); reserve.updateState();
if (interestRateMode == ReserveLogic.InterestRateMode.STABLE) { if (interestRateMode == ReserveLogic.InterestRateMode.STABLE) {
//burn stable rate tokens, mint variable rate tokens //burn stable rate tokens, mint variable rate tokens
IStableDebtToken(reserve.stableDebtTokenAddress).burn(msg.sender, stableDebt); IStableDebtToken(reserve.stableDebtTokenAddress).burn(msg.sender, stableDebt);
IVariableDebtToken(reserve.variableDebtTokenAddress).mint(msg.sender, stableDebt); IVariableDebtToken(reserve.variableDebtTokenAddress).mint(
msg.sender,
stableDebt,
reserve.variableBorrowIndex
);
} else { } else {
//do the opposite //do the opposite
IVariableDebtToken(reserve.variableDebtTokenAddress).burn(msg.sender, variableDebt); IVariableDebtToken(reserve.variableDebtTokenAddress).burn(
msg.sender,
variableDebt,
reserve.variableBorrowIndex
);
IStableDebtToken(reserve.stableDebtTokenAddress).mint( IStableDebtToken(reserve.stableDebtTokenAddress).mint(
msg.sender, msg.sender,
variableDebt, variableDebt,
@ -355,7 +359,9 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
* @param user the address of the user to be rebalanced * @param user the address of the user to be rebalanced
**/ **/
function rebalanceStableBorrowRate(address asset, address user) external override { function rebalanceStableBorrowRate(address asset, address user) external override {
whenNotPaused(); whenNotPaused();
ReserveLogic.ReserveData storage reserve = _reserves[asset]; ReserveLogic.ReserveData storage reserve = _reserves[asset];
IERC20 stableDebtToken = IERC20(reserve.stableDebtTokenAddress); IERC20 stableDebtToken = IERC20(reserve.stableDebtTokenAddress);
@ -369,15 +375,10 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
//if the utilization rate is below 95%, no rebalances are needed //if the utilization rate is below 95%, no rebalances are needed
uint256 totalBorrows = stableDebtToken.totalSupply().add(variableDebtToken.totalSupply()); uint256 totalBorrows = stableDebtToken.totalSupply().add(variableDebtToken.totalSupply());
uint256 availableLiquidity = IERC20(reserve.aTokenAddress).totalSupply(); uint256 availableLiquidity = IERC20(reserve.aTokenAddress).totalSupply();
uint256 utilizationRate = totalBorrows == 0 uint256 usageRatio = totalBorrows == 0
? 0 ? 0
: totalBorrows.rayDiv(availableLiquidity.add(totalBorrows)); : totalBorrows.rayDiv(availableLiquidity.add(totalBorrows));
require(
utilizationRate >= REBALANCE_UP_USAGE_RATIO_THRESHOLD,
Errors.INTEREST_RATE_REBALANCE_CONDITIONS_NOT_MET
);
//if the liquidity rate is below REBALANCE_UP_THRESHOLD of the max variable APR at 95% usage, //if the liquidity rate is below REBALANCE_UP_THRESHOLD of the max variable APR at 95% usage,
//then we allow rebalancing of the stable rate positions. //then we allow rebalancing of the stable rate positions.
@ -389,14 +390,13 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
.getMaxVariableBorrowRate(); .getMaxVariableBorrowRate();
require( require(
usageRatio >= REBALANCE_UP_USAGE_RATIO_THRESHOLD &&
currentLiquidityRate <= currentLiquidityRate <=
maxVariableBorrowRate.percentMul(REBALANCE_UP_LIQUIDITY_RATE_THRESHOLD), maxVariableBorrowRate.percentMul(REBALANCE_UP_LIQUIDITY_RATE_THRESHOLD),
Errors.INTEREST_RATE_REBALANCE_CONDITIONS_NOT_MET Errors.INTEREST_RATE_REBALANCE_CONDITIONS_NOT_MET
); );
//burn old debt tokens, mint new ones reserve.updateState();
reserve.updateCumulativeIndexesAndTimestamp();
IStableDebtToken(address(stableDebtToken)).burn(user, stableBorrowBalance); IStableDebtToken(address(stableDebtToken)).burn(user, stableBorrowBalance);
IStableDebtToken(address(stableDebtToken)).mint(user, stableBorrowBalance, reserve.currentStableBorrowRate); IStableDebtToken(address(stableDebtToken)).mint(user, stableBorrowBalance, reserve.currentStableBorrowRate);
@ -576,7 +576,7 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
if (debtMode == ReserveLogic.InterestRateMode.NONE) { if (debtMode == ReserveLogic.InterestRateMode.NONE) {
IERC20(asset).transferFrom(receiverAddress, vars.aTokenAddress, vars.amountPlusPremium); IERC20(asset).transferFrom(receiverAddress, vars.aTokenAddress, vars.amountPlusPremium);
reserve.updateCumulativeIndexesAndTimestamp(); reserve.updateState();
reserve.cumulateToLiquidityIndex(IERC20(vars.aTokenAddress).totalSupply(), vars.premium); reserve.cumulateToLiquidityIndex(IERC20(vars.aTokenAddress).totalSupply(), vars.premium);
reserve.updateInterestRates(asset, vars.aTokenAddress, vars.premium, 0); reserve.updateInterestRates(asset, vars.aTokenAddress, vars.premium, 0);
@ -649,6 +649,7 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
uint256 ltv, uint256 ltv,
uint256 liquidationThreshold, uint256 liquidationThreshold,
uint256 liquidationBonus, uint256 liquidationBonus,
uint256 reserveFactor,
address interestRateStrategyAddress, address interestRateStrategyAddress,
bool usageAsCollateralEnabled, bool usageAsCollateralEnabled,
bool borrowingEnabled, bool borrowingEnabled,
@ -664,6 +665,7 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
reserve.configuration.getLtv(), reserve.configuration.getLtv(),
reserve.configuration.getLiquidationThreshold(), reserve.configuration.getLiquidationThreshold(),
reserve.configuration.getLiquidationBonus(), reserve.configuration.getLiquidationBonus(),
reserve.configuration.getReserveFactor(),
reserve.interestRateStrategyAddress, reserve.interestRateStrategyAddress,
reserve.configuration.getLtv() != 0, reserve.configuration.getLtv() != 0,
reserve.configuration.getBorrowingEnabled(), reserve.configuration.getBorrowingEnabled(),
@ -698,8 +700,8 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
view view
returns ( returns (
uint256 availableLiquidity, uint256 availableLiquidity,
uint256 totalBorrowsStable, uint256 totalStableDebt,
uint256 totalBorrowsVariable, uint256 totalVariableDebt,
uint256 liquidityRate, uint256 liquidityRate,
uint256 variableBorrowRate, uint256 variableBorrowRate,
uint256 stableBorrowRate, uint256 stableBorrowRate,
@ -710,6 +712,7 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
) )
{ {
ReserveLogic.ReserveData memory reserve = _reserves[asset]; ReserveLogic.ReserveData memory reserve = _reserves[asset];
return ( return (
IERC20(asset).balanceOf(reserve.aTokenAddress), IERC20(asset).balanceOf(reserve.aTokenAddress),
IERC20(reserve.stableDebtTokenAddress).totalSupply(), IERC20(reserve.stableDebtTokenAddress).totalSupply(),
@ -731,7 +734,6 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
returns ( returns (
uint256 totalCollateralETH, uint256 totalCollateralETH,
uint256 totalBorrowsETH, uint256 totalBorrowsETH,
uint256 availableBorrowsETH,
uint256 currentLiquidationThreshold, uint256 currentLiquidationThreshold,
uint256 ltv, uint256 ltv,
uint256 healthFactor uint256 healthFactor
@ -750,12 +752,6 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
_reservesList, _reservesList,
_addressesProvider.getPriceOracle() _addressesProvider.getPriceOracle()
); );
availableBorrowsETH = GenericLogic.calculateAvailableBorrowsETH(
totalCollateralETH,
totalBorrowsETH,
ltv
);
} }
function getUserReserveData(address asset, address user) function getUserReserveData(address asset, address user)
@ -767,10 +763,9 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
uint256 currentStableDebt, uint256 currentStableDebt,
uint256 currentVariableDebt, uint256 currentVariableDebt,
uint256 principalStableDebt, uint256 principalStableDebt,
uint256 principalVariableDebt, uint256 scaledVariableDebt,
uint256 stableBorrowRate, uint256 stableBorrowRate,
uint256 liquidityRate, uint256 liquidityRate,
uint256 variableBorrowIndex,
uint40 stableRateLastUpdated, uint40 stableRateLastUpdated,
bool usageAsCollateralEnabled bool usageAsCollateralEnabled
) )
@ -779,14 +774,14 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
currentATokenBalance = IERC20(reserve.aTokenAddress).balanceOf(user); currentATokenBalance = IERC20(reserve.aTokenAddress).balanceOf(user);
(currentStableDebt, currentVariableDebt) = Helpers.getUserCurrentDebt(user, reserve); (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; liquidityRate = reserve.currentLiquidityRate;
stableBorrowRate = IStableDebtToken(reserve.stableDebtTokenAddress).getUserStableRate(user); stableBorrowRate = IStableDebtToken(reserve.stableDebtTokenAddress).getUserStableRate(user);
stableRateLastUpdated = IStableDebtToken(reserve.stableDebtTokenAddress).getUserLastUpdated( stableRateLastUpdated = IStableDebtToken(reserve.stableDebtTokenAddress).getUserLastUpdated(
user user
); );
usageAsCollateralEnabled = _usersConfig[user].isUsingAsCollateral(reserve.id); usageAsCollateralEnabled = _usersConfig[user].isUsingAsCollateral(reserve.id);
variableBorrowIndex = IVariableDebtToken(reserve.variableDebtTokenAddress).getUserIndex(user);
} }
function getReserves() external override view returns (address[] memory) { function getReserves() external override view returns (address[] memory) {
@ -888,12 +883,12 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
oracle oracle
); );
uint256 reserveIndex = reserve.id; uint256 reserveId = reserve.id;
if (!userConfig.isBorrowing(reserveIndex)) { if (!userConfig.isBorrowing(reserveId)) {
userConfig.setBorrowing(reserveIndex, true); userConfig.setBorrowing(reserveId, true);
} }
reserve.updateCumulativeIndexesAndTimestamp(); reserve.updateState();
//caching the current stable borrow rate //caching the current stable borrow rate
uint256 currentStableRate = 0; uint256 currentStableRate = 0;
@ -909,7 +904,11 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
currentStableRate currentStableRate
); );
} else { } else {
IVariableDebtToken(reserve.variableDebtTokenAddress).mint(vars.onBehalfOf, vars.amount); IVariableDebtToken(reserve.variableDebtTokenAddress).mint(
vars.onBehalfOf,
vars.amount,
reserve.variableBorrowIndex
);
} }
reserve.updateInterestRates( reserve.updateInterestRates(

View File

@ -9,6 +9,7 @@ import {
import {IAToken} from '../tokenization/interfaces/IAToken.sol'; import {IAToken} from '../tokenization/interfaces/IAToken.sol';
import {IStableDebtToken} from '../tokenization/interfaces/IStableDebtToken.sol'; import {IStableDebtToken} from '../tokenization/interfaces/IStableDebtToken.sol';
import {IVariableDebtToken} from '../tokenization/interfaces/IVariableDebtToken.sol'; import {IVariableDebtToken} from '../tokenization/interfaces/IVariableDebtToken.sol';
import {DebtTokenBase} from '../tokenization/base/DebtTokenBase.sol';
import {IPriceOracleGetter} from '../interfaces/IPriceOracleGetter.sol'; import {IPriceOracleGetter} from '../interfaces/IPriceOracleGetter.sol';
import {GenericLogic} from '../libraries/logic/GenericLogic.sol'; import {GenericLogic} from '../libraries/logic/GenericLogic.sol';
import {ReserveLogic} from '../libraries/logic/ReserveLogic.sol'; import {ReserveLogic} from '../libraries/logic/ReserveLogic.sol';
@ -221,7 +222,8 @@ contract LendingPoolCollateralManager is VersionedInitializable, LendingPoolStor
} }
//update the principal reserve //update the principal reserve
principalReserve.updateCumulativeIndexesAndTimestamp(); principalReserve.updateState();
principalReserve.updateInterestRates( principalReserve.updateInterestRates(
principal, principal,
principalReserve.aTokenAddress, principalReserve.aTokenAddress,
@ -232,13 +234,16 @@ contract LendingPoolCollateralManager is VersionedInitializable, LendingPoolStor
if (vars.userVariableDebt >= vars.actualAmountToLiquidate) { if (vars.userVariableDebt >= vars.actualAmountToLiquidate) {
IVariableDebtToken(principalReserve.variableDebtTokenAddress).burn( IVariableDebtToken(principalReserve.variableDebtTokenAddress).burn(
user, user,
vars.actualAmountToLiquidate vars.actualAmountToLiquidate,
principalReserve.variableBorrowIndex
); );
} else { } else {
IVariableDebtToken(principalReserve.variableDebtTokenAddress).burn( IVariableDebtToken(principalReserve.variableDebtTokenAddress).burn(
user, user,
vars.userVariableDebt vars.userVariableDebt,
principalReserve.variableBorrowIndex
); );
IStableDebtToken(principalReserve.stableDebtTokenAddress).burn( IStableDebtToken(principalReserve.stableDebtTokenAddress).burn(
user, user,
vars.actualAmountToLiquidate.sub(vars.userVariableDebt) vars.actualAmountToLiquidate.sub(vars.userVariableDebt)
@ -252,7 +257,7 @@ contract LendingPoolCollateralManager is VersionedInitializable, LendingPoolStor
//otherwise receives the underlying asset //otherwise receives the underlying asset
//updating collateral reserve //updating collateral reserve
collateralReserve.updateCumulativeIndexesAndTimestamp(); collateralReserve.updateState();
collateralReserve.updateInterestRates( collateralReserve.updateInterestRates(
collateral, collateral,
address(vars.collateralAtoken), address(vars.collateralAtoken),
@ -367,7 +372,7 @@ contract LendingPoolCollateralManager is VersionedInitializable, LendingPoolStor
vars.actualAmountToLiquidate = vars.principalAmountNeeded; vars.actualAmountToLiquidate = vars.principalAmountNeeded;
} }
//updating collateral reserve indexes //updating collateral reserve indexes
collateralReserve.updateCumulativeIndexesAndTimestamp(); collateralReserve.updateState();
vars.collateralAtoken.burn( vars.collateralAtoken.burn(
user, user,
@ -392,7 +397,7 @@ contract LendingPoolCollateralManager is VersionedInitializable, LendingPoolStor
); );
//updating debt reserve //updating debt reserve
debtReserve.updateCumulativeIndexesAndTimestamp(); debtReserve.updateState();
debtReserve.updateInterestRates( debtReserve.updateInterestRates(
principal, principal,
vars.principalAToken, vars.principalAToken,
@ -404,10 +409,15 @@ contract LendingPoolCollateralManager is VersionedInitializable, LendingPoolStor
if (vars.userVariableDebt >= vars.actualAmountToLiquidate) { if (vars.userVariableDebt >= vars.actualAmountToLiquidate) {
IVariableDebtToken(debtReserve.variableDebtTokenAddress).burn( IVariableDebtToken(debtReserve.variableDebtTokenAddress).burn(
user, user,
vars.actualAmountToLiquidate vars.actualAmountToLiquidate,
debtReserve.variableBorrowIndex
); );
} else { } else {
IVariableDebtToken(debtReserve.variableDebtTokenAddress).burn(user, vars.userVariableDebt); IVariableDebtToken(debtReserve.variableDebtTokenAddress).burn(
user,
vars.userVariableDebt,
debtReserve.variableBorrowIndex
);
IStableDebtToken(debtReserve.stableDebtTokenAddress).burn( IStableDebtToken(debtReserve.stableDebtTokenAddress).burn(
user, user,
vars.actualAmountToLiquidate.sub(vars.userVariableDebt) vars.actualAmountToLiquidate.sub(vars.userVariableDebt)
@ -468,8 +478,8 @@ contract LendingPoolCollateralManager is VersionedInitializable, LendingPoolStor
vars.fromReserveAToken = IAToken(fromReserve.aTokenAddress); vars.fromReserveAToken = IAToken(fromReserve.aTokenAddress);
vars.toReserveAToken = IAToken(toReserve.aTokenAddress); vars.toReserveAToken = IAToken(toReserve.aTokenAddress);
fromReserve.updateCumulativeIndexesAndTimestamp(); fromReserve.updateState();
toReserve.updateCumulativeIndexesAndTimestamp(); toReserve.updateState();
if (vars.fromReserveAToken.balanceOf(msg.sender) == amountToSwap) { if (vars.fromReserveAToken.balanceOf(msg.sender) == amountToSwap) {
_usersConfig[msg.sender].setUsingAsCollateral(fromReserve.id, false); _usersConfig[msg.sender].setUsingAsCollateral(fromReserve.id, false);

View File

@ -118,6 +118,13 @@ contract LendingPoolConfigurator is VersionedInitializable {
**/ **/
event ReserveBaseLtvChanged(address asset, uint256 ltv); 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 * @dev emitted when a reserve liquidation threshold is updated
* @param asset the address of the reserve * @param asset the address of the reserve
@ -405,8 +412,8 @@ contract LendingPoolConfigurator is VersionedInitializable {
function deactivateReserve(address asset) external onlyAaveAdmin { function deactivateReserve(address asset) external onlyAaveAdmin {
( (
uint256 availableLiquidity, uint256 availableLiquidity,
uint256 totalBorrowsStable, uint256 totalStableDebt,
uint256 totalBorrowsVariable, uint256 totalVariableDebt,
, ,
, ,
, ,
@ -416,7 +423,7 @@ contract LendingPoolConfigurator is VersionedInitializable {
) = pool.getReserveData(asset); ) = pool.getReserveData(asset);
require( require(
availableLiquidity == 0 && totalBorrowsStable == 0 && totalBorrowsVariable == 0, availableLiquidity == 0 && totalStableDebt == 0 && totalVariableDebt == 0,
Errors.RESERVE_LIQUIDITY_NOT_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 asset the address of the reserve
* @param ltv the new value for the loan to value * @param ltv the new value for the loan to value
**/ **/
@ -472,6 +479,22 @@ contract LendingPoolConfigurator is VersionedInitializable {
emit ReserveBaseLtvChanged(asset, ltv); 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. * @dev updates the liquidation threshold of a reserve.
* @param asset the address of the reserve * @param asset the address of the reserve
@ -559,7 +582,7 @@ contract LendingPoolConfigurator is VersionedInitializable {
payable(proxyAddress) payable(proxyAddress)
); );
(uint256 decimals, , , , , , , , , ) = pool.getReserveConfigurationData(asset); (uint256 decimals, , , , , , , , , , ) = pool.getReserveConfigurationData(asset);
bytes memory params = abi.encodeWithSignature( bytes memory params = abi.encodeWithSignature(
'initialize(uint8,string,string)', 'initialize(uint8,string,string)',

View File

@ -6,6 +6,7 @@ import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol';
import {ReserveLogic} from '../logic/ReserveLogic.sol'; import {ReserveLogic} from '../logic/ReserveLogic.sol';
import {WadRayMath} from '../math/WadRayMath.sol'; import {WadRayMath} from '../math/WadRayMath.sol';
import {IPriceOracleGetter} from '../../interfaces/IPriceOracleGetter.sol'; import {IPriceOracleGetter} from '../../interfaces/IPriceOracleGetter.sol';
import "@nomiclabs/buidler/console.sol";
/** /**
* @title ReserveConfiguration library * @title ReserveConfiguration library
@ -13,14 +14,15 @@ import {IPriceOracleGetter} from '../../interfaces/IPriceOracleGetter.sol';
* @notice Implements the bitmap logic to handle the reserve configuration * @notice Implements the bitmap logic to handle the reserve configuration
*/ */
library ReserveConfiguration { library ReserveConfiguration {
uint256 constant LTV_MASK = 0xFFFFFFFFFFF0000; uint256 constant LTV_MASK = 0xFFFFFFFFFFFFFFFF0000;
uint256 constant LIQUIDATION_THRESHOLD_MASK = 0xFFFFFFF0000FFFF; uint256 constant LIQUIDATION_THRESHOLD_MASK = 0xFFFFFFFFFFFF0000FFFF;
uint256 constant LIQUIDATION_BONUS_MASK = 0xFFF0000FFFFFFFF; uint256 constant LIQUIDATION_BONUS_MASK = 0xFFFFFFF0000FFFFFFFF;
uint256 constant DECIMALS_MASK = 0xF00FFFFFFFFFFFF; uint256 constant DECIMALS_MASK = 0xFFFFFF00FFFFFFFFFFFF;
uint256 constant ACTIVE_MASK = 0xEFFFFFFFFFFFFFF; uint256 constant ACTIVE_MASK = 0xFFFFFEFFFFFFFFFFFFFF;
uint256 constant FROZEN_MASK = 0xDFFFFFFFFFFFFFF; uint256 constant FROZEN_MASK = 0xFFFFFDFFFFFFFFFFFFFF;
uint256 constant BORROWING_MASK = 0xBFFFFFFFFFFFFFF; uint256 constant BORROWING_MASK = 0xFFFFFBFFFFFFFFFFFFFF;
uint256 constant STABLE_BORROWING_MASK = 0x7FFFFFFFFFFFFFF; uint256 constant STABLE_BORROWING_MASK = 0xFFFF07FFFFFFFFFFFFFF;
uint256 constant RESERVE_FACTOR_MASK = 0xFFFFFFFFFFFFFFFF;
struct Map { struct Map {
//bit 0-15: LTV //bit 0-15: LTV
@ -31,9 +33,28 @@ library ReserveConfiguration {
//bit 57: reserve is freezed //bit 57: reserve is freezed
//bit 58: borrowing is enabled //bit 58: borrowing is enabled
//bit 59: stable rate borrowing enabled //bit 59: stable rate borrowing enabled
//bit 64-79: reserve factor
uint256 data; 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 * @dev sets the Loan to Value of the reserve
* @param self the reserve configuration * @param self the reserve configuration

View File

@ -48,7 +48,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 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 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 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 // require error messages - ReserveLogic
string public constant RESERVE_ALREADY_INITIALIZED = '34'; // 'Reserve has already been initialized' string public constant RESERVE_ALREADY_INITIALIZED = '34'; // 'Reserve has already been initialized'

View File

@ -26,21 +26,4 @@ library Helpers {
DebtTokenBase(reserve.variableDebtTokenAddress).balanceOf(user) 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)
);
}
} }

View File

@ -253,28 +253,4 @@ library GenericLogic {
return (collateralBalanceETH.percentMul(liquidationThreshold)).wadDiv(borrowBalanceETH); return (collateralBalanceETH.percentMul(liquidationThreshold)).wadDiv(borrowBalanceETH);
} }
/**
* @dev calculates the equivalent amount in ETH that an user can borrow, depending on the available collateral and the
* average Loan To Value.
* @param collateralBalanceETH the total collateral balance
* @param borrowBalanceETH the total borrow balance
* @param ltv the average loan to value
* @return the amount available to borrow in ETH for the user
**/
function calculateAvailableBorrowsETH(
uint256 collateralBalanceETH,
uint256 borrowBalanceETH,
uint256 ltv
) internal pure returns (uint256) {
uint256 availableBorrowsETH = collateralBalanceETH.percentMul(ltv); //ltv is in percentage
if (availableBorrowsETH < borrowBalanceETH) {
return 0;
}
availableBorrowsETH = availableBorrowsETH.sub(borrowBalanceETH);
return availableBorrowsETH;
}
} }

View File

@ -6,10 +6,13 @@ import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol';
import {MathUtils} from '../math/MathUtils.sol'; import {MathUtils} from '../math/MathUtils.sol';
import {IPriceOracleGetter} from '../../interfaces/IPriceOracleGetter.sol'; import {IPriceOracleGetter} from '../../interfaces/IPriceOracleGetter.sol';
import {SafeERC20} from '@openzeppelin/contracts/token/ERC20/SafeERC20.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 {IStableDebtToken} from '../../tokenization/interfaces/IStableDebtToken.sol';
import {IVariableDebtToken} from '../../tokenization/interfaces/IVariableDebtToken.sol';
import {ReserveConfiguration} from '../configuration/ReserveConfiguration.sol'; import {ReserveConfiguration} from '../configuration/ReserveConfiguration.sol';
import {IReserveInterestRateStrategy} from '../../interfaces/IReserveInterestRateStrategy.sol'; import {IReserveInterestRateStrategy} from '../../interfaces/IReserveInterestRateStrategy.sol';
import {WadRayMath} from '../math/WadRayMath.sol'; import {WadRayMath} from '../math/WadRayMath.sol';
import {PercentageMath} from '../math/PercentageMath.sol';
import {Errors} from '../helpers/Errors.sol'; import {Errors} from '../helpers/Errors.sol';
/** /**
@ -20,6 +23,7 @@ import {Errors} from '../helpers/Errors.sol';
library ReserveLogic { library ReserveLogic {
using SafeMath for uint256; using SafeMath for uint256;
using WadRayMath for uint256; using WadRayMath for uint256;
using PercentageMath for uint256;
using SafeERC20 for IERC20; using SafeERC20 for IERC20;
/** /**
@ -27,7 +31,6 @@ library ReserveLogic {
* @param reserve the address of the reserve * @param reserve the address of the reserve
* @param liquidityRate the new liquidity rate * @param liquidityRate the new liquidity rate
* @param stableBorrowRate the new stable borrow rate * @param stableBorrowRate the new stable borrow rate
* @param averageStableBorrowRate the new average stable borrow rate
* @param variableBorrowRate the new variable borrow rate * @param variableBorrowRate the new variable borrow rate
* @param liquidityIndex the new liquidity index * @param liquidityIndex the new liquidity index
* @param variableBorrowIndex the new variable borrow index * @param variableBorrowIndex the new variable borrow index
@ -36,7 +39,6 @@ library ReserveLogic {
address indexed reserve, address indexed reserve,
uint256 liquidityRate, uint256 liquidityRate,
uint256 stableBorrowRate, uint256 stableBorrowRate,
uint256 averageStableBorrowRate,
uint256 variableBorrowRate, uint256 variableBorrowRate,
uint256 liquidityIndex, uint256 liquidityIndex,
uint256 variableBorrowIndex uint256 variableBorrowIndex
@ -66,6 +68,7 @@ library ReserveLogic {
address aTokenAddress; address aTokenAddress;
address stableDebtTokenAddress; address stableDebtTokenAddress;
address variableDebtTokenAddress; address variableDebtTokenAddress;
//address of the interest rate strategy
address interestRateStrategyAddress; address interestRateStrategyAddress;
//the id of the reserve. Represents the position in the list of the active reserves //the id of the reserve. Represents the position in the list of the active reserves
uint8 id; uint8 id;
@ -124,7 +127,7 @@ library ReserveLogic {
* @return an address of the corresponding debt token from reserve configuration * @return an address of the corresponding debt token from reserve configuration
**/ **/
function getDebtTokenAddress(ReserveLogic.ReserveData storage reserve, uint256 interestRateMode) function getDebtTokenAddress(ReserveLogic.ReserveData storage reserve, uint256 interestRateMode)
internal external
view view
returns (address) returns (address)
{ {
@ -144,36 +147,25 @@ library ReserveLogic {
* a formal specification. * a formal specification.
* @param reserve the reserve object * @param reserve the reserve object
**/ **/
function updateCumulativeIndexesAndTimestamp(ReserveData storage reserve) internal { function updateState(ReserveData storage reserve) external {
uint256 currentLiquidityRate = reserve.currentLiquidityRate; address variableDebtToken = reserve.variableDebtTokenAddress;
uint256 previousVariableBorrowIndex = reserve.variableBorrowIndex;
uint256 previousLiquidityIndex = reserve.liquidityIndex;
//only cumulating if there is any income being produced (uint256 newLiquidityIndex, uint256 newVariableBorrowIndex) = _updateIndexes(
if (currentLiquidityRate > 0) { reserve,
uint40 lastUpdateTimestamp = reserve.lastUpdateTimestamp; variableDebtToken,
uint256 cumulatedLiquidityInterest = MathUtils.calculateLinearInterest( previousLiquidityIndex,
currentLiquidityRate, previousVariableBorrowIndex
lastUpdateTimestamp
); );
uint256 index = cumulatedLiquidityInterest.rayMul(reserve.liquidityIndex);
require(index < (1 << 128), Errors.LIQUIDITY_INDEX_OVERFLOW);
reserve.liquidityIndex = uint128(index); _mintToTreasury(
reserve,
//as the liquidity rate might come only from stable rate loans, we need to ensure variableDebtToken,
//that there is actual variable debt before accumulating previousVariableBorrowIndex,
if (IERC20(reserve.variableDebtTokenAddress).totalSupply() > 0) { newLiquidityIndex,
uint256 cumulatedVariableBorrowInterest = MathUtils.calculateCompoundedInterest( newVariableBorrowIndex
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);
} }
/** /**
@ -228,12 +220,13 @@ library ReserveLogic {
} }
struct UpdateInterestRatesLocalVars { struct UpdateInterestRatesLocalVars {
uint256 currentAvgStableRate;
uint256 availableLiquidity;
address stableDebtTokenAddress; address stableDebtTokenAddress;
uint256 availableLiquidity;
uint256 totalStableDebt;
uint256 newLiquidityRate; uint256 newLiquidityRate;
uint256 newStableRate; uint256 newStableRate;
uint256 newVariableRate; uint256 newVariableRate;
uint256 avgStableRate;
} }
/** /**
@ -253,8 +246,10 @@ library ReserveLogic {
UpdateInterestRatesLocalVars memory vars; UpdateInterestRatesLocalVars memory vars;
vars.stableDebtTokenAddress = reserve.stableDebtTokenAddress; vars.stableDebtTokenAddress = reserve.stableDebtTokenAddress;
vars.currentAvgStableRate = IStableDebtToken(vars.stableDebtTokenAddress)
.getAverageStableRate(); (vars.totalStableDebt, vars.avgStableRate) = IStableDebtToken(vars.stableDebtTokenAddress)
.getTotalSupplyAndAvgRate();
vars.availableLiquidity = IERC20(reserveAddress).balanceOf(aTokenAddress); vars.availableLiquidity = IERC20(reserveAddress).balanceOf(aTokenAddress);
( (
@ -264,9 +259,10 @@ library ReserveLogic {
) = IReserveInterestRateStrategy(reserve.interestRateStrategyAddress).calculateInterestRates( ) = IReserveInterestRateStrategy(reserve.interestRateStrategyAddress).calculateInterestRates(
reserveAddress, reserveAddress,
vars.availableLiquidity.add(liquidityAdded).sub(liquidityTaken), vars.availableLiquidity.add(liquidityAdded).sub(liquidityTaken),
IERC20(vars.stableDebtTokenAddress).totalSupply(), vars.totalStableDebt,
IERC20(reserve.variableDebtTokenAddress).totalSupply(), IERC20(reserve.variableDebtTokenAddress).totalSupply(),
vars.currentAvgStableRate vars.avgStableRate,
reserve.configuration.getReserveFactor()
); );
require(vars.newLiquidityRate < (1 << 128), 'ReserveLogic: Liquidity rate overflow'); require(vars.newLiquidityRate < (1 << 128), 'ReserveLogic: Liquidity rate overflow');
require(vars.newStableRate < (1 << 128), 'ReserveLogic: Stable borrow rate overflow'); require(vars.newStableRate < (1 << 128), 'ReserveLogic: Stable borrow rate overflow');
@ -280,10 +276,134 @@ library ReserveLogic {
reserveAddress, reserveAddress,
vars.newLiquidityRate, vars.newLiquidityRate,
vars.newStableRate, vars.newStableRate,
vars.currentAvgStableRate,
vars.newVariableRate, vars.newVariableRate,
reserve.liquidityIndex, reserve.liquidityIndex,
reserve.variableBorrowIndex 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);
}
} }

View File

@ -91,7 +91,7 @@ contract WalletBalanceProvider {
uint256[] memory balances = new uint256[](reserves.length); uint256[] memory balances = new uint256[](reserves.length);
for (uint256 j = 0; j < reserves.length; j++) { for (uint256 j = 0; j < reserves.length; j++) {
(, , , , , , , , bool isActive, ) = pool.getReserveConfigurationData(reserves[j]); (, , , , , , , , , bool isActive, ) = pool.getReserveConfigurationData(reserves[j]);
if (!isActive) { if (!isActive) {
balances[j] = 0; balances[j] = 0;

View File

@ -6,12 +6,13 @@ import {LendingPool} from '../../lendingpool/LendingPool.sol';
contract MockAToken is AToken { contract MockAToken is AToken {
constructor( constructor(
LendingPool _pool, LendingPool pool,
address _underlyingAssetAddress, address underlyingAssetAddress,
string memory _tokenName, address reserveTreasury,
string memory _tokenSymbol, string memory tokenName,
string memory tokenSymbol,
address incentivesController address incentivesController
) public AToken(_pool, _underlyingAssetAddress, _tokenName, _tokenSymbol, incentivesController) {} ) public AToken(pool, underlyingAssetAddress, reserveTreasury, tokenName, tokenSymbol, incentivesController) {}
function getRevision() internal override pure returns (uint256) { function getRevision() internal override pure returns (uint256) {
return 0x2; return 0x2;

View File

@ -20,18 +20,8 @@ import {SafeERC20} from '../misc/SafeERC20.sol';
*/ */
contract AToken is VersionedInitializable, IncentivizedERC20, IAToken { contract AToken is VersionedInitializable, IncentivizedERC20, IAToken {
using WadRayMath for uint256; 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'); bytes public constant EIP712_REVISION = bytes('1');
bytes32 internal constant EIP712_DOMAIN = keccak256( bytes32 internal constant EIP712_DOMAIN = keccak256(
'EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)' '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)' '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 { modifier onlyLendingPool {
require(msg.sender == address(POOL), Errors.CALLER_MUST_BE_LENDING_POOL); require(msg.sender == address(POOL), Errors.CALLER_MUST_BE_LENDING_POOL);
_; _;
@ -48,12 +49,14 @@ contract AToken is VersionedInitializable, IncentivizedERC20, IAToken {
constructor( constructor(
LendingPool pool, LendingPool pool,
address underlyingAssetAddress, address underlyingAssetAddress,
address reserveTreasuryAddress,
string memory tokenName, string memory tokenName,
string memory tokenSymbol, string memory tokenSymbol,
address incentivesController address incentivesController
) public IncentivizedERC20(tokenName, tokenSymbol, 18, incentivesController) { ) public IncentivizedERC20(tokenName, tokenSymbol, 18, incentivesController) {
POOL = pool; POOL = pool;
UNDERLYING_ASSET_ADDRESS = underlyingAssetAddress; UNDERLYING_ASSET_ADDRESS = underlyingAssetAddress;
RESERVE_TREASURY_ADDRESS = reserveTreasuryAddress;
} }
function getRevision() internal virtual override pure returns (uint256) { function getRevision() internal virtual override pure returns (uint256) {
@ -98,20 +101,13 @@ contract AToken is VersionedInitializable, IncentivizedERC20, IAToken {
uint256 amount, uint256 amount,
uint256 index uint256 index
) external override onlyLendingPool { ) external override onlyLendingPool {
uint256 currentBalance = balanceOf(user); _burn(user, amount.rayDiv(index));
require(amount <= currentBalance, Errors.INVALID_ATOKEN_BALANCE);
uint256 scaledAmount = amount.rayDiv(index);
_burn(user, scaledAmount);
//transfers the underlying to the target //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 //transfer event to track balances
emit Transfer(user, address(0), amount); emit Transfer(user, address(0), amount);
emit Burn(msg.sender, receiverOfUnderlying, amount, index); emit Burn(msg.sender, receiverOfUnderlying, amount, index);
} }
@ -126,16 +122,22 @@ contract AToken is VersionedInitializable, IncentivizedERC20, IAToken {
uint256 amount, uint256 amount,
uint256 index uint256 index
) external override onlyLendingPool { ) external override onlyLendingPool {
uint256 scaledAmount = amount.rayDiv(index);
//mint an equivalent amount of tokens to cover the new deposit //mint an equivalent amount of tokens to cover the new deposit
_mint(user, scaledAmount); _mint(user, amount.rayDiv(index));
//transfer event to track balances //transfer event to track balances
emit Transfer(address(0), user, amount); emit Transfer(address(0), user, amount);
emit Mint(user, amount, index); 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 * @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 * 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)); 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. * @dev Used to validate transfers before actually executing them.
* @param user address of the user to check * @param user address of the user to check
@ -232,7 +242,7 @@ contract AToken is VersionedInitializable, IncentivizedERC20, IAToken {
onlyLendingPool onlyLendingPool
returns (uint256) returns (uint256)
{ {
IncentivizedERC20(UNDERLYING_ASSET_ADDRESS).safeTransfer(target, amount); IERC20(UNDERLYING_ASSET_ADDRESS).safeTransfer(target, amount);
return amount; return amount;
} }
@ -271,6 +281,14 @@ contract AToken is VersionedInitializable, IncentivizedERC20, IAToken {
_approve(owner, spender, value); _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( function _transfer(
address from, address from,
address to, address to,
@ -283,13 +301,17 @@ contract AToken is VersionedInitializable, IncentivizedERC20, IAToken {
uint256 index = POOL.getReserveNormalizedIncome(UNDERLYING_ASSET_ADDRESS); uint256 index = POOL.getReserveNormalizedIncome(UNDERLYING_ASSET_ADDRESS);
uint256 scaledAmount = amount.rayDiv(index); super._transfer(from, to, amount.rayDiv(index));
super._transfer(from, to, scaledAmount);
emit BalanceTransfer(from, to, amount, 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( function _transfer(
address from, address from,
address to, address to,

View File

@ -8,6 +8,7 @@ import {DebtTokenBase} from './base/DebtTokenBase.sol';
import {MathUtils} from '../libraries/math/MathUtils.sol'; import {MathUtils} from '../libraries/math/MathUtils.sol';
import {WadRayMath} from '../libraries/math/WadRayMath.sol'; import {WadRayMath} from '../libraries/math/WadRayMath.sol';
import {IStableDebtToken} from './interfaces/IStableDebtToken.sol'; import {IStableDebtToken} from './interfaces/IStableDebtToken.sol';
import "@nomiclabs/buidler/console.sol";
/** /**
* @title contract StableDebtToken * @title contract StableDebtToken
@ -21,6 +22,7 @@ contract StableDebtToken is IStableDebtToken, DebtTokenBase {
uint256 private _avgStableRate; uint256 private _avgStableRate;
mapping(address => uint40) _timestamps; mapping(address => uint40) _timestamps;
uint40 _totalSupplyTimestamp;
constructor( constructor(
address pool, address pool,
@ -68,7 +70,7 @@ contract StableDebtToken is IStableDebtToken, DebtTokenBase {
* @return the accumulated debt of the user * @return the accumulated debt of the user
**/ **/
function balanceOf(address account) public virtual override view returns (uint256) { function balanceOf(address account) public virtual override view returns (uint256) {
uint256 accountBalance = principalBalanceOf(account); uint256 accountBalance = super.balanceOf(account);
uint256 stableRate = _usersData[account]; uint256 stableRate = _usersData[account];
if (accountBalance == 0) { if (accountBalance == 0) {
return 0; return 0;
@ -77,14 +79,15 @@ contract StableDebtToken is IStableDebtToken, DebtTokenBase {
stableRate, stableRate,
_timestamps[account] _timestamps[account]
); );
return accountBalance.wadToRay().rayMul(cumulatedInterest).rayToWad(); return accountBalance.rayMul(cumulatedInterest);
} }
struct MintLocalVars { struct MintLocalVars {
uint256 supplyAfterMint; uint256 previousSupply;
uint256 supplyBeforeMint; uint256 nextSupply;
uint256 amountInRay; uint256 amountInRay;
uint256 newStableRate; uint256 newStableRate;
uint256 currentAvgStableRate;
} }
/** /**
@ -108,8 +111,10 @@ contract StableDebtToken is IStableDebtToken, DebtTokenBase {
uint256 balanceIncrease uint256 balanceIncrease
) = _calculateBalanceIncrease(user); ) = _calculateBalanceIncrease(user);
vars.supplyBeforeMint = totalSupply().add(balanceIncrease); //accrueing the interest accumulation to the stored total supply and caching it
vars.supplyAfterMint = vars.supplyBeforeMint.add(amount); vars.previousSupply = totalSupply();
vars.currentAvgStableRate = _avgStableRate;
vars.nextSupply = _totalSupply = vars.previousSupply.add(amount);
vars.amountInRay = amount.wadToRay(); vars.amountInRay = amount.wadToRay();
@ -122,16 +127,17 @@ contract StableDebtToken is IStableDebtToken, DebtTokenBase {
require(vars.newStableRate < (1 << 128), 'Debt token: stable rate overflow'); require(vars.newStableRate < (1 << 128), 'Debt token: stable rate overflow');
_usersData[user] = vars.newStableRate; _usersData[user] = vars.newStableRate;
//updating the user and supply timestamp
//solium-disable-next-line //solium-disable-next-line
_timestamps[user] = uint40(block.timestamp); _totalSupplyTimestamp = _timestamps[user] = uint40(block.timestamp);
//calculates the updated average stable rate //calculates the updated average stable rate
_avgStableRate = _avgStableRate _avgStableRate = vars.currentAvgStableRate
.rayMul(vars.supplyBeforeMint.wadToRay()) .rayMul(vars.previousSupply.wadToRay())
.add(rate.rayMul(vars.amountInRay)) .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 // transfer event to track balances
emit Transfer(address(0), user, amount); emit Transfer(address(0), user, amount);
@ -158,30 +164,39 @@ contract StableDebtToken is IStableDebtToken, DebtTokenBase {
uint256 balanceIncrease uint256 balanceIncrease
) = _calculateBalanceIncrease(user); ) = _calculateBalanceIncrease(user);
uint256 supplyBeforeBurn = totalSupply().add(balanceIncrease);
uint256 supplyAfterBurn = supplyBeforeBurn.sub(amount);
if (supplyAfterBurn == 0) { uint256 previousSupply = totalSupply();
//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; _avgStableRate = 0;
_totalSupply = 0;
} else { } else {
uint256 nextSupply = _totalSupply = previousSupply.sub(amount);
_avgStableRate = _avgStableRate _avgStableRate = _avgStableRate
.rayMul(supplyBeforeBurn.wadToRay()) .rayMul(previousSupply.wadToRay())
.sub(_usersData[user].rayMul(amount.wadToRay())) .sub(_usersData[user].rayMul(amount.wadToRay()))
.rayDiv(supplyAfterBurn.wadToRay()); .rayDiv(nextSupply.wadToRay());
} }
if (amount == currentBalance) { if (amount == currentBalance) {
_usersData[user] = 0; _usersData[user] = 0;
_timestamps[user] = 0; _timestamps[user] = 0;
} else { } else {
//solium-disable-next-line //solium-disable-next-line
_timestamps[user] = uint40(block.timestamp); _timestamps[user] = uint40(block.timestamp);
} }
//solium-disable-next-line
_totalSupplyTimestamp = uint40(block.timestamp);
if (balanceIncrease > amount) { if (balanceIncrease > amount) {
_mint(user, balanceIncrease.sub(amount)); _mint(user, balanceIncrease.sub(amount), previousSupply);
} else { } else {
_burn(user, amount.sub(balanceIncrease)); _burn(user, amount.sub(balanceIncrease), previousSupply);
} }
// transfer event to track balances // transfer event to track balances
@ -189,4 +204,127 @@ contract StableDebtToken is IStableDebtToken, DebtTokenBase {
emit BurnDebt(user, amount, previousBalance, currentBalance, balanceIncrease); 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);
}
}
} }

View File

@ -39,79 +39,81 @@ contract VariableDebtToken is DebtTokenBase, IVariableDebtToken {
* @return the debt balance of the user * @return the debt balance of the user
**/ **/
function balanceOf(address user) public virtual override view returns (uint256) { function balanceOf(address user) public virtual override view returns (uint256) {
uint256 userBalance = principalBalanceOf(user); uint256 scaledBalance = super.balanceOf(user);
uint256 index = _usersData[user];
if (userBalance == 0) { if (scaledBalance == 0) {
return 0; return 0;
} }
return return scaledBalance.rayMul(POOL.getReserveNormalizedVariableDebt(UNDERLYING_ASSET));
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];
} }
/** /**
* @dev mints new variable debt * @dev mints new variable debt
* @param user the user receiving the debt * @param user the user receiving the debt
* @param amount the amount of debt being minted * @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 { function mint(
( address user,
uint256 previousBalance, uint256 amount,
uint256 currentBalance, uint256 index
uint256 balanceIncrease ) external override onlyLendingPool {
) = _calculateBalanceIncrease(user);
_mint(user, amount.add(balanceIncrease)); _mint(user, amount.rayDiv(index));
uint256 newUserIndex = POOL.getReserveNormalizedVariableDebt(UNDERLYING_ASSET);
require(newUserIndex < (1 << 128), 'Debt token: Index overflow');
_usersData[user] = newUserIndex;
emit Transfer(address(0), user, amount); emit Transfer(address(0), user, amount);
emit MintDebt(user, amount, previousBalance, currentBalance, balanceIncrease, newUserIndex); emit Mint(user, amount, index);
} }
/** /**
* @dev burns user variable debt * @dev burns user variable debt
* @param user the user which debt is burnt * @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 { function burn(
( address user,
uint256 previousBalance, uint256 amount,
uint256 currentBalance, uint256 index
uint256 balanceIncrease ) external override onlyLendingPool {
) = _calculateBalanceIncrease(user); _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 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());
}
} }

View File

@ -65,14 +65,6 @@ abstract contract DebtTokenBase is IncentivizedERC20, VersionedInitializable {
return UNDERLYING_ASSET; 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 * @dev Being non transferrable, the debt token does not implement any of the
* standard ERC20 functions for transfer and allowance. * standard ERC20 functions for transfer and allowance.
@ -133,35 +125,4 @@ abstract contract DebtTokenBase is IncentivizedERC20, VersionedInitializable {
subtractedValue; subtractedValue;
revert('ALLOWANCE_NOT_SUPPORTED'); 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
);
}
} }

View File

@ -2,8 +2,9 @@
pragma solidity ^0.6.8; pragma solidity ^0.6.8;
import {IERC20} from '../../interfaces/IERC20.sol'; 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 * @dev emitted after aTokens are burned
* @param from the address performing the redeem * @param from the address performing the redeem
@ -16,15 +17,6 @@ interface IAToken is IERC20 {
uint256 value, uint256 value,
uint256 index 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 * @dev emitted during the transfer action
* @param from the address from which the tokens are being transferred * @param from the address from which the tokens are being transferred
@ -38,7 +30,6 @@ interface IAToken is IERC20 {
uint256 value, uint256 value,
uint256 index uint256 index
); );
/** /**
* @dev burns the aTokens and sends the equivalent amount of underlying to the target. * @dev burns the aTokens and sends the equivalent amount of underlying to the target.
* only lending pools can call this function * only lending pools can call this function
@ -53,13 +44,11 @@ interface IAToken is IERC20 {
) external; ) external;
/** /**
* @dev mints aTokens to user * @dev mints aTokens to the reserve treasury
* only lending pools can call this function * @param amount the amount to mint
* @param user the address receiving the minted tokens * @param index the liquidity index of the reserve
* @param amount the amount of tokens to mint **/
* @param index the liquidity index function mintToTreasury(uint256 amount, uint256 index) external;
*/
function mint(address user, uint256 amount, uint256 index) external;
/** /**
* @dev transfers tokens in the event of a borrow being liquidated, in case the liquidators reclaims the aToken * @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 uint256 value
) external; ) 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); function isTransferAllowed(address user, uint256 amount) external view returns (bool);
/** /**
@ -104,6 +72,7 @@ interface IAToken is IERC20 {
* @param amount the amount to transfer * @param amount the amount to transfer
* @return the amount transferred * @return the amount transferred
**/ **/
function transferUnderlyingTo(address user, uint256 amount) external returns (uint256); function transferUnderlyingTo(address user, uint256 amount) external returns (uint256);
} }

View 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);
}

View File

@ -84,4 +84,26 @@ interface IStableDebtToken {
* @return the timestamp * @return the timestamp
**/ **/
function getUserLastUpdated(address user) external view returns (uint40); 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);
} }

View File

@ -1,66 +1,36 @@
// SPDX-License-Identifier: agpl-3.0 // SPDX-License-Identifier: agpl-3.0
pragma solidity ^0.6.8; pragma solidity ^0.6.8;
import {IScaledBalanceToken} from './IScaledBalanceToken.sol';
/** /**
* @title interface IVariableDebtToken * @title interface IVariableDebtToken
* @author Aave * @author Aave
* @notice defines the basic interface for a variable debt token. * @notice defines the basic interface for a variable debt token.
* @dev does not inherit from IERC20 to save in contract size
**/ **/
interface IVariableDebtToken { interface IVariableDebtToken is IScaledBalanceToken {
/**
* @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
);
/** /**
* @dev emitted when variable debt is burnt * @dev emitted when variable debt is burnt
* @param user the user which debt has been burned * @param user the user which debt has been burned
* @param amount the amount of debt being 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 * @param index the index of the user
**/ **/
event BurnDebt( event Burn(
address user, address indexed user,
uint256 amount, uint256 amount,
uint256 previousBalance,
uint256 currentBalance,
uint256 balanceIncrease,
uint256 index 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 * @dev burns user variable debt
* @param user the user which debt is burnt * @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; function burn(
address user,
uint256 amount,
uint256 index
) external;
/**
* @dev returns the last index of the user
* @return the index of the user
**/
function getUserIndex(address user) external view returns (uint256);
} }

View File

@ -5,7 +5,7 @@
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}, },
"localhost": { "localhost": {
"address": "0x9Dc554694756dC303a087e04bA6918C333Bc26a7", "address": "0x58F132FBB86E21545A4Bace3C19f1C05d86d7A22",
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}, },
"coverage": { "coverage": {
@ -19,7 +19,7 @@
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}, },
"localhost": { "localhost": {
"address": "0xAfC307938C1c0035942c141c31524504c89Aaa8B", "address": "0xa4bcDF64Cdd5451b6ac3743B414124A6299B65FF",
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}, },
"coverage": { "coverage": {
@ -33,7 +33,7 @@
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}, },
"localhost": { "localhost": {
"address": "0x73DE1e0ab6A5C221258703bc546E0CAAcCc6EC87", "address": "0x5A0773Ff307Bf7C71a832dBB5312237fD3437f9F",
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}, },
"coverage": { "coverage": {
@ -65,7 +65,7 @@
"address": "0x6642B57e4265BAD868C17Fc1d1F4F88DBBA04Aa8" "address": "0x6642B57e4265BAD868C17Fc1d1F4F88DBBA04Aa8"
}, },
"localhost": { "localhost": {
"address": "0x65e0Cd5B8904A02f2e00BC6f58bf881998D54BDe" "address": "0x6642B57e4265BAD868C17Fc1d1F4F88DBBA04Aa8"
}, },
"coverage": { "coverage": {
"address": "0x6642B57e4265BAD868C17Fc1d1F4F88DBBA04Aa8" "address": "0x6642B57e4265BAD868C17Fc1d1F4F88DBBA04Aa8"
@ -81,7 +81,7 @@
"address": "0xD9273d497eDBC967F39d419461CfcF382a0A822e" "address": "0xD9273d497eDBC967F39d419461CfcF382a0A822e"
}, },
"localhost": { "localhost": {
"address": "0x5d12dDe3286D94E0d85F9D3B01B7099cfA0aBCf1" "address": "0xD9273d497eDBC967F39d419461CfcF382a0A822e"
}, },
"coverage": { "coverage": {
"address": "0xD9273d497eDBC967F39d419461CfcF382a0A822e" "address": "0xD9273d497eDBC967F39d419461CfcF382a0A822e"
@ -93,7 +93,7 @@
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}, },
"localhost": { "localhost": {
"address": "0xbeA90474c2F3C7c43bC7c36CaAf5272c927Af5a1", "address": "0x1750499D05Ed1674d822430FB960d5F6731fDf64",
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}, },
"coverage": { "coverage": {
@ -107,7 +107,7 @@
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}, },
"localhost": { "localhost": {
"address": "0x19E42cA990cF697D3dda0e59131215C43bB6989F", "address": "0xEC1C93A9f6a9e18E97784c76aC52053587FcDB89",
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}, },
"coverage": { "coverage": {
@ -121,7 +121,7 @@
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}, },
"localhost": { "localhost": {
"address": "0xE30c3983E51bC9d6baE3E9437710a1459e21e81F", "address": "0x7B6C3e5486D9e6959441ab554A889099eed76290",
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}, },
"coverage": { "coverage": {
@ -135,7 +135,7 @@
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}, },
"localhost": { "localhost": {
"address": "0xDf69898e844197a24C658CcF9fD53dF15948dc8b", "address": "0xD83D2773a7873ae2b5f8Fb92097e20a8C64F691E",
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}, },
"coverage": { "coverage": {
@ -149,7 +149,7 @@
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}, },
"localhost": { "localhost": {
"address": "0xBe6d8642382C241c9B4B50c89574DbF3f4181E7D", "address": "0x626FdE749F9d499d3777320CAf29484B624ab84a",
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}, },
"coverage": { "coverage": {
@ -207,7 +207,7 @@
"address": "0x2B681757d757fbB80cc51c6094cEF5eE75bF55aA" "address": "0x2B681757d757fbB80cc51c6094cEF5eE75bF55aA"
}, },
"localhost": { "localhost": {
"address": "0xAd49512dFBaD6fc13D67d3935283c0606812E962" "address": "0x2B681757d757fbB80cc51c6094cEF5eE75bF55aA"
}, },
"coverage": { "coverage": {
"address": "0x2B681757d757fbB80cc51c6094cEF5eE75bF55aA" "address": "0x2B681757d757fbB80cc51c6094cEF5eE75bF55aA"
@ -219,7 +219,7 @@
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}, },
"localhost": { "localhost": {
"address": "0xA29C2A7e59aa49C71aF084695337E3AA5e820758", "address": "0xDf73fC454FA018051D4a1509e63D11530A59DE10",
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}, },
"coverage": { "coverage": {
@ -233,7 +233,7 @@
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}, },
"localhost": { "localhost": {
"address": "0xbe66dC9DFEe580ED968403e35dF7b5159f873df8", "address": "0x7c2C195CD6D34B8F845992d380aADB2730bB9C6F",
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}, },
"coverage": { "coverage": {
@ -247,7 +247,7 @@
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}, },
"localhost": { "localhost": {
"address": "0x93AfC6Df4bB8F62F2493B19e577f8382c0BA9EBC", "address": "0x8858eeB3DfffA017D4BCE9801D340D36Cf895CCf",
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}, },
"coverage": { "coverage": {
@ -261,7 +261,7 @@
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}, },
"localhost": { "localhost": {
"address": "0x75Ded61646B5945BdDd0CD9a9Db7c8288DA6F810", "address": "0x0078371BDeDE8aAc7DeBfFf451B74c5EDB385Af7",
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}, },
"coverage": { "coverage": {
@ -275,7 +275,7 @@
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}, },
"localhost": { "localhost": {
"address": "0xdE7c40e675bF1aA45c18cCbaEb9662B16b0Ddf7E", "address": "0xf4e77E5Da47AC3125140c470c71cBca77B5c638c",
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}, },
"coverage": { "coverage": {
@ -289,7 +289,7 @@
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}, },
"localhost": { "localhost": {
"address": "0xDFbeeed692AA81E7f86E72F7ACbEA2A1C4d63544", "address": "0x3619DbE27d7c1e7E91aA738697Ae7Bc5FC3eACA5",
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}, },
"coverage": { "coverage": {
@ -303,7 +303,7 @@
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}, },
"localhost": { "localhost": {
"address": "0x5191aA68c7dB195181Dd2441dBE23A48EA24b040", "address": "0x038B86d9d8FAFdd0a02ebd1A476432877b0107C8",
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}, },
"coverage": { "coverage": {
@ -317,7 +317,7 @@
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}, },
"localhost": { "localhost": {
"address": "0x8F9422aa37215c8b3D1Ea1674138107F84D68F26", "address": "0x1A1FEe7EeD918BD762173e4dc5EfDB8a78C924A8",
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}, },
"coverage": { "coverage": {
@ -331,7 +331,7 @@
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}, },
"localhost": { "localhost": {
"address": "0xa89E20284Bd638F31b0011D0fC754Fc9d2fa73e3", "address": "0x500D1d6A4c7D8Ae28240b47c8FCde034D827fD5e",
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}, },
"coverage": { "coverage": {
@ -345,7 +345,7 @@
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}, },
"localhost": { "localhost": {
"address": "0xaA935993065F2dDB1d13623B1941C7AEE3A60F23", "address": "0xc4905364b78a742ccce7B890A89514061E47068D",
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}, },
"coverage": { "coverage": {
@ -359,7 +359,7 @@
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}, },
"localhost": { "localhost": {
"address": "0x35A2624888e207e4B3434E9a9E250bF6Ee68FeA3", "address": "0xD6C850aeBFDC46D7F4c207e445cC0d6B0919BDBe",
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}, },
"coverage": { "coverage": {
@ -373,7 +373,7 @@
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}, },
"localhost": { "localhost": {
"address": "0x1f569c307949a908A4b8Ff7453a88Ca0b8D8df13", "address": "0x8B5B7a6055E54a36fF574bbE40cf2eA68d5554b3",
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}, },
"coverage": { "coverage": {
@ -387,7 +387,7 @@
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}, },
"localhost": { "localhost": {
"address": "0x4301cb254CCc126B9eb9cbBE030C6FDA2FA16D4a", "address": "0xEcc0a6dbC0bb4D51E4F84A315a9e5B0438cAD4f0",
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}, },
"coverage": { "coverage": {
@ -401,7 +401,7 @@
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}, },
"localhost": { "localhost": {
"address": "0x0766c9592a8686CAB0081b4f35449462c6e82F11", "address": "0x20Ce94F404343aD2752A2D01b43fa407db9E0D00",
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}, },
"coverage": { "coverage": {
@ -415,7 +415,7 @@
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}, },
"localhost": { "localhost": {
"address": "0xaF6D34adD35E1A565be4539E4d1069c48A49C953", "address": "0x1d80315fac6aBd3EfeEbE97dEc44461ba7556160",
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}, },
"coverage": { "coverage": {
@ -429,7 +429,7 @@
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}, },
"localhost": { "localhost": {
"address": "0x48bb3E35D2D6994374db457a6Bf61de2d9cC8E49", "address": "0x2D8553F9ddA85A9B3259F6Bf26911364B85556F5",
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}, },
"coverage": { "coverage": {
@ -443,7 +443,7 @@
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}, },
"localhost": { "localhost": {
"address": "0x1E59BA56B1F61c3Ee946D8c7e2994B4A9b0cA45C", "address": "0x52d3b94181f8654db2530b0fEe1B19173f519C52",
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}, },
"coverage": { "coverage": {
@ -457,7 +457,7 @@
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}, },
"localhost": { "localhost": {
"address": "0x53813198c75959DDB604462831d8989C29152164", "address": "0xd15468525c35BDBC1eD8F2e09A00F8a173437f2f",
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}, },
"coverage": { "coverage": {
@ -471,7 +471,7 @@
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}, },
"localhost": { "localhost": {
"address": "0x0eD6115873ce6B807a03FE0df1f940387779b729", "address": "0x7e35Eaf7e8FBd7887ad538D4A38Df5BbD073814a",
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}, },
"coverage": { "coverage": {
@ -485,7 +485,7 @@
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}, },
"localhost": { "localhost": {
"address": "0xFFfDa24e7E3d5F89a24278f53d6f0F81B3bE0d6B", "address": "0x5bcb88A0d20426e451332eE6C4324b0e663c50E0",
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}, },
"coverage": { "coverage": {
@ -499,7 +499,7 @@
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}, },
"localhost": { "localhost": {
"address": "0x5889354f21A1C8D8D2f82669d778f6Dab778B519", "address": "0x3521eF8AaB0323004A6dD8b03CE890F4Ea3A13f5",
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}, },
"coverage": { "coverage": {
@ -513,7 +513,7 @@
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}, },
"localhost": { "localhost": {
"address": "0x09F7bF33B3F8922268B34103af3a8AF83148C9B1", "address": "0x53369fd4680FfE3DfF39Fc6DDa9CfbfD43daeA2E",
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}, },
"coverage": { "coverage": {
@ -527,7 +527,7 @@
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}, },
"localhost": { "localhost": {
"address": "0x8f3966F7d53Fd5f12b701C8835e1e32541613869", "address": "0xB00cC45B4a7d3e1FEE684cFc4417998A1c183e6d",
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}, },
"coverage": { "coverage": {
@ -541,7 +541,7 @@
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}, },
"localhost": { "localhost": {
"address": "0x9Dc554694756dC303a087e04bA6918C333Bc26a7", "address": "0x58F132FBB86E21545A4Bace3C19f1C05d86d7A22",
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}, },
"coverage": { "coverage": {
@ -554,7 +554,7 @@
"address": "0x2cfcA5785261fbC88EFFDd46fCFc04c22525F9e4" "address": "0x2cfcA5785261fbC88EFFDd46fCFc04c22525F9e4"
}, },
"localhost": { "localhost": {
"address": "0x9305d862ee95a899b83906Cd9CB666aC269E5f66" "address": "0x2cfcA5785261fbC88EFFDd46fCFc04c22525F9e4"
}, },
"coverage": { "coverage": {
"address": "0x2cfcA5785261fbC88EFFDd46fCFc04c22525F9e4" "address": "0x2cfcA5785261fbC88EFFDd46fCFc04c22525F9e4"
@ -566,7 +566,7 @@
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}, },
"localhost": { "localhost": {
"address": "0x02BB514187B830d6A2111197cd7D8cb60650B970", "address": "0xB660Fdd109a95718cB9d20E3A89EE6cE342aDcB6",
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}, },
"coverage": { "coverage": {
@ -580,7 +580,7 @@
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}, },
"localhost": { "localhost": {
"address": "0x6774Ce86Abf5EBB22E9F45b5f55daCbB4170aD7f", "address": "0x830bceA96E56DBC1F8578f75fBaC0AF16B32A07d",
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}, },
"coverage": { "coverage": {
@ -590,7 +590,7 @@
}, },
"AToken": { "AToken": {
"localhost": { "localhost": {
"address": "0x007C1a44e85bDa8F562F916685A9DC8BdC6542bF", "address": "0xA0AB1cB92A4AF81f84dCd258155B5c25D247b54E",
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}, },
"buidlerevm": { "buidlerevm": {
@ -608,7 +608,7 @@
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}, },
"localhost": { "localhost": {
"address": "0xFBdF1E93D0D88145e3CcA63bf8d513F83FB0903b", "address": "0xEcb928A3c079a1696Aa5244779eEc3dE1717fACd",
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}, },
"coverage": { "coverage": {
@ -622,7 +622,7 @@
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}, },
"localhost": { "localhost": {
"address": "0xEcb928A3c079a1696Aa5244779eEc3dE1717fACd", "address": "0xf784709d2317D872237C4bC22f867d1BAe2913AB",
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}, },
"coverage": { "coverage": {
@ -636,7 +636,7 @@
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}, },
"localhost": { "localhost": {
"address": "0xE45fF4A0A8D0E9734C73874c034E03594E15ba28", "address": "0xDFbeeed692AA81E7f86E72F7ACbEA2A1C4d63544",
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}, },
"coverage": { "coverage": {
@ -650,7 +650,7 @@
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}, },
"localhost": { "localhost": {
"address": "0x5cCC6Abc4c9F7262B9485797a848Ec6CC28A11dF", "address": "0x5191aA68c7dB195181Dd2441dBE23A48EA24b040",
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
}, },
"coverage": { "coverage": {
@ -664,6 +664,9 @@
}, },
"coverage": { "coverage": {
"address": "0xBEF0d4b9c089a5883741fC14cbA352055f35DDA2" "address": "0xBEF0d4b9c089a5883741fC14cbA352055f35DDA2"
},
"localhost": {
"address": "0xBEF0d4b9c089a5883741fC14cbA352055f35DDA2"
} }
} }
} }

View File

@ -31,6 +31,7 @@ import BigNumber from 'bignumber.js';
import {Ierc20Detailed} from '../types/Ierc20Detailed'; import {Ierc20Detailed} from '../types/Ierc20Detailed';
import {StableDebtToken} from '../types/StableDebtToken'; import {StableDebtToken} from '../types/StableDebtToken';
import {VariableDebtToken} from '../types/VariableDebtToken'; import {VariableDebtToken} from '../types/VariableDebtToken';
import { ZERO_ADDRESS } from './constants';
import {MockSwapAdapter} from '../types/MockSwapAdapter'; import {MockSwapAdapter} from '../types/MockSwapAdapter';
import {signTypedData_v4, TypedData} from 'eth-sig-util'; import {signTypedData_v4, TypedData} from 'eth-sig-util';
import {fromRpcSig, ECDSASignature} from 'ethereumjs-util'; import {fromRpcSig, ECDSASignature} from 'ethereumjs-util';
@ -290,13 +291,15 @@ export const deployVariableDebtToken = async ([
export const deployGenericAToken = async ([ export const deployGenericAToken = async ([
poolAddress, poolAddress,
underlyingAssetAddress, underlyingAssetAddress,
reserveTreasuryAddress,
name, name,
symbol, symbol,
incentivesController, incentivesController,
]: [tEthereumAddress, tEthereumAddress, string, string, tEthereumAddress]) => { ]: [tEthereumAddress, tEthereumAddress, tEthereumAddress, string, string, tEthereumAddress]) => {
const token = await deployContract<AToken>(eContractid.AToken, [ const token = await deployContract<AToken>(eContractid.AToken, [
poolAddress, poolAddress,
underlyingAssetAddress, underlyingAssetAddress,
reserveTreasuryAddress,
name, name,
symbol, symbol,
incentivesController, 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) => { export const getMintableErc20 = async (address: tEthereumAddress) => {
return await getContract<MintableErc20>( return await getContract<MintableErc20>(
eContractid.MintableERC20, eContractid.MintableERC20,

View File

@ -245,6 +245,7 @@ const initReserves = async (
const aToken = await deployGenericAToken([ const aToken = await deployGenericAToken([
lendingPool.address, lendingPool.address,
tokenAddress, tokenAddress,
ZERO_ADDRESS,
`Aave interest bearing ${assetSymbol === 'WETH' ? 'ETH' : assetSymbol}`, `Aave interest bearing ${assetSymbol === 'WETH' ? 'ETH' : assetSymbol}`,
`a${assetSymbol === 'WETH' ? 'ETH' : assetSymbol}`, `a${assetSymbol === 'WETH' ? 'ETH' : assetSymbol}`,
incentivesController, incentivesController,

View File

@ -180,6 +180,23 @@ makeSuite('LendingPoolConfigurator', (testEnv: TestEnv) => {
).to.be.revertedWith(CALLER_NOT_AAVE_ADMIN); ).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 () => { it('Changes liquidation threshold of the reserve', async () => {
const {configurator, pool, weth} = testEnv; const {configurator, pool, weth} = testEnv;
await configurator.setLiquidationThreshold(weth.address, '75'); await configurator.setLiquidationThreshold(weth.address, '75');

View File

@ -125,7 +125,9 @@ makeSuite('LendingPool. repayWithCollateral() with liquidator', (testEnv: TestEn
).minus(usdcUserDataBefore.currentVariableDebt); ).minus(usdcUserDataBefore.currentVariableDebt);
const expectedStableDebtIncrease = calcExpectedStableDebtTokenBalance( const expectedStableDebtIncrease = calcExpectedStableDebtTokenBalance(
usdcUserDataBefore, usdcUserDataBefore.principalStableDebt,
usdcUserDataBefore.stableBorrowRate,
usdcUserDataBefore.stableRateLastUpdated,
new BigNumber(repayWithCollateralTimestamp) new BigNumber(repayWithCollateralTimestamp)
).minus(usdcUserDataBefore.currentStableDebt); ).minus(usdcUserDataBefore.currentStableDebt);
@ -233,7 +235,7 @@ makeSuite('LendingPool. repayWithCollateral() with liquidator', (testEnv: TestEn
userData: usdcUserDataBefore, userData: usdcUserDataBefore,
} = await getContractsData(usdc.address, user.address, testEnv); } = 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 mockSwapAdapter.setAmountToReturn(amountToRepay);
await waitForTx( await waitForTx(
@ -295,7 +297,7 @@ makeSuite('LendingPool. repayWithCollateral() with liquidator', (testEnv: TestEn
'INVALID_DEBT_POSITION' 'INVALID_DEBT_POSITION'
); );
expect(wethUserDataAfter.currentATokenBalance).to.be.bignumber.equal( expect(wethUserDataAfter.currentATokenBalance).to.be.bignumber.almostEqual(
new BigNumber(wethUserDataBefore.currentATokenBalance).minus( new BigNumber(wethUserDataBefore.currentATokenBalance).minus(
expectedCollateralLiquidated.toString() expectedCollateralLiquidated.toString()
), ),
@ -368,7 +370,7 @@ makeSuite('LendingPool. repayWithCollateral() with liquidator', (testEnv: TestEn
userData: usdcUserDataBefore, userData: usdcUserDataBefore,
} = await getContractsData(usdc.address, user.address, testEnv); } = await getContractsData(usdc.address, user.address, testEnv);
const amountToRepay = usdcReserveDataBefore.totalBorrowsVariable.toFixed(0); const amountToRepay = usdcReserveDataBefore.totalVariableDebt.toFixed(0);
await mockSwapAdapter.setAmountToReturn(amountToRepay); await mockSwapAdapter.setAmountToReturn(amountToRepay);
await waitForTx( await waitForTx(
@ -486,7 +488,7 @@ makeSuite('LendingPool. repayWithCollateral() with liquidator', (testEnv: TestEn
testEnv testEnv
); );
const amountToRepay = daiReserveDataBefore.totalBorrowsVariable.toString(); const amountToRepay = daiReserveDataBefore.totalVariableDebt.toString();
await waitForTx(await mockSwapAdapter.setTryReentrancy(true)); await waitForTx(await mockSwapAdapter.setTryReentrancy(true));
@ -522,7 +524,7 @@ makeSuite('LendingPool. repayWithCollateral() with liquidator', (testEnv: TestEn
); );
// First half // First half
const amountToRepay = daiReserveDataBefore.totalBorrowsVariable.dividedBy(2).toString(); const amountToRepay = daiReserveDataBefore.totalVariableDebt.dividedBy(2).toString();
await mockSwapAdapter.setAmountToReturn(amountToRepay); await mockSwapAdapter.setAmountToReturn(amountToRepay);
await expect( await expect(
@ -568,7 +570,7 @@ makeSuite('LendingPool. repayWithCollateral() with liquidator', (testEnv: TestEn
); );
// First half // 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 mockSwapAdapter.setAmountToReturn(amountToRepay);
await waitForTx( await waitForTx(
@ -654,7 +656,7 @@ makeSuite('LendingPool. repayWithCollateral() with liquidator', (testEnv: TestEn
await increaseTime(1000); await increaseTime(1000);
// Repay the remaining DAI // Repay the remaining DAI
const amountToRepay = daiReserveDataBefore.totalBorrowsVariable.toString(); const amountToRepay = daiReserveDataBefore.totalVariableDebt.toString();
await mockSwapAdapter.setAmountToReturn(amountToRepay); await mockSwapAdapter.setAmountToReturn(amountToRepay);
const receipt = await waitForTx( const receipt = await waitForTx(
@ -816,7 +818,7 @@ makeSuite('LendingPool. repayWithCollateral() with liquidator', (testEnv: TestEn
new BigNumber(repayWithCollateralTimestamp) new BigNumber(repayWithCollateralTimestamp)
).minus(usdcUserDataBefore.currentVariableDebt); ).minus(usdcUserDataBefore.currentVariableDebt);
expect(usdcUserDataAfter.currentVariableDebt).to.be.bignumber.equal( expect(usdcUserDataAfter.currentVariableDebt).to.be.bignumber.almostEqual(
new BigNumber(usdcUserDataBefore.currentVariableDebt) new BigNumber(usdcUserDataBefore.currentVariableDebt)
.minus(expectedDebtCovered.toString()) .minus(expectedDebtCovered.toString())
.plus(expectedVariableDebtIncrease), .plus(expectedVariableDebtIncrease),

View File

@ -62,8 +62,8 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => {
const currentLiquidityIndex = reserveData.liquidityIndex; const currentLiquidityIndex = reserveData.liquidityIndex;
const totalLiquidity = new BigNumber(reserveData.availableLiquidity.toString()) const totalLiquidity = new BigNumber(reserveData.availableLiquidity.toString())
.plus(reserveData.totalBorrowsStable.toString()) .plus(reserveData.totalStableDebt.toString())
.plus(reserveData.totalBorrowsVariable.toString()); .plus(reserveData.totalVariableDebt.toString());
expect(totalLiquidity.toString()).to.be.equal('1000720000000000000'); expect(totalLiquidity.toString()).to.be.equal('1000720000000000000');
expect(currentLiquidityRate.toString()).to.be.equal('0'); expect(currentLiquidityRate.toString()).to.be.equal('0');
@ -89,8 +89,8 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => {
const currentLiquidityIndex = reserveData.liquidityIndex; const currentLiquidityIndex = reserveData.liquidityIndex;
const totalLiquidity = new BigNumber(reserveData.availableLiquidity.toString()) const totalLiquidity = new BigNumber(reserveData.availableLiquidity.toString())
.plus(reserveData.totalBorrowsStable.toString()) .plus(reserveData.totalStableDebt.toString())
.plus(reserveData.totalBorrowsVariable.toString()); .plus(reserveData.totalVariableDebt.toString());
expect(totalLiquidity.toString()).to.be.equal('1001620648000000000'); expect(totalLiquidity.toString()).to.be.equal('1001620648000000000');
expect(currentLiqudityRate.toString()).to.be.equal('0'); 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 userData = await pool.getUserReserveData(usdc.address, depositor.address);
const totalLiquidity = reserveData.availableLiquidity const totalLiquidity = reserveData.availableLiquidity
.add(reserveData.totalBorrowsStable) .add(reserveData.totalStableDebt)
.add(reserveData.totalBorrowsVariable) .add(reserveData.totalVariableDebt)
.toString(); .toString();
const currentLiqudityRate = reserveData.liquidityRate.toString(); const currentLiqudityRate = reserveData.liquidityRate.toString();
const currentLiquidityIndex = reserveData.liquidityIndex.toString(); const currentLiquidityIndex = reserveData.liquidityIndex.toString();

View File

@ -32,6 +32,7 @@ import {waitForTx} from '../__setup.spec';
import {ContractReceipt} from 'ethers'; import {ContractReceipt} from 'ethers';
import {AToken} from '../../types/AToken'; import {AToken} from '../../types/AToken';
import {RateMode, tEthereumAddress} from '../../helpers/types'; import {RateMode, tEthereumAddress} from '../../helpers/types';
import { time } from 'console';
const {expect} = chai; const {expect} = chai;
@ -48,7 +49,8 @@ const almostEqualOrEqual = function (
key === 'marketStableRate' || key === 'marketStableRate' ||
key === 'symbol' || key === 'symbol' ||
key === 'aTokenAddress' || key === 'aTokenAddress' ||
key === 'decimals' key === 'decimals' ||
key === 'totalStableDebtLastUpdated'
) { ) {
// skipping consistency check on accessory data // skipping consistency check on accessory data
return; return;
@ -262,10 +264,6 @@ export const withdraw = async (
txCost txCost
); );
const actualAmountWithdrawn = userDataBefore.currentATokenBalance.minus(
expectedUserData.currentATokenBalance
);
expectEqual(reserveDataAfter, expectedReserveData); expectEqual(reserveDataAfter, expectedReserveData);
expectEqual(userDataAfter, expectedUserData); expectEqual(userDataAfter, expectedUserData);
@ -371,8 +369,7 @@ export const borrow = async (
expectedReserveData, expectedReserveData,
userDataBefore, userDataBefore,
txTimestamp, txTimestamp,
timestamp, timestamp
txCost
); );
expectEqual(reserveDataAfter, expectedReserveData); expectEqual(reserveDataAfter, expectedReserveData);
@ -475,8 +472,7 @@ export const repay = async (
user.address, user.address,
onBehalfOf.address, onBehalfOf.address,
txTimestamp, txTimestamp,
timestamp, timestamp
txCost
); );
expectEqual(reserveDataAfter, expectedReserveData); expectEqual(reserveDataAfter, expectedReserveData);
@ -741,9 +737,12 @@ export const getContractsData = async (
sender?: string sender?: string
) => { ) => {
const {pool} = testEnv; const {pool} = testEnv;
const reserveData = await getReserveData(pool, reserve);
const userData = await getUserData(pool, reserve, user, sender || user); const [userData, reserveData, timestamp] = await Promise.all([
const timestamp = await timeLatest(); getUserData(pool, reserve, user, sender || user),
getReserveData(pool, reserve),
timeLatest(),
]);
return { return {
reserveData, reserveData,

View File

@ -626,6 +626,17 @@
}, },
"expected": "success" "expected": "success"
}, },
{
"name": "repay",
"args": {
"reserve": "DAI",
"amount": "-1",
"user": "1",
"onBehalfOf": "1",
"borrowRateMode": "variable"
},
"expected": "success"
},
{ {
"name": "withdraw", "name": "withdraw",
"args": { "args": {

File diff suppressed because it is too large Load Diff

View File

@ -4,9 +4,8 @@ import {
getLendingRateOracle, getLendingRateOracle,
getIErc20Detailed, getIErc20Detailed,
getMintableErc20, getMintableErc20,
getAToken, getAToken, getStableDebtToken, getVariableDebtToken
} from '../../../helpers/contracts-helpers'; } from '../../../helpers/contracts-helpers';
import {ZERO_ADDRESS} from '../../../helpers/constants';
import {tEthereumAddress} from '../../../helpers/types'; import {tEthereumAddress} from '../../../helpers/types';
import BigNumber from 'bignumber.js'; import BigNumber from 'bignumber.js';
import {getDb, BRE} from '../../../helpers/misc-utils'; import {getDb, BRE} from '../../../helpers/misc-utils';
@ -15,41 +14,54 @@ export const getReserveData = async (
pool: LendingPool, pool: LendingPool,
reserve: tEthereumAddress reserve: tEthereumAddress
): Promise<ReserveData> => { ): Promise<ReserveData> => {
const data = await pool.getReserveData(reserve); const [reserveData, tokenAddresses, rateOracle, token] = await Promise.all([
const tokenAddresses = await pool.getReserveTokensAddresses(reserve); pool.getReserveData(reserve),
const rateOracle = await getLendingRateOracle(); 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 rate = (await rateOracle.getMarketBorrowRate(reserve)).toString();
const token = await getIErc20Detailed(reserve);
const symbol = await token.symbol(); const symbol = await token.symbol();
const decimals = new BigNumber(await token.decimals()); const decimals = new BigNumber(await token.decimals());
const totalLiquidity = new BigNumber(data.availableLiquidity.toString()) const totalLiquidity = new BigNumber(reserveData.availableLiquidity.toString())
.plus(data.totalBorrowsStable.toString()) .plus(reserveData.totalStableDebt.toString())
.plus(data.totalBorrowsVariable.toString()); .plus(reserveData.totalVariableDebt.toString());
const utilizationRate = new BigNumber( const utilizationRate = new BigNumber(
totalLiquidity.eq(0) totalLiquidity.eq(0)
? 0 ? 0
: new BigNumber(data.totalBorrowsStable.toString()) : new BigNumber(reserveData.totalStableDebt.toString())
.plus(data.totalBorrowsVariable.toString()) .plus(reserveData.totalVariableDebt.toString())
.rayDiv(totalLiquidity) .rayDiv(totalLiquidity)
); );
return { return {
totalLiquidity, totalLiquidity,
utilizationRate, utilizationRate,
availableLiquidity: new BigNumber(data.availableLiquidity.toString()), availableLiquidity: new BigNumber(reserveData.availableLiquidity.toString()),
totalBorrowsStable: new BigNumber(data.totalBorrowsStable.toString()), totalStableDebt: new BigNumber(reserveData.totalStableDebt.toString()),
totalBorrowsVariable: new BigNumber(data.totalBorrowsVariable.toString()), totalVariableDebt: new BigNumber(reserveData.totalVariableDebt.toString()),
liquidityRate: new BigNumber(data.liquidityRate.toString()), liquidityRate: new BigNumber(reserveData.liquidityRate.toString()),
variableBorrowRate: new BigNumber(data.variableBorrowRate.toString()), variableBorrowRate: new BigNumber(reserveData.variableBorrowRate.toString()),
stableBorrowRate: new BigNumber(data.stableBorrowRate.toString()), stableBorrowRate: new BigNumber(reserveData.stableBorrowRate.toString()),
averageStableBorrowRate: new BigNumber(data.averageStableBorrowRate.toString()), averageStableBorrowRate: new BigNumber(reserveData.averageStableBorrowRate.toString()),
liquidityIndex: new BigNumber(data.liquidityIndex.toString()), liquidityIndex: new BigNumber(reserveData.liquidityIndex.toString()),
variableBorrowIndex: new BigNumber(data.variableBorrowIndex.toString()), variableBorrowIndex: new BigNumber(reserveData.variableBorrowIndex.toString()),
lastUpdateTimestamp: new BigNumber(data.lastUpdateTimestamp), lastUpdateTimestamp: new BigNumber(reserveData.lastUpdateTimestamp),
totalStableDebtLastUpdated: new BigNumber(totalStableDebtLastUpdated),
principalStableDebt: new BigNumber(principalStableDebt.toString()),
scaledVariableDebt: new BigNumber(scaledVariableDebt.toString()),
address: reserve, address: reserve,
aTokenAddress: tokenAddresses.aTokenAddress, aTokenAddress: tokenAddresses.aTokenAddress,
symbol, symbol,
@ -69,7 +81,6 @@ export const getUserData = async (
getATokenUserData(reserve, user, pool), getATokenUserData(reserve, user, pool),
]); ]);
const token = await getMintableErc20(reserve); const token = await getMintableErc20(reserve);
const walletBalance = new BigNumber((await token.balanceOf(sender || user)).toString()); const walletBalance = new BigNumber((await token.balanceOf(sender || user)).toString());
@ -79,8 +90,7 @@ export const getUserData = async (
currentStableDebt: new BigNumber(userData.currentStableDebt.toString()), currentStableDebt: new BigNumber(userData.currentStableDebt.toString()),
currentVariableDebt: new BigNumber(userData.currentVariableDebt.toString()), currentVariableDebt: new BigNumber(userData.currentVariableDebt.toString()),
principalStableDebt: new BigNumber(userData.principalStableDebt.toString()), principalStableDebt: new BigNumber(userData.principalStableDebt.toString()),
principalVariableDebt: new BigNumber(userData.principalVariableDebt.toString()), scaledVariableDebt: new BigNumber(userData.scaledVariableDebt.toString()),
variableBorrowIndex: new BigNumber(userData.variableBorrowIndex.toString()),
stableBorrowRate: new BigNumber(userData.stableBorrowRate.toString()), stableBorrowRate: new BigNumber(userData.stableBorrowRate.toString()),
liquidityRate: new BigNumber(userData.liquidityRate.toString()), liquidityRate: new BigNumber(userData.liquidityRate.toString()),
usageAsCollateralEnabled: userData.usageAsCollateralEnabled, usageAsCollateralEnabled: userData.usageAsCollateralEnabled,
@ -107,5 +117,4 @@ const getATokenUserData = async (reserve: string, user: string, pool: LendingPoo
const scaledBalance = await aToken.scaledBalanceOf(user); const scaledBalance = await aToken.scaledBalanceOf(user);
return scaledBalance.toString(); return scaledBalance.toString();
}; };

View File

@ -6,8 +6,7 @@ export interface UserReserveData {
currentStableDebt: BigNumber; currentStableDebt: BigNumber;
currentVariableDebt: BigNumber; currentVariableDebt: BigNumber;
principalStableDebt: BigNumber; principalStableDebt: BigNumber;
principalVariableDebt: BigNumber; scaledVariableDebt: BigNumber;
variableBorrowIndex: BigNumber;
liquidityRate: BigNumber; liquidityRate: BigNumber;
stableBorrowRate: BigNumber; stableBorrowRate: BigNumber;
stableRateLastUpdated: BigNumber; stableRateLastUpdated: BigNumber;
@ -22,8 +21,10 @@ export interface ReserveData {
decimals: BigNumber; decimals: BigNumber;
totalLiquidity: BigNumber; totalLiquidity: BigNumber;
availableLiquidity: BigNumber; availableLiquidity: BigNumber;
totalBorrowsStable: BigNumber; totalStableDebt: BigNumber;
totalBorrowsVariable: BigNumber; totalVariableDebt: BigNumber;
principalStableDebt: BigNumber,
scaledVariableDebt: BigNumber,
averageStableBorrowRate: BigNumber; averageStableBorrowRate: BigNumber;
variableBorrowRate: BigNumber; variableBorrowRate: BigNumber;
stableBorrowRate: BigNumber; stableBorrowRate: BigNumber;
@ -33,6 +34,7 @@ export interface ReserveData {
aTokenAddress: string; aTokenAddress: string;
marketStableRate: BigNumber; marketStableRate: BigNumber;
lastUpdateTimestamp: BigNumber; lastUpdateTimestamp: BigNumber;
totalStableDebtLastUpdated: BigNumber;
liquidityRate: BigNumber; liquidityRate: BigNumber;
[key: string]: BigNumber | string; [key: string]: BigNumber | string;
} }

View File

@ -175,7 +175,9 @@ makeSuite('LendingPool liquidation - liquidator receiving the underlying asset',
); );
const stableDebtBeforeTx = calcExpectedStableDebtTokenBalance( const stableDebtBeforeTx = calcExpectedStableDebtTokenBalance(
userReserveDataBefore, userReserveDataBefore.principalStableDebt,
userReserveDataBefore.stableBorrowRate,
userReserveDataBefore.stableRateLastUpdated,
txTimestamp txTimestamp
); );

View File

@ -420,7 +420,9 @@ makeSuite('LendingPool. repayWithCollateral()', (testEnv: TestEnv) => {
).minus(usdcUserDataBefore.currentVariableDebt); ).minus(usdcUserDataBefore.currentVariableDebt);
const expectedStableDebtIncrease = calcExpectedStableDebtTokenBalance( const expectedStableDebtIncrease = calcExpectedStableDebtTokenBalance(
usdcUserDataBefore, usdcUserDataBefore.principalStableDebt,
usdcUserDataBefore.stableBorrowRate,
usdcUserDataBefore.stableRateLastUpdated,
new BigNumber(repayWithCollateralTimestamp) new BigNumber(repayWithCollateralTimestamp)
).minus(usdcUserDataBefore.currentStableDebt); ).minus(usdcUserDataBefore.currentStableDebt);
@ -556,14 +558,14 @@ makeSuite('LendingPool. repayWithCollateral()', (testEnv: TestEnv) => {
new BigNumber(repayWithCollateralTimestamp) new BigNumber(repayWithCollateralTimestamp)
).minus(daiUserDataBefore.currentVariableDebt); ).minus(daiUserDataBefore.currentVariableDebt);
expect(daiUserDataAfter.currentVariableDebt).to.be.bignumber.equal( expect(daiUserDataAfter.currentVariableDebt).to.be.bignumber.almostEqual(
new BigNumber(daiUserDataBefore.currentVariableDebt) new BigNumber(daiUserDataBefore.currentVariableDebt)
.minus(expectedDebtCovered.toString()) .minus(expectedDebtCovered.toString())
.plus(expectedVariableDebtIncrease), .plus(expectedVariableDebtIncrease),
'INVALID_VARIABLE_DEBT_POSITION' '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; expect(wethUserDataAfter.usageAsCollateralEnabled).to.be.false;
}); });

View File

@ -23,9 +23,10 @@ makeSuite('Upgradeability', (testEnv: TestEnv) => {
const aTokenInstance = await deployContract<MockAToken>(eContractid.MockAToken, [ const aTokenInstance = await deployContract<MockAToken>(eContractid.MockAToken, [
pool.address, pool.address,
dai.address, dai.address,
ZERO_ADDRESS,
'Aave Interest bearing DAI updated', 'Aave Interest bearing DAI updated',
'aDAI', 'aDAI',
ZERO_ADDRESS, ZERO_ADDRESS
]); ]);
const stableDebtTokenInstance = await deployContract<MockStableDebtToken>( const stableDebtTokenInstance = await deployContract<MockStableDebtToken>(

View File

@ -18,7 +18,7 @@ makeSuite('Variable debt token tests', (testEnv: TestEnv) => {
daiVariableDebtTokenAddress 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 CALLER_MUST_BE_LENDING_POOL
); );
}); });
@ -34,7 +34,7 @@ makeSuite('Variable debt token tests', (testEnv: TestEnv) => {
daiVariableDebtTokenAddress 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 CALLER_MUST_BE_LENDING_POOL
); );
}); });